11#include <QtGui/qguiapplication.h>
12#include <QtGui/qwindow.h>
13#include <qpa/qwindowsysteminterface.h>
14#include <private/qguiapplication_p.h>
15#include <private/qhighdpiscaling_p.h>
16#include <QtGui/qevent.h>
17#include <QtGui/private/qwindowsguieventdispatcher_p.h>
18#include <QtCore/private/qdebug_p.h>
19#include <QtCore/private/qtools_p.h>
21#if defined(WM_APPCOMMAND)
22# ifndef FAPPCOMMAND_MOUSE
23# define FAPPCOMMAND_MOUSE 0x8000
25# ifndef FAPPCOMMAND_KEY
26# define FAPPCOMMAND_KEY 0
28# ifndef FAPPCOMMAND_OEM
29# define FAPPCOMMAND_OEM 0x1000
31# ifndef FAPPCOMMAND_MASK
32# define FAPPCOMMAND_MASK 0xF000
34# ifndef GET_APPCOMMAND_LPARAM
35# define GET_APPCOMMAND_LPARAM(lParam) ((short)(HIWORD(lParam) & ~FAPPCOMMAND_MASK))
37# ifndef GET_DEVICE_LPARAM
38# define GET_DEVICE_LPARAM(lParam) ((WORD)(HIWORD(lParam) & FAPPCOMMAND_MASK))
40# ifndef GET_MOUSEORKEY_LPARAM
41# define GET_MOUSEORKEY_LPARAM GET_DEVICE_LPARAM
43# ifndef GET_FLAGS_LPARAM
44# define GET_FLAGS_LPARAM(lParam) (LOWORD(lParam))
46# ifndef GET_KEYSTATE_LPARAM
47# define GET_KEYSTATE_LPARAM(lParam) GET_FLAGS_LPARAM(lParam)
54
55
56
57
58
59
60
65 : m_useRTLExtensions(
false), m_keyGrabber(
nullptr)
67 memset(keyLayout, 0,
sizeof(keyLayout));
68 auto *app =
static_cast<QGuiApplication *>(QGuiApplication::instance());
69 QObject::connect(app, &QGuiApplication::applicationStateChanged,
70 app, clearKeyRecorderOnApplicationInActive);
77#define LANG_PASHTO 0x63
80#define LANG_SYRIAC 0x5a
83#define LANG_DIVEHI 0x65
86#define VK_OEM_PLUS 0xBB
95 const auto keyFlags = HIWORD(msg.lParam);
96 quint32 scancode = LOBYTE(keyFlags);
99 if ((keyFlags & KF_EXTENDED) != 0)
121 inline void storeKey(
int code,
int ascii,
int state,
const QString& text);
132 if (state == Qt::ApplicationInactive)
139 for (
int i = 0; i <
nrecs; ++i) {
140 if (records[i].code == code) {
142 deleted_record = records[i];
144 while (i + 1 <
nrecs) {
145 records[i] = records[i + 1];
149 result = &deleted_record;
151 result = &records[i];
162 "Internal KeyRecorder",
163 "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
166 qWarning(
"Qt: Internal keyboard buffer overflow");
169 records[nrecs++] = KeyRecord(code,ascii,state,text);
364 Qt::Key_MediaPrevious,
366 Qt::Key_MediaTogglePlayPause,
461 Qt::Key_MediaPrevious,
463 Qt::Key_MediaTogglePlayPause,
474 Qt::Key_MicVolumeDown,
498 Qt::Key_AudioForward,
510 Qt::ControlModifier | Qt::ShiftModifier,
512 Qt::AltModifier | Qt::ShiftModifier,
513 Qt::AltModifier | Qt::ControlModifier,
514 Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier,
518static_assert((
NumMods == KeyboardLayoutItem::NumQtKeys));
520#ifndef QT_NO_DEBUG_STREAM
523 QDebugStateSaver saver(d);
525 d <<
"KeyboardLayoutItem(";
527 for (size_t i = 0; i < NumMods; ++i) {
528 if (
const quint32 qtKey = k.qtKey[i]) {
529 d <<
'[' << i <<
' ';
530 QtDebugUtils::formatQFlags(d, ModsTbl[i]);
531 d <<
' ' << Qt::hex << Qt::showbase << qtKey << Qt::dec << Qt::noshowbase <<
' ';
532 QtDebugUtils::formatQEnum(d, Qt::Key(qtKey));
533 if (qtKey >= 32 && qtKey < 128)
534 d <<
" '" <<
char(qtKey) <<
'\'';
535 if (k.deadkeys & (1<<i))
547
548
551 return KeyTbl[keyCode];
555static inline quint32 toKeyOrUnicode(quint32 vk, quint32 scancode,
unsigned char *kbdBuffer,
bool *isDeadkey =
nullptr)
557 Q_ASSERT(vk > 0 && vk < 256);
559 QChar unicodeBuffer[5];
560 int res = ToUnicode(vk, scancode, kbdBuffer,
reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
563 if (res == 0 && kbdBuffer[VK_CONTROL]) {
564 const unsigned char controlState = kbdBuffer[VK_CONTROL];
565 kbdBuffer[VK_CONTROL] = 0;
566 res = ToUnicode(vk, scancode, kbdBuffer,
reinterpret_cast<LPWSTR>(unicodeBuffer), 5, 0);
567 kbdBuffer[VK_CONTROL] = controlState;
570 code = unicodeBuffer[0].toUpper().unicode();
574 if (code < 0x20 || code == 0x7f)
575 code = winceKeyBend(vk);
578 *isDeadkey = (res == -1);
580 return code == Qt::Key_unknown ? 0 : code;
585 a = QtMiscUtils::toAsciiUpper(a);
586 if ((state & Qt::ControlModifier) != 0) {
587 if (a >= 0 && a <= 31)
600 for (KeyboardLayoutItem &k : keyLayout)
609
611 LCID newLCID = MAKELCID(quintptr(GetKeyboardLayout(0)), SORT_DEFAULT);
615 wchar_t LCIDFontSig[16];
616 if (GetLocaleInfo(newLCID, LOCALE_FONTSIGNATURE, LCIDFontSig,
sizeof(LCIDFontSig) /
sizeof(
wchar_t))
617 && (LCIDFontSig[7] &
wchar_t(0x0800)))
620 WCHAR buffer[KL_NAMELENGTH];
621 if (GetKeyboardLayoutName(buffer)) {
623 m_isHebrewLayout = buffer[KL_NAMELENGTH - 4] == L'4' && buffer[KL_NAMELENGTH - 3] == L'0'
624 && buffer[KL_NAMELENGTH - 2] == L'D';
626 m_isHebrewLayout =
false;
628 keyboardInputDirection = bidi ? Qt::RightToLeft : Qt::LeftToRight;
634inline void setKbdState(
unsigned char *kbd,
bool shift,
bool ctrl,
bool alt)
636 kbd[VK_LSHIFT ] = (shift ? 0x80 : 0);
637 kbd[VK_SHIFT ] = (shift ? 0x80 : 0);
638 kbd[VK_LCONTROL] = (ctrl ? 0x80 : 0);
639 kbd[VK_CONTROL ] = (ctrl ? 0x80 : 0);
640 kbd[VK_RMENU ] = (alt ? 0x80 : 0);
641 kbd[VK_MENU ] = (alt ? 0x80 : 0);
647 unsigned char kbdBuffer[256];
648 GetKeyboardState(kbdBuffer);
649 const quint32 scancode = getScancode(msg);
650 updatePossibleKeyCodes(kbdBuffer, scancode, quint32(msg.wParam));
656void QWindowsKeyMapper::updatePossibleKeyCodes(
unsigned char *kbdBuffer, quint32 scancode,
659 if (!vk_key || (keyLayout[vk_key].exists && !keyLayout[vk_key].dirty))
663 unsigned char buffer[256];
664 memcpy(buffer, kbdBuffer,
sizeof(buffer));
666 buffer[VK_LWIN ] = 0;
667 buffer[VK_RWIN ] = 0;
668 buffer[VK_CAPITAL ] = 0;
669 buffer[VK_NUMLOCK ] = 0;
670 buffer[VK_SCROLL ] = 0;
672 buffer[VK_RSHIFT ] = 0;
673 buffer[VK_RCONTROL] = 0;
674 buffer[VK_LMENU ] = 0;
680 bool isDeadKey =
false;
681 keyLayout[vk_key].deadkeys = 0;
682 keyLayout[vk_key].dirty =
false;
683 keyLayout[vk_key].exists =
true;
685 keyLayout[vk_key].qtKey[0] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
686 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x01 : 0;
688 keyLayout[vk_key].qtKey[1] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
689 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x02 : 0;
691 keyLayout[vk_key].qtKey[2] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
692 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x04 : 0;
694 keyLayout[vk_key].qtKey[3] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
695 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x08 : 0;
697 keyLayout[vk_key].qtKey[4] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
698 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x10 : 0;
700 keyLayout[vk_key].qtKey[5] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
701 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x20 : 0;
703 keyLayout[vk_key].qtKey[6] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
704 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x40 : 0;
706 keyLayout[vk_key].qtKey[7] = toKeyOrUnicode(vk_key, scancode, buffer, &isDeadKey);
707 keyLayout[vk_key].deadkeys |= isDeadKey ? 0x80 : 0;
709 quint32 fallbackKey = winceKeyBend(vk_key);
710 if (!fallbackKey || fallbackKey == Qt::Key_unknown) {
712 if (vk_key != keyLayout[vk_key].qtKey[0]
713 && (vk_key != keyLayout[vk_key].qtKey[1] || m_isHebrewLayout)
714 && (vk_key < 0x5B && vk_key > 0x2F))
715 fallbackKey = vk_key;
717 keyLayout[vk_key].qtKey[8] = fallbackKey;
721 if (keyLayout[vk_key].deadkeys) {
728 unsigned char emptyBuffer[256];
729 memset(emptyBuffer, 0,
sizeof(emptyBuffer));
730 ::ToAscii(VK_SPACE, 0, emptyBuffer,
reinterpret_cast<LPWORD>(&buffer), 0);
731 ::ToAscii(vk_key, scancode, kbdBuffer,
reinterpret_cast<LPWORD>(&buffer), 0);
733 qCDebug(lcQpaEvents) <<
__FUNCTION__ <<
"for virtual key="
734 << Qt::hex << Qt::showbase << vk_key << Qt::dec << Qt::noshowbase << keyLayout[vk_key];
739 const QChar ch = QChar(ushort(msg.wParam));
740 return ch.isNull() ? QString() : QString(ch);
745 const UINT dpi = GetDpiForWindow(hwnd);
746 const int captionHeight = GetSystemMetricsForDpi(SM_CYCAPTION, dpi);
748 return captionHeight;
751 const int frameHeight = GetSystemMetricsForDpi(SM_CYSIZEFRAME, dpi)
752 + GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
753 return captionHeight + frameHeight;
758 static constexpr const Qt::WindowFlags titleBarHints =
759 Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint | Qt::WindowContextHelpButtonHint;
760 return (flags & Qt::WindowSystemMenuHint) && (flags & Qt::WindowTitleHint) && !(flags & titleBarHints)
761 && (flags & (Qt::FramelessWindowHint | Qt::CustomizeWindowHint));
767 HWND topLevelHwnd = QWindowsWindow::handleOf(topLevel);
768 HMENU menu = GetSystemMenu(topLevelHwnd, FALSE);
772#define enabled (MF_BYCOMMAND | MFS_ENABLED)
773#define disabled (MF_BYCOMMAND | MFS_GRAYED)
775 EnableMenuItem(menu, SC_MINIMIZE, (topLevel->flags() & Qt::WindowMinimizeButtonHint) ?
enabled :
disabled);
776 const bool maximized = IsZoomed(topLevelHwnd);
778 EnableMenuItem(menu, SC_MAXIMIZE, !(topLevel->flags() & Qt::WindowMaximizeButtonHint) || maximized ?
disabled :
enabled);
783 EnableMenuItem(menu, SC_SIZE, (topLevel->flags() & Qt::MSWindowsFixedSizeDialogHint) || maximized ?
disabled :
enabled);
785 EnableMenuItem(menu, SC_CLOSE,
enabled);
789 HiliteMenuItem(topLevelHwnd, menu, SC_RESTORE, MF_BYCOMMAND | MFS_HILITE);
792 SetMenuDefaultItem(menu, SC_CLOSE, FALSE);
797 const QPoint pos = QHighDpi::toNativePixels(topLevel->geometry().topLeft(), topLevel);
798 const int titleBarOffset = isSystemMenuOffsetNeeded(topLevel->flags()) ? getTitleBarHeight(topLevelHwnd) : 0;
799 const int ret = TrackPopupMenuEx(menu,
800 TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD,
801 pos.x(), pos.y() + titleBarOffset,
808 HiliteMenuItem(topLevelHwnd, menu, SC_RESTORE, MF_BYCOMMAND | MFS_UNHILITE);
811 qWindowsWndProc(topLevelHwnd, WM_SYSCOMMAND, WPARAM(ret), 0);
815 Qt::KeyboardModifiers mods,
816 quint32 nativeScanCode,
817 quint32 nativeVirtualKey,
818 quint32 nativeModifiers,
819 const QString & text = QString(),
820 bool autorep =
false,
823 QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyPress, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
824 QWindowSystemInterface::handleExtendedKeyEvent(w, timestamp, QEvent::KeyRelease, k, mods, nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
828
829
832 const MSG &msg, LRESULT *result)
837 if (msg.message == WM_INPUTLANGCHANGE) {
842#if defined(WM_APPCOMMAND)
843 if (msg.message == WM_APPCOMMAND)
844 return translateMultimediaKeyEventInternal(widget, msg);
850 if (msg.message != WM_CHAR && msg.message != WM_IME_CHAR)
855 if (PeekMessage(&peekedMsg, hwnd, 0, 0, PM_NOREMOVE) && peekedMsg.message == WM_DEADCHAR)
858 return translateKeyEventInternal(widget, msg,
false, result);
861bool QWindowsKeyMapper::translateMultimediaKeyEventInternal(QWindow *window,
const MSG &msg)
863#if defined(WM_APPCOMMAND)
864 const int cmd = GET_APPCOMMAND_LPARAM(msg.lParam);
866 bool skipPressRelease =
false;
867 switch (GET_DEVICE_LPARAM(msg.lParam)) {
868 case FAPPCOMMAND_MOUSE:
870 case FAPPCOMMAND_KEY:
874 if (cmd != APPCOMMAND_BROWSER_HOME)
875 skipPressRelease =
true;
879 const int dwKeys = GET_KEYSTATE_LPARAM(msg.lParam);
881 state |= (dwKeys & MK_SHIFT ?
int(Qt::ShiftModifier) : 0);
882 state |= (dwKeys & MK_CONTROL ?
int(Qt::ControlModifier) : 0);
884 QWindow *receiver = m_keyGrabber ? m_keyGrabber : window;
886 if (cmd < 0 || cmd > 52)
889 const int qtKey =
int(CmdTbl[cmd]);
890 if (!skipPressRelease)
891 sendExtendedPressRelease(receiver, msg.time, qtKey, Qt::KeyboardModifier(state), 0, 0, 0);
894# if QT_CONFIG(shortcut)
895 const QKeySequence sequence(Qt::Modifier(state) | Qt::Key(qtKey));
896 return QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(sequence);
910 enum : LONG_PTR { RightFlag = 0x1000000 };
911 if (msg->wParam != VK_CONTROL || (msg->lParam & RightFlag) != 0
912 || (msg->message != WM_KEYDOWN && msg->message != WM_SYSKEYUP)) {
915 const UINT expectedMessage = msg->message == WM_SYSKEYUP
916 ? WM_KEYUP : msg->message;
918 if (PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_NOREMOVE) == FALSE
919 || peekedMsg.message != expectedMessage || peekedMsg.wParam != VK_MENU
920 || (peekedMsg.lParam & RightFlag) == 0) {
924 PeekMessage(&peekedMsg, msg->hwnd, 0, 0, PM_REMOVE);
929 bool , LRESULT *lResult)
931 const bool altGr = m_detectAltGrModifier && isAltGr(&msg);
934 const UINT msgType = msg.message;
936 const quint32 scancode = getScancode(msg);
937 auto vk_key = quint32(msg.wParam);
938 quint32 nModifiers = 0;
940 QWindow *receiver = m_keyGrabber ? m_keyGrabber : window;
943 nModifiers |= (GetKeyState(VK_LSHIFT ) & 0x80 ?
ShiftLeft : 0);
944 nModifiers |= (GetKeyState(VK_RSHIFT ) & 0x80 ?
ShiftRight : 0);
945 nModifiers |= (GetKeyState(VK_LCONTROL) & 0x80 ?
ControlLeft : 0);
946 nModifiers |= (GetKeyState(VK_RCONTROL) & 0x80 ?
ControlRight : 0);
947 nModifiers |= (GetKeyState(VK_LMENU ) & 0x80 ?
AltLeft : 0);
948 nModifiers |= (GetKeyState(VK_RMENU ) & 0x80 ?
AltRight : 0);
949 nModifiers |= (GetKeyState(VK_LWIN ) & 0x80 ?
MetaLeft : 0);
950 nModifiers |= (GetKeyState(VK_RWIN ) & 0x80 ?
MetaRight : 0);
952 nModifiers |= (GetKeyState(VK_CAPITAL ) & 0x01 ?
CapsLock : 0);
953 nModifiers |= (GetKeyState(VK_NUMLOCK ) & 0x01 ?
NumLock : 0);
954 nModifiers |= (GetKeyState(VK_SCROLL ) & 0x01 ?
ScrollLock : 0);
961 state |= (nModifiers & ShiftAny ?
int(Qt::ShiftModifier) : 0);
962 state |= (nModifiers & AltLeft ?
int(Qt::AltModifier) : 0);
963 if ((nModifiers & AltRight) != 0)
964 state |= m_seenAltGr ? Qt::GroupSwitchModifier : Qt::AltModifier;
965 if ((nModifiers & ControlAny) != 0 && (state & Qt::GroupSwitchModifier) == 0)
966 state |= Qt::ControlModifier;
967 state |= (nModifiers & MetaAny ?
int(Qt::MetaModifier) : 0);
970 if (msgType == WM_CHAR || msgType == WM_IME_CHAR) {
971 sendExtendedPressRelease(receiver, msg.time, 0, Qt::KeyboardModifier(state), scancode, 0, nModifiers, messageKeyText(msg),
false);
976 if (msgType == WM_SYSKEYDOWN && (nModifiers & AltAny) != 0 && GetMenu(msg.hwnd) !=
nullptr)
978 if (msgType == WM_SYSKEYUP && nModifiers == 0 && GetMenu(msg.hwnd) !=
nullptr)
983 if (m_useRTLExtensions) {
984 static int dirStatus = 0;
985 if (!dirStatus && state == Qt::ControlModifier
986 && msg.wParam == VK_CONTROL
987 && msgType == WM_KEYDOWN) {
988 if (GetKeyState(VK_LCONTROL) < 0)
989 dirStatus = VK_LCONTROL;
990 else if (GetKeyState(VK_RCONTROL) < 0)
991 dirStatus = VK_RCONTROL;
992 }
else if (dirStatus) {
993 if (msgType == WM_KEYDOWN) {
994 if (msg.wParam == VK_SHIFT) {
995 if (dirStatus == VK_LCONTROL && GetKeyState(VK_LSHIFT) < 0)
996 dirStatus = VK_LSHIFT;
997 else if (dirStatus == VK_RCONTROL && GetKeyState(VK_RSHIFT) < 0)
998 dirStatus = VK_RSHIFT;
1002 }
else if (msgType == WM_KEYUP) {
1003 if (dirStatus == VK_LSHIFT
1004 && ((msg.wParam == VK_SHIFT && GetKeyState(VK_LCONTROL))
1005 || (msg.wParam == VK_CONTROL && GetKeyState(VK_LSHIFT)))) {
1006 sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_L, {},
1007 scancode, vk_key, nModifiers, QString(),
false);
1010 }
else if (dirStatus == VK_RSHIFT
1011 && ( (msg.wParam == VK_SHIFT && GetKeyState(VK_RCONTROL))
1012 || (msg.wParam == VK_CONTROL && GetKeyState(VK_RSHIFT)))) {
1013 sendExtendedPressRelease(receiver, msg.time, Qt::Key_Direction_R, {},
1014 scancode, vk_key, nModifiers, QString(),
false);
1027 if (msg.wParam == VK_PROCESSKEY)
1031 if (msg.wParam == 0 || msg.wParam == 0xFF)
1035 int modifiersIndex = 0;
1036 modifiersIndex |= (nModifiers &
ShiftAny ? 0x1 : 0);
1037 modifiersIndex |= (nModifiers &
ControlAny ? 0x2 : 0);
1038 modifiersIndex |= (nModifiers &
AltAny ? 0x4 : 0);
1042 int code = keyLayout[vk_key].qtKey[modifiersIndex];
1046 if ((code == Qt::Key_Return) && (msg.lParam & 0x1000000))
1047 code = Qt::Key_Enter;
1049 code = Qt::Key_AltGr;
1054 if (code == Qt::Key_Control)
1055 state = state ^ Qt::ControlModifier;
1056 else if (code == Qt::Key_Shift)
1057 state = state ^ Qt::ShiftModifier;
1058 else if (code == Qt::Key_Alt)
1059 state = state ^ Qt::AltModifier;
1060 else if (code == Qt::Key_AltGr)
1061 state = state ^ Qt::GroupSwitchModifier;
1064 if (!(msg.lParam & 0x1000000)) {
1070 case Qt::Key_PageUp:
1071 case Qt::Key_PageDown:
1074 case Qt::Key_Insert:
1075 case Qt::Key_Delete:
1076 case Qt::Key_Asterisk:
1079 case Qt::Key_Period:
1091 state |= ((msg.wParam >=
'0' && msg.wParam <=
'9')
1093 ? 0 :
int(Qt::KeypadModifier);
1096 if (uint(msg.lParam) == 0x004c0001 || uint(msg.lParam) == 0xc04c0001)
1097 state |= Qt::KeypadModifier;
1106 case Qt::Key_NumLock:
1107 state |= Qt::KeypadModifier;
1115 if (msgType == WM_KEYDOWN || msgType == WM_IME_KEYDOWN || msgType == WM_SYSKEYDOWN) {
1123 if (rec && rec
->state != state) {
1130 UINT charType = (msgType == WM_KEYDOWN
1132 : msgType == WM_IME_KEYDOWN ? WM_IME_CHAR : WM_SYSCHAR);
1135 if (PeekMessage(&wm_char,
nullptr, charType, charType, PM_REMOVE)) {
1136 if (QWindowsContext::filterNativeEvent(&wm_char, lResult))
1138 if (receiver && QWindowsContext::filterNativeEvent(receiver, &wm_char, lResult))
1141 uch = QChar(ushort(wm_char.wParam));
1142 if (uch.isHighSurrogate()) {
1143 m_lastHighSurrogate = uch;
1146 if (uch.isLowSurrogate() && !m_lastHighSurrogate.isNull()) {
1147 if (QObject *focusObject = QGuiApplication::focusObject()) {
1148 const QChar chars[2] = {m_lastHighSurrogate, uch};
1149 QInputMethodEvent event;
1150 event.setCommitString(QString(chars, 2));
1151 QCoreApplication::sendEvent(focusObject, &event);
1153 m_lastHighSurrogate = QChar();
1156 m_lastHighSurrogate = QChar();
1158 if (msgType == WM_SYSKEYDOWN && uch.isLetter() && (msg.lParam & KF_ALTDOWN))
1159 uch = uch.toLower();
1160 if (!code && !uch.row())
1168 if (uch.isNull() && msgType == WM_IME_KEYDOWN) {
1169 const auto *windowsInputContext =
1171 if (!(windowsInputContext && windowsInputContext->isComposing()))
1172 vk_key = ImmGetVirtualKey(
reinterpret_cast<HWND>(window->winId()));
1174 wchar_t newKey[3] = {0};
1175 GetKeyboardState(keyState);
1176 int val = ToUnicode(vk_key, scancode, keyState, newKey, 2, 0);
1178 uch = QChar(newKey[0]);
1188 if (msg.wParam == VK_DELETE) {
1189 uch = QChar(QLatin1Char(0x7f));
1191 if (msgType != WM_SYSKEYDOWN || !code) {
1192 UINT map = MapVirtualKey(UINT(msg.wParam), 2);
1194 if (!(map & 0x80000000))
1195 uch = QChar(ushort(map));
1198 if (!code && !uch.row())
1203 if (state == Qt::AltModifier) {
1205 case Qt::Key_Escape:
1219 if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
1220 code = Qt::Key_Backtab;
1225 if (code < Qt::Key_Shift || code > Qt::Key_ScrollLock) {
1226 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
1227 Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text,
true);
1228 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
1229 Qt::KeyboardModifier(state), scancode, quint32(msg.wParam), nModifiers, rec->text,
true);
1236 const QString text = uch.isNull() ? QString() : QString(uch);
1237 const char a = uch.row() ?
char(0) :
char(uch.cell());
1238 const Qt::KeyboardModifiers modifiers(state);
1239#ifndef QT_NO_SHORTCUT
1241 if (modifiers == Qt::SHIFT && code == Qt::Key_F10
1242 && !QGuiApplicationPrivate::instance()->shortcutMap.hasShortcutForKeySequence(QKeySequence(Qt::SHIFT | Qt::Key_F10))) {
1246 key_recorder.storeKey(
int(msg.wParam), a, state, text);
1251 if (msg.wParam == VK_PACKET)
1254 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
1255 modifiers, scancode, quint32(msg.wParam), nModifiers, text,
false);
1259 if (msgType == WM_SYSKEYDOWN && !result && a) {
1260 HWND parent = GetParent(QWindowsWindow::handleOf(receiver));
1262 if (GetMenu(parent)) {
1263 SendMessage(parent, WM_SYSCOMMAND, SC_KEYMENU, a);
1268 parent = GetParent(parent);
1283 if (!rec && !(code == Qt::Key_Shift
1284 || code == Qt::Key_Control
1285 || code == Qt::Key_Meta
1286 || code == Qt::Key_Alt)) {
1293 if ((msg.lParam & 0x40000000) == 0 &&
1294 Qt::KeyboardModifier(state) == Qt::NoModifier &&
1295 ((code == Qt::Key_F18) || (code == Qt::Key_F19) || (code == Qt::Key_F20))) {
1296 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyPress, code,
1297 Qt::MetaModifier, scancode,
1298 quint32(msg.wParam), MetaLeft);
1299 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
1300 Qt::NoModifier, scancode,
1301 quint32(msg.wParam), 0);
1309 if (code == Qt::Key_Tab && (state & Qt::ShiftModifier) == Qt::ShiftModifier)
1310 code = Qt::Key_Backtab;
1311 QWindowSystemInterface::handleExtendedKeyEvent(receiver, msg.time, QEvent::KeyRelease, code,
1312 Qt::KeyboardModifier(state), scancode, quint32(msg.wParam),
1314 (rec ? rec->text : QString()),
false);
1317 if (code == Qt::Key_Alt) {
1319 HWND parent = GetParent(QWindowsWindow::handleOf(receiver));
1325 parent = GetParent(parent);
1335 Qt::KeyboardModifiers modifiers = Qt::NoModifier;
1336 if (GetKeyState(VK_SHIFT) < 0)
1337 modifiers |= Qt::ShiftModifier;
1338 if (GetKeyState(VK_CONTROL) < 0)
1339 modifiers |= Qt::ControlModifier;
1340 if (GetKeyState(VK_MENU) < 0)
1341 modifiers |= Qt::AltModifier;
1342 if (GetKeyState(VK_LWIN) < 0 || GetKeyState(VK_RWIN) < 0)
1343 modifiers |= Qt::MetaModifier;
1349 QList<QKeyCombination> result;
1352 const quint32 nativeVirtualKey = e->nativeVirtualKey();
1353 if (nativeVirtualKey > 255)
1360 quint32 baseKey = kbItem.qtKey[0];
1361 Qt::KeyboardModifiers keyMods = e->modifiers();
1362 if (baseKey == Qt::Key_Return && (e->nativeModifiers() & ExtendedKey)) {
1363 result << (Qt::Key_Enter | keyMods);
1369 if (baseKey == Qt::Key_Tab && (keyMods & Qt::ShiftModifier))
1370 result << (Qt::Key_Backtab | (keyMods & ~Qt::ShiftModifier));
1373 result << QKeyCombination::fromCombined(
int(baseKey) +
int(keyMods));
1375 for (size_t i = 1; i < NumMods; ++i) {
1376 Qt::KeyboardModifiers neededMods = ModsTbl[i];
1377 quint32 key = kbItem.qtKey[i];
1378 if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
1379 const Qt::KeyboardModifiers missingMods = keyMods & ~neededMods;
1380 const auto matchedKey = QKeyCombination::fromCombined(
int(key) +
int(missingMods));
1381 const auto it = std::find_if(result.begin(), result.end(),
1382 [key](
auto keyCombination) {
1383 return keyCombination.key() == key;
1387 if (it == result.end())
1388 result << matchedKey;
1389 else if (missingMods > it->keyboardModifiers())
1393 qCDebug(lcQpaEvents) <<
__FUNCTION__ << e <<
"nativeVirtualKey="
1394 << Qt::showbase << Qt::hex << e->nativeVirtualKey() << Qt::dec << Qt::noshowbase
1395 << e->modifiers() << kbItem <<
"\n returns" << result;
\inmodule QtCore\reentrant
Singleton container for all relevant information.
QWindowsWindow * findPlatformWindow(const QWindowsMenuBar *mb) const
static QWindowsContext * instance()
Windows Input context implementation.
static QWindowsIntegration * instance()
Translates Windows keys to QWindowSystemInterface events.
bool translateKeyEvent(QWindow *widget, HWND hwnd, const MSG &msg, LRESULT *result)
To be called from the window procedure.
Qt::KeyboardModifiers queryKeyboardModifiers() const override
QList< QKeyCombination > possibleKeyCombinations(const QKeyEvent *e) const override
Combined button and popup list for selecting options.
static const Qt::KeyboardModifiers ModsTbl[]
static bool isAltGr(MSG *msg)
static constexpr quint32 getScancode(const MSG &msg)
static int asciiToKeycode(char a, int state)
static const size_t NumMods
static const int QT_MAX_KEY_RECORDINGS
static int getTitleBarHeight(const HWND hwnd)
quint32 winceKeyBend(quint32 keyCode)
static void sendExtendedPressRelease(QWindow *w, unsigned long timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString &text=QString(), bool autorep=false, ushort count=1)
static QString messageKeyText(const MSG &msg)
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 const uint CmdTbl[]
static void clearKeyRecorderOnApplicationInActive(Qt::ApplicationState state)
static bool isSystemMenuOffsetNeeded(const Qt::WindowFlags flags)
static void showSystemMenu(QWindow *w)
static KeyRecorder key_recorder
static const uint KeyTbl[]
KeyRecord(int c, int a, int s, const QString &t)
void storeKey(int code, int ascii, int state, const QString &text)
KeyRecord * findKey(int code, bool remove)
KeyRecord records[QT_MAX_KEY_RECORDINGS]