From 1150b69836a9e999ebefa38e7fa608d4f07ee6fd Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Mon, 21 Jun 2021 22:29:32 -0400 Subject: [PATCH] Fix Windows Auto-Type sending characters to virtualized guests * Fix #1833 --- src/autotype/windows/AutoTypeWindows.cpp | 58 +++++++++--- src/gui/osutils/winutils/WinUtils.cpp | 112 +---------------------- src/gui/osutils/winutils/WinUtils.h | 2 +- 3 files changed, 50 insertions(+), 122 deletions(-) diff --git a/src/autotype/windows/AutoTypeWindows.cpp b/src/autotype/windows/AutoTypeWindows.cpp index f391dd015..39e854bc3 100644 --- a/src/autotype/windows/AutoTypeWindows.cpp +++ b/src/autotype/windows/AutoTypeWindows.cpp @@ -83,20 +83,59 @@ bool AutoTypePlatformWin::raiseWindow(WId window) // void AutoTypePlatformWin::sendChar(const QChar& ch, bool isKeyDown) { - DWORD nativeFlags = KEYEVENTF_UNICODE; + auto vkey = VkKeyScanExW(ch.unicode(), GetKeyboardLayout(0)); + if (vkey == -1) { + // VKey not found, send as Unicode character + DWORD flags = KEYEVENTF_UNICODE; + if (!isKeyDown) { + flags |= KEYEVENTF_KEYUP; + } + + INPUT in; + in.type = INPUT_KEYBOARD; + in.ki.wVk = 0; + in.ki.wScan = ch.unicode(); + in.ki.dwFlags = flags; + in.ki.time = 0; + in.ki.dwExtraInfo = ::GetMessageExtraInfo(); + ::SendInput(1, &in, sizeof(INPUT)); + return; + } + + if (HIBYTE(vkey) & 0x1) { + sendKey(Qt::Key_Shift, true); + } + if (HIBYTE(vkey) & 0x2) { + sendKey(Qt::Key_Control, true); + } + if (HIBYTE(vkey) & 0x4) { + sendKey(Qt::Key_Alt, true); + } + + DWORD flags = KEYEVENTF_SCANCODE; if (!isKeyDown) { - nativeFlags |= KEYEVENTF_KEYUP; + flags |= KEYEVENTF_KEYUP; } INPUT in; in.type = INPUT_KEYBOARD; in.ki.wVk = 0; - in.ki.wScan = ch.unicode(); - in.ki.dwFlags = nativeFlags; + in.ki.wScan = MapVirtualKey(LOBYTE(vkey), MAPVK_VK_TO_VSC); + in.ki.dwFlags = flags; in.ki.time = 0; in.ki.dwExtraInfo = ::GetMessageExtraInfo(); ::SendInput(1, &in, sizeof(INPUT)); + + if (HIBYTE(vkey) & 0x1) { + sendKey(Qt::Key_Shift, false); + } + if (HIBYTE(vkey) & 0x2) { + sendKey(Qt::Key_Control, false); + } + if (HIBYTE(vkey) & 0x4) { + sendKey(Qt::Key_Alt, false); + } } // @@ -104,11 +143,8 @@ void AutoTypePlatformWin::sendChar(const QChar& ch, bool isKeyDown) // void AutoTypePlatformWin::sendKey(Qt::Key key, bool isKeyDown) { - DWORD nativeKeyCode = winUtils()->qtToNativeKeyCode(key); - if (nativeKeyCode < 1 || nativeKeyCode > 254) { - return; - } - DWORD nativeFlags = 0; + WORD nativeKeyCode = winUtils()->qtToNativeKeyCode(key); + DWORD nativeFlags = KEYEVENTF_SCANCODE; if (isExtendedKey(nativeKeyCode)) { nativeFlags |= KEYEVENTF_EXTENDEDKEY; } @@ -118,8 +154,8 @@ void AutoTypePlatformWin::sendKey(Qt::Key key, bool isKeyDown) INPUT in; in.type = INPUT_KEYBOARD; - in.ki.wVk = LOWORD(nativeKeyCode); - in.ki.wScan = LOWORD(::MapVirtualKeyW(nativeKeyCode, MAPVK_VK_TO_VSC)); + in.ki.wVk = 0; + in.ki.wScan = MapVirtualKey(LOBYTE(nativeKeyCode), MAPVK_VK_TO_VSC); in.ki.dwFlags = nativeFlags; in.ki.time = 0; in.ki.dwExtraInfo = ::GetMessageExtraInfo(); diff --git a/src/gui/osutils/winutils/WinUtils.cpp b/src/gui/osutils/winutils/WinUtils.cpp index ce44e71d3..d9c1b6907 100644 --- a/src/gui/osutils/winutils/WinUtils.cpp +++ b/src/gui/osutils/winutils/WinUtils.cpp @@ -216,7 +216,7 @@ void WinUtils::triggerGlobalShortcut(int id) // Translate qt key code to windows virtual key code // see: https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731%28v=vs.85%29.aspx // -DWORD WinUtils::qtToNativeKeyCode(Qt::Key key) +WORD WinUtils::qtToNativeKeyCode(Qt::Key key) { switch (key) { case Qt::Key_Backspace: @@ -266,80 +266,6 @@ DWORD WinUtils::qtToNativeKeyCode(Qt::Key key) case Qt::Key_Help: return VK_HELP; // 0x2F - case Qt::Key_0: - return 0x30; // 0x30 - case Qt::Key_1: - return 0x31; // 0x31 - case Qt::Key_2: - return 0x32; // 0x32 - case Qt::Key_3: - return 0x33; // 0x33 - case Qt::Key_4: - return 0x34; // 0x34 - case Qt::Key_5: - return 0x35; // 0x35 - case Qt::Key_6: - return 0x36; // 0x36 - case Qt::Key_7: - return 0x37; // 0x37 - case Qt::Key_8: - return 0x38; // 0x38 - case Qt::Key_9: - return 0x39; // 0x39 - - case Qt::Key_A: - return 0x41; // 0x41 - case Qt::Key_B: - return 0x42; // 0x42 - case Qt::Key_C: - return 0x43; // 0x43 - case Qt::Key_D: - return 0x44; // 0x44 - case Qt::Key_E: - return 0x45; // 0x45 - case Qt::Key_F: - return 0x46; // 0x46 - case Qt::Key_G: - return 0x47; // 0x47 - case Qt::Key_H: - return 0x48; // 0x48 - case Qt::Key_I: - return 0x49; // 0x49 - case Qt::Key_J: - return 0x4A; // 0x4A - case Qt::Key_K: - return 0x4B; // 0x4B - case Qt::Key_L: - return 0x4C; // 0x4C - case Qt::Key_M: - return 0x4D; // 0x4D - case Qt::Key_N: - return 0x4E; // 0x4E - case Qt::Key_O: - return 0x4F; // 0x4F - case Qt::Key_P: - return 0x50; // 0x50 - case Qt::Key_Q: - return 0x51; // 0x51 - case Qt::Key_R: - return 0x52; // 0x52 - case Qt::Key_S: - return 0x53; // 0x53 - case Qt::Key_T: - return 0x54; // 0x54 - case Qt::Key_U: - return 0x55; // 0x55 - case Qt::Key_V: - return 0x56; // 0x56 - case Qt::Key_W: - return 0x57; // 0x57 - case Qt::Key_X: - return 0x58; // 0x58 - case Qt::Key_Y: - return 0x59; // 0x59 - case Qt::Key_Z: - return 0x5A; // 0x5A - case Qt::Key_F1: return VK_F1; // 0x70 case Qt::Key_F2: @@ -394,42 +320,8 @@ DWORD WinUtils::qtToNativeKeyCode(Qt::Key key) case Qt::Key_ScrollLock: return VK_SCROLL; // 0x91 - case Qt::Key_Exclam: // ! - case Qt::Key_QuoteDbl: // " - case Qt::Key_NumberSign: // # - case Qt::Key_Dollar: // $ - case Qt::Key_Percent: // % - case Qt::Key_Ampersand: // & - case Qt::Key_Apostrophe: // ' - case Qt::Key_ParenLeft: // ( - case Qt::Key_ParenRight: // ) - case Qt::Key_Asterisk: // * - case Qt::Key_Plus: // + - case Qt::Key_Comma: // , - case Qt::Key_Minus: // - - case Qt::Key_Period: // . - case Qt::Key_Slash: // / - case Qt::Key_Colon: // : - case Qt::Key_Semicolon: // ; - case Qt::Key_Less: // < - case Qt::Key_Equal: // = - case Qt::Key_Greater: // > - case Qt::Key_Question: // ? - case Qt::Key_BracketLeft: // [ - case Qt::Key_Backslash: // '\' - case Qt::Key_BracketRight: // ] - case Qt::Key_AsciiCircum: // ^ - case Qt::Key_Underscore: // _ - case Qt::Key_QuoteLeft: // ` - case Qt::Key_BraceLeft: // { - case Qt::Key_Bar: // | - case Qt::Key_BraceRight: // } - case Qt::Key_AsciiTilde: // ~ - return LOBYTE(::VkKeyScanExW(key, ::GetKeyboardLayout(0))); - default: - Q_ASSERT(false); - return 0; + return LOBYTE(::VkKeyScanExW(key, ::GetKeyboardLayout(0))); } } // clang-format on diff --git a/src/gui/osutils/winutils/WinUtils.h b/src/gui/osutils/winutils/WinUtils.h index ca595dea2..9e4492a5f 100644 --- a/src/gui/osutils/winutils/WinUtils.h +++ b/src/gui/osutils/winutils/WinUtils.h @@ -54,7 +54,7 @@ public: QString* error = nullptr) override; bool unregisterGlobalShortcut(const QString& name) override; - DWORD qtToNativeKeyCode(Qt::Key key); + WORD qtToNativeKeyCode(Qt::Key key); DWORD qtToNativeModifiers(Qt::KeyboardModifiers modifiers); bool canPreventScreenCapture() const override;