10#include <QtGui/qguiapplication.h>
11#include <QtGui/qwindow.h>
12#include <qpa/qwindowsysteminterface.h>
13#include <private/qguiapplication_p.h>
14#include <private/qhighdpiscaling_p.h>
15#include <QtGui/qevent.h>
16#include <QtGui/private/qwindowsguieventdispatcher_p.h>
17#include <QtCore/private/qdebug_p.h>
18#include <QtCore/private/qtools_p.h>
20#if defined(WM_APPCOMMAND)
21# ifndef FAPPCOMMAND_MOUSE
22# define FAPPCOMMAND_MOUSE 0x8000
24# ifndef FAPPCOMMAND_KEY
25# define FAPPCOMMAND_KEY 0
27# ifndef FAPPCOMMAND_OEM
28# define FAPPCOMMAND_OEM 0x1000
30# ifndef FAPPCOMMAND_MASK
31# define FAPPCOMMAND_MASK 0xF000
33# ifndef GET_APPCOMMAND_LPARAM
34# define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
36# ifndef GET_DEVICE_LPARAM
37# define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
39# ifndef GET_MOUSEORKEY_LPARAM
40# define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
42# ifndef GET_FLAGS_LPARAM
43# define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
45# ifndef GET_KEYSTATE_LPARAM
46# define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
66 memset(keyLayout, 0,
sizeof(keyLayout));
76#define LANG_PASHTO 0x63
79#define LANG_SYRIAC 0x5a
82#define LANG_DIVEHI 0x65
85#define VK_OEM_PLUS 0xBB
153 "Internal KeyRecorder",
154 "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
157 qWarning(
"Qt: Internal keyboard buffer overflow");
497static const Qt::KeyboardModifiers
ModsTbl[] = {
511#ifndef QT_NO_DEBUG_STREAM
516 d <<
"KeyboardLayoutItem(";
520 d <<
'[' <<
i <<
' ';
525 d <<
" '" << char(
qtKey) <<
'\'';
577 QChar unicodeBuffer[5];
578 int res = ToUnicode(vk, scancode, kbdBuffer,
reinterpret_cast<LPWSTR
>(unicodeBuffer), 5, 0);
581 if (
res == 0 && kbdBuffer[VK_CONTROL]) {
582 const unsigned char controlState = kbdBuffer[VK_CONTROL];
583 kbdBuffer[VK_CONTROL] = 0;
584 res = ToUnicode(vk, scancode, kbdBuffer,
reinterpret_cast<LPWSTR
>(unicodeBuffer), 5, 0);
585 kbdBuffer[VK_CONTROL] = controlState;
592 if (code < 0x20 || code == 0x7f)
596 *isDeadkey = (
res == -1);
605 if (
a >= 0 &&
a <= 31)
616void QWindowsKeyMapper::deleteLayouts()
629 LCID newLCID = MAKELCID(
quintptr(GetKeyboardLayout(0)), SORT_DEFAULT);
633 wchar_t LCIDFontSig[16];
634 if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig,
sizeof(LCIDFontSig) /
sizeof(
wchar_t))
635 && (LCIDFontSig[7] &
wchar_t(0x0800)))
646 kbd[VK_LSHIFT ] = (
shift ? 0x80 : 0);
647 kbd[VK_SHIFT ] = (
shift ? 0x80 : 0);
648 kbd[VK_LCONTROL] = (ctrl ? 0x80 : 0);
649 kbd[VK_CONTROL ] = (ctrl ? 0x80 : 0);
650 kbd[VK_RMENU ] = (alt ? 0x80 : 0);
651 kbd[VK_MENU ] = (alt ? 0x80 : 0);
655void QWindowsKeyMapper::updateKeyMap(
const MSG &msg)
657 unsigned char kbdBuffer[256];
658 GetKeyboardState(kbdBuffer);
660 updatePossibleKeyCodes(kbdBuffer, scancode,
quint32(msg.wParam));
666void QWindowsKeyMapper::updatePossibleKeyCodes(
unsigned char *kbdBuffer,
quint32 scancode,
669 if (!vk_key || (keyLayout[vk_key].exists && !keyLayout[vk_key].dirty))
673 unsigned char buffer[256];
690 bool isDeadKey =
false;
692 keyLayout[vk_key].
dirty =
false;
693 keyLayout[vk_key].
exists =
true;
696 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x01 : 0;
699 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x02 : 0;
702 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x04 : 0;
705 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x08 : 0;
708 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x10 : 0;
711 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x20 : 0;
714 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x40 : 0;
717 keyLayout[vk_key].
deadkeys |= isDeadKey ? 0x80 : 0;
722 if (vk_key != keyLayout[vk_key].
qtKey[0] && vk_key != keyLayout[vk_key].
qtKey[1]
723 && vk_key < 0x5B && vk_key > 0x2F)
724 fallbackKey = vk_key;
726 keyLayout[vk_key].
qtKey[8] = fallbackKey;
730 if (keyLayout[vk_key].deadkeys) {
737 unsigned char emptyBuffer[256];
738 memset(emptyBuffer, 0,
sizeof(emptyBuffer));
739 ::ToAscii(VK_SPACE, 0, emptyBuffer,
reinterpret_cast<LPWORD
>(&
buffer), 0);
740 ::ToAscii(vk_key, scancode, kbdBuffer,
reinterpret_cast<LPWORD
>(&
buffer), 0);
742 qCDebug(lcQpaEvents) << __FUNCTION__ <<
"for virtual key="
754 const UINT dpi = GetDpiForWindow(hwnd);
755 const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
757 return captionHeight;
760 const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
761 + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
762 return captionHeight + frameHeight;
767 static constexpr const Qt::WindowFlags titleBarHints =
777 HMENU
menu = GetSystemMenu(topLevelHwnd, FALSE);
781#define enabled (MF_BYCOMMAND | MFS_ENABLED)
782#define disabled (MF_BYCOMMAND | MFS_GRAYED)
785 const bool maximized = IsZoomed(topLevelHwnd);
798 HiliteMenuItem(topLevelHwnd,
menu, SC_RESTORE, MF_BYCOMMAND | MFS_HILITE);
801 SetMenuDefaultItem(
menu, SC_CLOSE, FALSE);
808 const int ret = TrackPopupMenuEx(
menu,
809 TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
810 pos.x(),
pos.y() + titleBarOffset,
817 HiliteMenuItem(topLevelHwnd,
menu, SC_RESTORE, MF_BYCOMMAND | MFS_UNHILITE);
824 Qt::KeyboardModifiers mods,
829 bool autorep =
false,
846 if (msg.message == WM_INPUTLANGCHANGE) {
851#if defined(WM_APPCOMMAND)
852 if (msg.message == WM_APPCOMMAND)
853 return translateMultimediaKeyEventInternal(
widget, msg);
859 if (msg.message != WM_CHAR && msg.message != WM_IME_CHAR)
864 if (PeekMessage(&peekedMsg, hwnd, 0, 0, PM_NOREMOVE) && peekedMsg.message == WM_DEADCHAR)
867 return translateKeyEventInternal(
widget, msg,
false,
result);
870bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(
QWindow *
window,
const MSG &msg)
872#if defined(WM_APPCOMMAND)
873 const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
875 bool skipPressRelease =
false;
876 switch (GET_DEVICE_LPARAM(msg.lParam)) {
877 case FAPPCOMMAND_MOUSE:
879 case FAPPCOMMAND_KEY:
883 if (cmd != APPCOMMAND_BROWSER_HOME)
884 skipPressRelease =
true;
888 const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam);
895 if (cmd < 0 || cmd > 52)
899 if (!skipPressRelease)
903# if QT_CONFIG(shortcut)
919 enum : LONG_PTR { RightFlag = 0x1000000 };
920 if (msg->wParam != VK_CONTROL || (msg->lParam & RightFlag) != 0
921 || (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYUP)) {
924 const UINT expectedMessage = msg->message == WM_SYSKEYUP
925 ? WM_KEYUP : msg->message;
927 if (PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_NOREMOVE) == FALSE
928 || peekedMsg.message != expectedMessage || peekedMsg.wParam != VK_MENU
929 || (peekedMsg.lParam & RightFlag) == 0) {
933 PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_REMOVE);
938 bool , LRESULT *lResult)
940 const bool altGr = m_detectAltGrModifier &&
isAltGr(&msg);
943 const UINT msgType = msg.message;
946 auto vk_key =
quint32(msg.wParam);
952 nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ?
ShiftLeft : 0);
953 nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ?
ShiftRight : 0);
954 nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ?
ControlLeft : 0);
955 nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ?
ControlRight : 0);
956 nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ?
AltLeft : 0);
957 nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ?
AltRight : 0);
958 nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ?
MetaLeft : 0);
959 nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ?
MetaRight : 0);
961 nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ?
CapsLock : 0);
962 nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ?
NumLock : 0);
963 nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ?
ScrollLock : 0);
979 if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
985 if (msgType == WM_SYSKEYDOWN && (nModifiers &
AltAny) != 0 && GetMenu(msg.hwnd) !=
nullptr)
987 if (msgType == WM_SYSKEYUP && nModifiers == 0 && GetMenu(msg.hwnd) !=
nullptr)
992 if (m_useRTLExtensions) {
993 static int dirStatus = 0;
995 && msg.wParam == VK_CONTROL
996 && msgType == WM_KEYDOWN) {
997 if (GetKeyState(VK_LCONTROL) < 0)
998 dirStatus = VK_LCONTROL;
999 else if (GetKeyState(VK_RCONTROL) < 0)
1000 dirStatus = VK_RCONTROL;
1001 }
else if (dirStatus) {
1002 if (msgType == WM_KEYDOWN) {
1003 if (msg.wParam == VK_SHIFT) {
1004 if (dirStatus == VK_LCONTROL && GetKeyState(VK_LSHIFT) < 0)
1005 dirStatus = VK_LSHIFT;
1006 else if (dirStatus == VK_RCONTROL && GetKeyState(VK_RSHIFT) < 0)
1007 dirStatus = VK_RSHIFT;
1011 }
else if (msgType == WM_KEYUP) {
1012 if (dirStatus == VK_LSHIFT
1013 && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
1014 || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
1016 scancode, vk_key, nModifiers,
QString(),
false);
1019 }
else if (dirStatus == VK_RSHIFT
1020 && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
1021 || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
1023 scancode, vk_key, nModifiers,
QString(),
false);
1036 if (msg.wParam == VK_PROCESSKEY)
1040 if (msg.wParam == 0 || msg.wParam == 0xFF)
1044 int modifiersIndex = 0;
1045 modifiersIndex |= (nModifiers &
ShiftAny ? 0x1 : 0);
1046 modifiersIndex |= (nModifiers &
ControlAny ? 0x2 : 0);
1047 modifiersIndex |= (nModifiers &
AltAny ? 0x4 : 0);
1051 int code = keyLayout[vk_key].
qtKey[modifiersIndex];
1073 if (!(msg.lParam & 0x1000000)) {
1100 state |= ((msg.wParam >=
'0' && msg.wParam <=
'9')
1105 if (
uint(msg.lParam) == 0x004c0001 ||
uint(msg.lParam) == 0xc04c0001)
1124 if (msgType == WM_KEYDOWN || msgType == WM_IME_KEYDOWN || msgType == WM_SYSKEYDOWN) {
1139 UINT charType = (msgType == WM_KEYDOWN
1141 : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR);
1144 if (PeekMessage(&wm_char,
nullptr, charType, charType, PM_REMOVE)) {
1152 m_lastHighSurrogate = uch;
1157 const QChar chars[2] = {m_lastHighSurrogate, uch};
1159 event.setCommitString(
QString(chars, 2));
1162 m_lastHighSurrogate =
QChar();
1165 m_lastHighSurrogate =
QChar();
1167 if (msgType == WM_SYSKEYDOWN && uch.
isLetter() && (msg.lParam & KF_ALTDOWN))
1169 if (!code && !uch.
row())
1177 if (uch.
isNull() && msgType == WM_IME_KEYDOWN) {
1181 vk_key = ImmGetVirtualKey(
reinterpret_cast<HWND
>(
window->winId()));
1183 wchar_t newKey[3] = {0};
1184 GetKeyboardState(keyState);
1185 int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0);
1187 uch =
QChar(newKey[0]);
1197 if (msg.wParam == VK_DELETE) {
1200 if (msgType != WM_SYSKEYDOWN || !code) {
1201 UINT
map = MapVirtualKey(UINT(msg.wParam), 2);
1203 if (!(
map & 0x80000000))
1207 if (!code && !uch.
row())
1246 const char a = uch.
row() ? char(0) : char(uch.cell());
1248#ifndef QT_NO_SHORTCUT
1260 if (msg.wParam == VK_PACKET)
1268 if (msgType == WM_SYSKEYDOWN && !
result &&
a) {
1272 SendMessage(
parent, WM_SYSCOMMAND, SC_KEYMENU,
a);
1302 if ((msg.lParam & 0x40000000) == 0 &&
1345 if (GetKeyState(VK_SHIFT) < 0)
1347 if (GetKeyState(VK_CONTROL) < 0)
1349 if (GetKeyState(VK_MENU) < 0)
1351 if (GetKeyState(VK_LWIN) < 0 || GetKeyState(VK_RWIN) < 0)
1361 const quint32 nativeVirtualKey =
e->nativeVirtualKey();
1362 if (nativeVirtualKey > 255)
1370 Qt::KeyboardModifiers keyMods =
e->modifiers();
1375 result << int(baseKey) + int(keyMods);
1378 Qt::KeyboardModifiers neededMods =
ModsTbl[
i];
1380 if (
key &&
key != baseKey && ((keyMods & neededMods) == neededMods)) {
1381 const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
1382 const int matchedKey = int(
key) + int(missingMods);
1385 [
key] (
int k) { return (k & ~Qt::KeyboardModifierMask) == key; });
1394 qCDebug(lcQpaEvents) << __FUNCTION__ <<
e <<
"nativeVirtualKey="
QChar toLower() const noexcept
Returns the lowercase equivalent if the character is uppercase or titlecase; otherwise returns the ch...
constexpr uchar row() const noexcept
Returns the row (most significant byte) of the Unicode character.
constexpr bool isLowSurrogate() const noexcept
Returns true if the QChar is the low part of a UTF16 surrogate (for example if its code point is in r...
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
constexpr uchar cell() const noexcept
Returns the cell (least significant byte) of the Unicode character.
constexpr bool isNull() const noexcept
Returns true if the character is the Unicode character 0x0000 ('\0'); otherwise returns false.
QChar toUpper() const noexcept
Returns the uppercase equivalent if the character is lowercase or titlecase; otherwise returns the ch...
constexpr bool isLetter() const noexcept
Returns true if the character is a letter (Letter_* categories); otherwise returns false.
constexpr bool isHighSurrogate() const noexcept
Returns true if the QChar is the high part of a UTF16 surrogate (for example if its code point is in ...
static bool sendEvent(QObject *receiver, QEvent *event)
Sends event event directly to receiver receiver, using the notify() function.
static QCoreApplication * instance() noexcept
Returns a pointer to the application's QCoreApplication (or QGuiApplication/QApplication) instance.
static QGuiApplicationPrivate * instance()
static QObject * focusObject()
Returns the QObject in currently active window that will be final receiver of events tied to focus,...
void applicationStateChanged(Qt::ApplicationState state)
The QKeyEvent class describes a key event.
The QKeySequence class encapsulates a key sequence as used by shortcuts.
qsizetype size() const noexcept
const_reference at(qsizetype i) const noexcept
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
\inmodule QtCore\reentrant
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static bool handleExtendedKeyEvent(QWindow *window, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
Qt::WindowFlags flags
the window flags of the window
static HWND handleOf(const QWindow *w)
Singleton container for all relevant information.
static QWindowsContext * instance()
static bool filterNativeEvent(MSG *msg, LRESULT *result)
static QWindowsIntegration * instance()
bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result)
To be called from the window procedure.
static Qt::KeyboardModifiers queryKeyboardModifiers()
QList< int > possibleKeys(const QKeyEvent *e) const
static QWindow * topLevelOf(QWindow *w)
EGLImageKHR int int EGLuint64KHR * modifiers
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
T toNativePixels(const T &value, const C *context)
Combined button and popup list for selecting options.
static void formatQEnum(QDebug &debug, QEnum value)
static void formatQFlags(QDebug &debug, const QFlags< Enum > &value)
constexpr char toAsciiUpper(char ch) noexcept
QTextStream & hex(QTextStream &stream)
Calls QTextStream::setIntegerBase(16) on stream and returns stream.
QTextStream & showbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() | QTextStream::ShowBase) on stream and r...
QTextStream & noshowbase(QTextStream &stream)
Calls QTextStream::setNumberFlags(QTextStream::numberFlags() & ~QTextStream::ShowBase) on stream and ...
@ Key_MediaTogglePlayPause
QTextStream & dec(QTextStream &stream)
Calls QTextStream::setIntegerBase(10) on stream and returns stream.
@ WindowContextHelpButtonHint
@ MSWindowsFixedSizeDialogHint
@ WindowMaximizeButtonHint
@ WindowMinimizeButtonHint
@ WindowMinMaxButtonsHint
static QT_WARNING_DISABLE_FLOAT_COMPARE ShiftResult shift(const QBezier *orig, QBezier *shifted, qreal offset, qreal threshold)
#define qCDebug(category,...)
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLenum GLsizei count
GLenum GLenum GLsizei const GLuint GLboolean enabled
#define Q_ASSERT_X(cond, x, msg)
static QString qtKey(CFStringRef cfkey)
static QWindowsInputContext * windowsInputContext()
LRESULT QT_WIN_CALLBACK qWindowsWndProc(HWND, UINT, WPARAM, LPARAM)
static const size_t NumMods
static const uint CmdTbl[]
static bool isAltGr(MSG *msg)
static KeyRecorder key_recorder
static void sendExtendedPressRelease(QWindow *w, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
static int asciiToKeycode(char a, int state)
static const uint KeyTbl[]
static int getTitleBarHeight(const HWND hwnd)
QDebug operator<<(QDebug d, const KeyboardLayoutItem &k)
quint32 winceKeyBend(quint32 keyCode)
static QString messageKeyText(const MSG &msg)
static const int QT_MAX_KEY_RECORDINGS
void setKbdState(unsigned char *kbd, bool shift, bool ctrl, bool alt)
static quint32 toKeyOrUnicode(quint32 vk, quint32 scancode, unsigned char *kbdBuffer, bool *isDeadkey=nullptr)
static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state)
static bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
static void showSystemMenu(QWindow *w)
static const Qt::KeyboardModifiers ModsTbl[]
static const Qt::KeyboardModifiers ModsTbl[]
settings remove("monkey")
QApplication app(argc, argv)
[0]
KeyRecord(int c, int a, int s, const QString &t)
KeyRecord records[QT_MAX_KEY_RECORDINGS]
void storeKey(int code, int ascii, int state, const QString &text)
KeyRecord * findKey(int code, bool remove)
static const size_t NumQtKeys
\inmodule QtCore \reentrant
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent