deskflow/src/lib/platform/MSWindowsKeyState.cpp
Povilas Kanapickas 314899ac7d chore: arch, Remove support for lazy error code to string evaluations
This functionality is not needed because in all code paths the error
code is immediately converted to string without actually using the lazy
evaluation functionality.

based-on: 53dff5b803
ported and expanded by sithlord48
2025-05-28 14:00:18 +01:00

1340 lines
50 KiB
C++

/*
* Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2022, 2025 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2003 Chris Schoeneman
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/
#include "platform/MSWindowsKeyState.h"
#include "arch/win32/XArchWindows.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "platform/MSWindowsDesks.h"
#include "platform/MSWindowsHandle.h"
// extended mouse buttons
#if !defined(VK_XBUTTON1)
#define VK_XBUTTON1 0x05
#define VK_XBUTTON2 0x06
#endif
//
// MSWindowsKeyState
//
// map virtual keys to deskflow key enumeration
const KeyID MSWindowsKeyState::s_virtualKey[] = {
/* 0x000 */ {kKeyNone}, // reserved
/* 0x001 */ {kKeyNone}, // VK_LBUTTON
/* 0x002 */ {kKeyNone}, // VK_RBUTTON
/* 0x003 */ {kKeyNone}, // VK_CANCEL
/* 0x004 */ {kKeyNone}, // VK_MBUTTON
/* 0x005 */ {kKeyNone}, // VK_XBUTTON1
/* 0x006 */ {kKeyNone}, // VK_XBUTTON2
/* 0x007 */ {kKeyNone}, // undefined
/* 0x008 */ {kKeyBackSpace}, // VK_BACK
/* 0x009 */ {kKeyTab}, // VK_TAB
/* 0x00a */ {kKeyNone}, // undefined
/* 0x00b */ {kKeyNone}, // undefined
/* 0x00c */ {kKeyClear}, // VK_CLEAR
/* 0x00d */ {kKeyReturn}, // VK_RETURN
/* 0x00e */ {kKeyNone}, // undefined
/* 0x00f */ {kKeyNone}, // undefined
/* 0x010 */ {kKeyShift_L}, // VK_SHIFT
/* 0x011 */ {kKeyControl_L}, // VK_CONTROL
/* 0x012 */ {kKeyAlt_L}, // VK_MENU
/* 0x013 */ {kKeyPause}, // VK_PAUSE
/* 0x014 */ {kKeyCapsLock}, // VK_CAPITAL
/* 0x015 */ {kKeyKana}, // VK_HANGUL, VK_KANA
/* 0x016 */ {kKeyNone}, // undefined
/* 0x017 */ {kKeyNone}, // VK_JUNJA
/* 0x018 */ {kKeyNone}, // VK_FINAL
/* 0x019 */ {kKeyKanzi}, // VK_HANJA, VK_KANJI
/* 0x01a */ {kKeyNone}, // undefined
/* 0x01b */ {kKeyEscape}, // VK_ESCAPE
/* 0x01c */ {kKeyHenkan}, // VK_CONVERT
/* 0x01d */ {kKeyNone}, // VK_NONCONVERT
/* 0x01e */ {kKeyNone}, // VK_ACCEPT
/* 0x01f */ {kKeyNone}, // VK_MODECHANGE
/* 0x020 */ {kKeyNone}, // VK_SPACE
/* 0x021 */ {kKeyKP_PageUp}, // VK_PRIOR
/* 0x022 */ {kKeyKP_PageDown}, // VK_NEXT
/* 0x023 */ {kKeyKP_End}, // VK_END
/* 0x024 */ {kKeyKP_Home}, // VK_HOME
/* 0x025 */ {kKeyKP_Left}, // VK_LEFT
/* 0x026 */ {kKeyKP_Up}, // VK_UP
/* 0x027 */ {kKeyKP_Right}, // VK_RIGHT
/* 0x028 */ {kKeyKP_Down}, // VK_DOWN
/* 0x029 */ {kKeySelect}, // VK_SELECT
/* 0x02a */ {kKeyNone}, // VK_PRINT
/* 0x02b */ {kKeyExecute}, // VK_EXECUTE
/* 0x02c */ {kKeyPrint}, // VK_SNAPSHOT
/* 0x02d */ {kKeyKP_Insert}, // VK_INSERT
/* 0x02e */ {kKeyKP_Delete}, // VK_DELETE
/* 0x02f */ {kKeyHelp}, // VK_HELP
/* 0x030 */ {kKeyNone}, // VK_0
/* 0x031 */ {kKeyNone}, // VK_1
/* 0x032 */ {kKeyNone}, // VK_2
/* 0x033 */ {kKeyNone}, // VK_3
/* 0x034 */ {kKeyNone}, // VK_4
/* 0x035 */ {kKeyNone}, // VK_5
/* 0x036 */ {kKeyNone}, // VK_6
/* 0x037 */ {kKeyNone}, // VK_7
/* 0x038 */ {kKeyNone}, // VK_8
/* 0x039 */ {kKeyNone}, // VK_9
/* 0x03a */ {kKeyNone}, // undefined
/* 0x03b */ {kKeyNone}, // undefined
/* 0x03c */ {kKeyNone}, // undefined
/* 0x03d */ {kKeyNone}, // undefined
/* 0x03e */ {kKeyNone}, // undefined
/* 0x03f */ {kKeyNone}, // undefined
/* 0x040 */ {kKeyNone}, // undefined
/* 0x041 */ {kKeyNone}, // VK_A
/* 0x042 */ {kKeyNone}, // VK_B
/* 0x043 */ {kKeyNone}, // VK_C
/* 0x044 */ {kKeyNone}, // VK_D
/* 0x045 */ {kKeyNone}, // VK_E
/* 0x046 */ {kKeyNone}, // VK_F
/* 0x047 */ {kKeyNone}, // VK_G
/* 0x048 */ {kKeyNone}, // VK_H
/* 0x049 */ {kKeyNone}, // VK_I
/* 0x04a */ {kKeyNone}, // VK_J
/* 0x04b */ {kKeyNone}, // VK_K
/* 0x04c */ {kKeyNone}, // VK_L
/* 0x04d */ {kKeyNone}, // VK_M
/* 0x04e */ {kKeyNone}, // VK_N
/* 0x04f */ {kKeyNone}, // VK_O
/* 0x050 */ {kKeyNone}, // VK_P
/* 0x051 */ {kKeyNone}, // VK_Q
/* 0x052 */ {kKeyNone}, // VK_R
/* 0x053 */ {kKeyNone}, // VK_S
/* 0x054 */ {kKeyNone}, // VK_T
/* 0x055 */ {kKeyNone}, // VK_U
/* 0x056 */ {kKeyNone}, // VK_V
/* 0x057 */ {kKeyNone}, // VK_W
/* 0x058 */ {kKeyNone}, // VK_X
/* 0x059 */ {kKeyNone}, // VK_Y
/* 0x05a */ {kKeyNone}, // VK_Z
/* 0x05b */ {kKeySuper_L}, // VK_LWIN
/* 0x05c */ {kKeySuper_R}, // VK_RWIN
/* 0x05d */ {kKeyMenu}, // VK_APPS
/* 0x05e */ {kKeyNone}, // undefined
/* 0x05f */ {kKeySleep}, // VK_SLEEP
/* 0x060 */ {kKeyKP_0}, // VK_NUMPAD0
/* 0x061 */ {kKeyKP_1}, // VK_NUMPAD1
/* 0x062 */ {kKeyKP_2}, // VK_NUMPAD2
/* 0x063 */ {kKeyKP_3}, // VK_NUMPAD3
/* 0x064 */ {kKeyKP_4}, // VK_NUMPAD4
/* 0x065 */ {kKeyKP_5}, // VK_NUMPAD5
/* 0x066 */ {kKeyKP_6}, // VK_NUMPAD6
/* 0x067 */ {kKeyKP_7}, // VK_NUMPAD7
/* 0x068 */ {kKeyKP_8}, // VK_NUMPAD8
/* 0x069 */ {kKeyKP_9}, // VK_NUMPAD9
/* 0x06a */ {kKeyKP_Multiply}, // VK_MULTIPLY
/* 0x06b */ {kKeyKP_Add}, // VK_ADD
/* 0x06c */ {kKeyKP_Separator}, // VK_SEPARATOR
/* 0x06d */ {kKeyKP_Subtract}, // VK_SUBTRACT
/* 0x06e */ {kKeyKP_Decimal}, // VK_DECIMAL
/* 0x06f */ {kKeyNone}, // VK_DIVIDE
/* 0x070 */ {kKeyF1}, // VK_F1
/* 0x071 */ {kKeyF2}, // VK_F2
/* 0x072 */ {kKeyF3}, // VK_F3
/* 0x073 */ {kKeyF4}, // VK_F4
/* 0x074 */ {kKeyF5}, // VK_F5
/* 0x075 */ {kKeyF6}, // VK_F6
/* 0x076 */ {kKeyF7}, // VK_F7
/* 0x077 */ {kKeyF8}, // VK_F8
/* 0x078 */ {kKeyF9}, // VK_F9
/* 0x079 */ {kKeyF10}, // VK_F10
/* 0x07a */ {kKeyF11}, // VK_F11
/* 0x07b */ {kKeyF12}, // VK_F12
/* 0x07c */ {kKeyF13}, // VK_F13
/* 0x07d */ {kKeyF14}, // VK_F14
/* 0x07e */ {kKeyF15}, // VK_F15
/* 0x07f */ {kKeyF16}, // VK_F16
/* 0x080 */ {kKeyF17}, // VK_F17
/* 0x081 */ {kKeyF18}, // VK_F18
/* 0x082 */ {kKeyF19}, // VK_F19
/* 0x083 */ {kKeyF20}, // VK_F20
/* 0x084 */ {kKeyF21}, // VK_F21
/* 0x085 */ {kKeyF22}, // VK_F22
/* 0x086 */ {kKeyF23}, // VK_F23
/* 0x087 */ {kKeyF24}, // VK_F24
/* 0x088 */ {kKeyNone}, // unassigned
/* 0x089 */ {kKeyNone}, // unassigned
/* 0x08a */ {kKeyNone}, // unassigned
/* 0x08b */ {kKeyNone}, // unassigned
/* 0x08c */ {kKeyNone}, // unassigned
/* 0x08d */ {kKeyNone}, // unassigned
/* 0x08e */ {kKeyNone}, // unassigned
/* 0x08f */ {kKeyNone}, // unassigned
/* 0x090 */ {kKeyNumLock}, // VK_NUMLOCK
/* 0x091 */ {kKeyScrollLock}, // VK_SCROLL
/* 0x092 */ {kKeyNone}, // unassigned
/* 0x093 */ {kKeyNone}, // unassigned
/* 0x094 */ {kKeyNone}, // unassigned
/* 0x095 */ {kKeyNone}, // unassigned
/* 0x096 */ {kKeyNone}, // unassigned
/* 0x097 */ {kKeyNone}, // unassigned
/* 0x098 */ {kKeyNone}, // unassigned
/* 0x099 */ {kKeyNone}, // unassigned
/* 0x09a */ {kKeyNone}, // unassigned
/* 0x09b */ {kKeyNone}, // unassigned
/* 0x09c */ {kKeyNone}, // unassigned
/* 0x09d */ {kKeyNone}, // unassigned
/* 0x09e */ {kKeyNone}, // unassigned
/* 0x09f */ {kKeyNone}, // unassigned
/* 0x0a0 */ {kKeyShift_L}, // VK_LSHIFT
/* 0x0a1 */ {kKeyShift_R}, // VK_RSHIFT
/* 0x0a2 */ {kKeyControl_L}, // VK_LCONTROL
/* 0x0a3 */ {kKeyControl_R}, // VK_RCONTROL
/* 0x0a4 */ {kKeyAlt_L}, // VK_LMENU
/* 0x0a5 */ {kKeyAlt_R}, // VK_RMENU
/* 0x0a6 */ {kKeyNone}, // VK_BROWSER_BACK
/* 0x0a7 */ {kKeyNone}, // VK_BROWSER_FORWARD
/* 0x0a8 */ {kKeyNone}, // VK_BROWSER_REFRESH
/* 0x0a9 */ {kKeyNone}, // VK_BROWSER_STOP
/* 0x0aa */ {kKeyNone}, // VK_BROWSER_SEARCH
/* 0x0ab */ {kKeyNone}, // VK_BROWSER_FAVORITES
/* 0x0ac */ {kKeyNone}, // VK_BROWSER_HOME
/* 0x0ad */ {kKeyNone}, // VK_VOLUME_MUTE
/* 0x0ae */ {kKeyNone}, // VK_VOLUME_DOWN
/* 0x0af */ {kKeyNone}, // VK_VOLUME_UP
/* 0x0b0 */ {kKeyNone}, // VK_MEDIA_NEXT_TRACK
/* 0x0b1 */ {kKeyNone}, // VK_MEDIA_PREV_TRACK
/* 0x0b2 */ {kKeyNone}, // VK_MEDIA_STOP
/* 0x0b3 */ {kKeyNone}, // VK_MEDIA_PLAY_PAUSE
/* 0x0b4 */ {kKeyNone}, // VK_LAUNCH_MAIL
/* 0x0b5 */ {kKeyNone}, // VK_LAUNCH_MEDIA_SELECT
/* 0x0b6 */ {kKeyNone}, // VK_LAUNCH_APP1
/* 0x0b7 */ {kKeyNone}, // VK_LAUNCH_APP2
/* 0x0b8 */ {kKeyNone}, // unassigned
/* 0x0b9 */ {kKeyNone}, // unassigned
/* 0x0ba */ {kKeyNone}, // OEM specific
/* 0x0bb */ {kKeyNone}, // OEM specific
/* 0x0bc */ {kKeyNone}, // OEM specific
/* 0x0bd */ {kKeyNone}, // OEM specific
/* 0x0be */ {kKeyNone}, // OEM specific
/* 0x0bf */ {kKeyNone}, // OEM specific
/* 0x0c0 */ {kKeyNone}, // OEM specific
/* 0x0c1 */ {kKeyNone}, // unassigned
/* 0x0c2 */ {kKeyNone}, // unassigned
/* 0x0c3 */ {kKeyNone}, // unassigned
/* 0x0c4 */ {kKeyNone}, // unassigned
/* 0x0c5 */ {kKeyNone}, // unassigned
/* 0x0c6 */ {kKeyNone}, // unassigned
/* 0x0c7 */ {kKeyNone}, // unassigned
/* 0x0c8 */ {kKeyNone}, // unassigned
/* 0x0c9 */ {kKeyNone}, // unassigned
/* 0x0ca */ {kKeyNone}, // unassigned
/* 0x0cb */ {kKeyNone}, // unassigned
/* 0x0cc */ {kKeyNone}, // unassigned
/* 0x0cd */ {kKeyNone}, // unassigned
/* 0x0ce */ {kKeyNone}, // unassigned
/* 0x0cf */ {kKeyNone}, // unassigned
/* 0x0d0 */ {kKeyNone}, // unassigned
/* 0x0d1 */ {kKeyNone}, // unassigned
/* 0x0d2 */ {kKeyNone}, // unassigned
/* 0x0d3 */ {kKeyNone}, // unassigned
/* 0x0d4 */ {kKeyNone}, // unassigned
/* 0x0d5 */ {kKeyNone}, // unassigned
/* 0x0d6 */ {kKeyNone}, // unassigned
/* 0x0d7 */ {kKeyNone}, // unassigned
/* 0x0d8 */ {kKeyNone}, // unassigned
/* 0x0d9 */ {kKeyNone}, // unassigned
/* 0x0da */ {kKeyNone}, // unassigned
/* 0x0db */ {kKeyNone}, // OEM specific
/* 0x0dc */ {kKeyNone}, // OEM specific
/* 0x0dd */ {kKeyNone}, // OEM specific
/* 0x0de */ {kKeyNone}, // OEM specific
/* 0x0df */ {kKeyNone}, // OEM specific
/* 0x0e0 */ {kKeyNone}, // OEM specific
/* 0x0e1 */ {kKeyNone}, // OEM specific
/* 0x0e2 */ {kKeyNone}, // OEM specific
/* 0x0e3 */ {kKeyNone}, // OEM specific
/* 0x0e4 */ {kKeyNone}, // OEM specific
/* 0x0e5 */ {kKeyNone}, // unassigned
/* 0x0e6 */ {kKeyNone}, // OEM specific
/* 0x0e7 */ {kKeyNone}, // unassigned
/* 0x0e8 */ {kKeyNone}, // unassigned
/* 0x0e9 */ {kKeyNone}, // OEM specific
/* 0x0ea */ {kKeyNone}, // OEM specific
/* 0x0eb */ {kKeyNone}, // OEM specific
/* 0x0ec */ {kKeyNone}, // OEM specific
/* 0x0ed */ {kKeyNone}, // OEM specific
/* 0x0ee */ {kKeyNone}, // OEM specific
/* 0x0ef */ {kKeyNone}, // OEM specific
/* 0x0f0 */ {kKeyNone}, // OEM specific
/* 0x0f1 */ {kKeyNone}, // OEM specific
/* 0x0f2 */ {kKeyHiraganaKatakana}, // VK_OEM_COPY
/* 0x0f3 */ {kKeyZenkaku}, // VK_OEM_AUTO
/* 0x0f4 */ {kKeyZenkaku}, // VK_OEM_ENLW
/* 0x0f5 */ {kKeyNone}, // OEM specific
/* 0x0f6 */ {kKeyNone}, // VK_ATTN
/* 0x0f7 */ {kKeyNone}, // VK_CRSEL
/* 0x0f8 */ {kKeyNone}, // VK_EXSEL
/* 0x0f9 */ {kKeyNone}, // VK_EREOF
/* 0x0fa */ {kKeyNone}, // VK_PLAY
/* 0x0fb */ {kKeyNone}, // VK_ZOOM
/* 0x0fc */ {kKeyNone}, // reserved
/* 0x0fd */ {kKeyNone}, // VK_PA1
/* 0x0fe */ {kKeyNone}, // VK_OEM_CLEAR
/* 0x0ff */ {kKeyNone}, // reserved
/* 0x100 */ {kKeyNone}, // reserved
/* 0x101 */ {kKeyNone}, // VK_LBUTTON
/* 0x102 */ {kKeyNone}, // VK_RBUTTON
/* 0x103 */ {kKeyBreak}, // VK_CANCEL
/* 0x104 */ {kKeyNone}, // VK_MBUTTON
/* 0x105 */ {kKeyNone}, // VK_XBUTTON1
/* 0x106 */ {kKeyNone}, // VK_XBUTTON2
/* 0x107 */ {kKeyNone}, // undefined
/* 0x108 */ {kKeyNone}, // VK_BACK
/* 0x109 */ {kKeyNone}, // VK_TAB
/* 0x10a */ {kKeyNone}, // undefined
/* 0x10b */ {kKeyNone}, // undefined
/* 0x10c */ {kKeyClear}, // VK_CLEAR
/* 0x10d */ {kKeyKP_Enter}, // VK_RETURN
/* 0x10e */ {kKeyNone}, // undefined
/* 0x10f */ {kKeyNone}, // undefined
/* 0x110 */ {kKeyShift_R}, // VK_SHIFT
/* 0x111 */ {kKeyControl_R}, // VK_CONTROL
/* 0x112 */ {kKeyAlt_R}, // VK_MENU
/* 0x113 */ {kKeyNone}, // VK_PAUSE
/* 0x114 */ {kKeyNone}, // VK_CAPITAL
/* 0x115 */ {kKeyHangul}, // VK_HANGUL
/* 0x116 */ {kKeyNone}, // undefined
/* 0x117 */ {kKeyNone}, // VK_JUNJA
/* 0x118 */ {kKeyNone}, // VK_FINAL
/* 0x119 */ {kKeyHanja}, // VK_HANJA
/* 0x11a */ {kKeyNone}, // undefined
/* 0x11b */ {kKeyNone}, // VK_ESCAPE
/* 0x11c */ {kKeyNone}, // VK_CONVERT
/* 0x11d */ {kKeyNone}, // VK_NONCONVERT
/* 0x11e */ {kKeyNone}, // VK_ACCEPT
/* 0x11f */ {kKeyNone}, // VK_MODECHANGE
/* 0x120 */ {kKeyNone}, // VK_SPACE
/* 0x121 */ {kKeyPageUp}, // VK_PRIOR
/* 0x122 */ {kKeyPageDown}, // VK_NEXT
/* 0x123 */ {kKeyEnd}, // VK_END
/* 0x124 */ {kKeyHome}, // VK_HOME
/* 0x125 */ {kKeyLeft}, // VK_LEFT
/* 0x126 */ {kKeyUp}, // VK_UP
/* 0x127 */ {kKeyRight}, // VK_RIGHT
/* 0x128 */ {kKeyDown}, // VK_DOWN
/* 0x129 */ {kKeySelect}, // VK_SELECT
/* 0x12a */ {kKeyNone}, // VK_PRINT
/* 0x12b */ {kKeyExecute}, // VK_EXECUTE
/* 0x12c */ {kKeyPrint}, // VK_SNAPSHOT
/* 0x12d */ {kKeyInsert}, // VK_INSERT
/* 0x12e */ {kKeyDelete}, // VK_DELETE
/* 0x12f */ {kKeyHelp}, // VK_HELP
/* 0x130 */ {kKeyNone}, // VK_0
/* 0x131 */ {kKeyNone}, // VK_1
/* 0x132 */ {kKeyNone}, // VK_2
/* 0x133 */ {kKeyNone}, // VK_3
/* 0x134 */ {kKeyNone}, // VK_4
/* 0x135 */ {kKeyNone}, // VK_5
/* 0x136 */ {kKeyNone}, // VK_6
/* 0x137 */ {kKeyNone}, // VK_7
/* 0x138 */ {kKeyNone}, // VK_8
/* 0x139 */ {kKeyNone}, // VK_9
/* 0x13a */ {kKeyNone}, // undefined
/* 0x13b */ {kKeyNone}, // undefined
/* 0x13c */ {kKeyNone}, // undefined
/* 0x13d */ {kKeyNone}, // undefined
/* 0x13e */ {kKeyNone}, // undefined
/* 0x13f */ {kKeyNone}, // undefined
/* 0x140 */ {kKeyNone}, // undefined
/* 0x141 */ {kKeyNone}, // VK_A
/* 0x142 */ {kKeyNone}, // VK_B
/* 0x143 */ {kKeyNone}, // VK_C
/* 0x144 */ {kKeyNone}, // VK_D
/* 0x145 */ {kKeyNone}, // VK_E
/* 0x146 */ {kKeyNone}, // VK_F
/* 0x147 */ {kKeyNone}, // VK_G
/* 0x148 */ {kKeyNone}, // VK_H
/* 0x149 */ {kKeyNone}, // VK_I
/* 0x14a */ {kKeyNone}, // VK_J
/* 0x14b */ {kKeyNone}, // VK_K
/* 0x14c */ {kKeyNone}, // VK_L
/* 0x14d */ {kKeyNone}, // VK_M
/* 0x14e */ {kKeyNone}, // VK_N
/* 0x14f */ {kKeyNone}, // VK_O
/* 0x150 */ {kKeyNone}, // VK_P
/* 0x151 */ {kKeyNone}, // VK_Q
/* 0x152 */ {kKeyNone}, // VK_R
/* 0x153 */ {kKeyNone}, // VK_S
/* 0x154 */ {kKeyNone}, // VK_T
/* 0x155 */ {kKeyNone}, // VK_U
/* 0x156 */ {kKeyNone}, // VK_V
/* 0x157 */ {kKeyNone}, // VK_W
/* 0x158 */ {kKeyNone}, // VK_X
/* 0x159 */ {kKeyNone}, // VK_Y
/* 0x15a */ {kKeyNone}, // VK_Z
/* 0x15b */ {kKeySuper_L}, // VK_LWIN
/* 0x15c */ {kKeySuper_R}, // VK_RWIN
/* 0x15d */ {kKeyMenu}, // VK_APPS
/* 0x15e */ {kKeyNone}, // undefined
/* 0x15f */ {kKeyNone}, // VK_SLEEP
/* 0x160 */ {kKeyNone}, // VK_NUMPAD0
/* 0x161 */ {kKeyNone}, // VK_NUMPAD1
/* 0x162 */ {kKeyNone}, // VK_NUMPAD2
/* 0x163 */ {kKeyNone}, // VK_NUMPAD3
/* 0x164 */ {kKeyNone}, // VK_NUMPAD4
/* 0x165 */ {kKeyNone}, // VK_NUMPAD5
/* 0x166 */ {kKeyNone}, // VK_NUMPAD6
/* 0x167 */ {kKeyNone}, // VK_NUMPAD7
/* 0x168 */ {kKeyNone}, // VK_NUMPAD8
/* 0x169 */ {kKeyNone}, // VK_NUMPAD9
/* 0x16a */ {kKeyNone}, // VK_MULTIPLY
/* 0x16b */ {kKeyNone}, // VK_ADD
/* 0x16c */ {kKeyKP_Separator}, // VK_SEPARATOR
/* 0x16d */ {kKeyNone}, // VK_SUBTRACT
/* 0x16e */ {kKeyNone}, // VK_DECIMAL
/* 0x16f */ {kKeyKP_Divide}, // VK_DIVIDE
/* 0x170 */ {kKeyNone}, // VK_F1
/* 0x171 */ {kKeyNone}, // VK_F2
/* 0x172 */ {kKeyNone}, // VK_F3
/* 0x173 */ {kKeyNone}, // VK_F4
/* 0x174 */ {kKeyNone}, // VK_F5
/* 0x175 */ {kKeyNone}, // VK_F6
/* 0x176 */ {kKeyNone}, // VK_F7
/* 0x177 */ {kKeyNone}, // VK_F8
/* 0x178 */ {kKeyNone}, // VK_F9
/* 0x179 */ {kKeyNone}, // VK_F10
/* 0x17a */ {kKeyNone}, // VK_F11
/* 0x17b */ {kKeyNone}, // VK_F12
/* 0x17c */ {kKeyF13}, // VK_F13
/* 0x17d */ {kKeyF14}, // VK_F14
/* 0x17e */ {kKeyF15}, // VK_F15
/* 0x17f */ {kKeyF16}, // VK_F16
/* 0x180 */ {kKeyF17}, // VK_F17
/* 0x181 */ {kKeyF18}, // VK_F18
/* 0x182 */ {kKeyF19}, // VK_F19
/* 0x183 */ {kKeyF20}, // VK_F20
/* 0x184 */ {kKeyF21}, // VK_F21
/* 0x185 */ {kKeyF22}, // VK_F22
/* 0x186 */ {kKeyF23}, // VK_F23
/* 0x187 */ {kKeyF24}, // VK_F24
/* 0x188 */ {kKeyNone}, // unassigned
/* 0x189 */ {kKeyNone}, // unassigned
/* 0x18a */ {kKeyNone}, // unassigned
/* 0x18b */ {kKeyNone}, // unassigned
/* 0x18c */ {kKeyNone}, // unassigned
/* 0x18d */ {kKeyNone}, // unassigned
/* 0x18e */ {kKeyNone}, // unassigned
/* 0x18f */ {kKeyNone}, // unassigned
/* 0x190 */ {kKeyNumLock}, // VK_NUMLOCK
/* 0x191 */ {kKeyNone}, // VK_SCROLL
/* 0x192 */ {kKeyNone}, // unassigned
/* 0x193 */ {kKeyNone}, // unassigned
/* 0x194 */ {kKeyNone}, // unassigned
/* 0x195 */ {kKeyNone}, // unassigned
/* 0x196 */ {kKeyNone}, // unassigned
/* 0x197 */ {kKeyNone}, // unassigned
/* 0x198 */ {kKeyNone}, // unassigned
/* 0x199 */ {kKeyNone}, // unassigned
/* 0x19a */ {kKeyNone}, // unassigned
/* 0x19b */ {kKeyNone}, // unassigned
/* 0x19c */ {kKeyNone}, // unassigned
/* 0x19d */ {kKeyNone}, // unassigned
/* 0x19e */ {kKeyNone}, // unassigned
/* 0x19f */ {kKeyNone}, // unassigned
/* 0x1a0 */ {kKeyShift_L}, // VK_LSHIFT
/* 0x1a1 */ {kKeyShift_R}, // VK_RSHIFT
/* 0x1a2 */ {kKeyControl_L}, // VK_LCONTROL
/* 0x1a3 */ {kKeyControl_R}, // VK_RCONTROL
/* 0x1a4 */ {kKeyAlt_L}, // VK_LMENU
/* 0x1a5 */ {kKeyAlt_R}, // VK_RMENU
/* 0x1a6 */ {kKeyWWWBack}, // VK_BROWSER_BACK
/* 0x1a7 */ {kKeyWWWForward}, // VK_BROWSER_FORWARD
/* 0x1a8 */ {kKeyWWWRefresh}, // VK_BROWSER_REFRESH
/* 0x1a9 */ {kKeyWWWStop}, // VK_BROWSER_STOP
/* 0x1aa */ {kKeyWWWSearch}, // VK_BROWSER_SEARCH
/* 0x1ab */ {kKeyWWWFavorites}, // VK_BROWSER_FAVORITES
/* 0x1ac */ {kKeyWWWHome}, // VK_BROWSER_HOME
/* 0x1ad */ {kKeyAudioMute}, // VK_VOLUME_MUTE
/* 0x1ae */ {kKeyAudioDown}, // VK_VOLUME_DOWN
/* 0x1af */ {kKeyAudioUp}, // VK_VOLUME_UP
/* 0x1b0 */ {kKeyAudioNext}, // VK_MEDIA_NEXT_TRACK
/* 0x1b1 */ {kKeyAudioPrev}, // VK_MEDIA_PREV_TRACK
/* 0x1b2 */ {kKeyAudioStop}, // VK_MEDIA_STOP
/* 0x1b3 */ {kKeyAudioPlay}, // VK_MEDIA_PLAY_PAUSE
/* 0x1b4 */ {kKeyAppMail}, // VK_LAUNCH_MAIL
/* 0x1b5 */ {kKeyAppMedia}, // VK_LAUNCH_MEDIA_SELECT
/* 0x1b6 */ {kKeyAppUser1}, // VK_LAUNCH_APP1
/* 0x1b7 */ {kKeyAppUser2}, // VK_LAUNCH_APP2
/* 0x1b8 */ {kKeyNone}, // unassigned
/* 0x1b9 */ {kKeyNone}, // unassigned
/* 0x1ba */ {kKeyNone}, // OEM specific
/* 0x1bb */ {kKeyNone}, // OEM specific
/* 0x1bc */ {kKeyNone}, // OEM specific
/* 0x1bd */ {kKeyNone}, // OEM specific
/* 0x1be */ {kKeyNone}, // OEM specific
/* 0x1bf */ {kKeyNone}, // OEM specific
/* 0x1c0 */ {kKeyNone}, // OEM specific
/* 0x1c1 */ {kKeyNone}, // unassigned
/* 0x1c2 */ {kKeyNone}, // unassigned
/* 0x1c3 */ {kKeyNone}, // unassigned
/* 0x1c4 */ {kKeyNone}, // unassigned
/* 0x1c5 */ {kKeyNone}, // unassigned
/* 0x1c6 */ {kKeyNone}, // unassigned
/* 0x1c7 */ {kKeyNone}, // unassigned
/* 0x1c8 */ {kKeyNone}, // unassigned
/* 0x1c9 */ {kKeyNone}, // unassigned
/* 0x1ca */ {kKeyNone}, // unassigned
/* 0x1cb */ {kKeyNone}, // unassigned
/* 0x1cc */ {kKeyNone}, // unassigned
/* 0x1cd */ {kKeyNone}, // unassigned
/* 0x1ce */ {kKeyNone}, // unassigned
/* 0x1cf */ {kKeyNone}, // unassigned
/* 0x1d0 */ {kKeyNone}, // unassigned
/* 0x1d1 */ {kKeyNone}, // unassigned
/* 0x1d2 */ {kKeyNone}, // unassigned
/* 0x1d3 */ {kKeyNone}, // unassigned
/* 0x1d4 */ {kKeyNone}, // unassigned
/* 0x1d5 */ {kKeyNone}, // unassigned
/* 0x1d6 */ {kKeyNone}, // unassigned
/* 0x1d7 */ {kKeyNone}, // unassigned
/* 0x1d8 */ {kKeyNone}, // unassigned
/* 0x1d9 */ {kKeyNone}, // unassigned
/* 0x1da */ {kKeyNone}, // unassigned
/* 0x1db */ {kKeyNone}, // OEM specific
/* 0x1dc */ {kKeyNone}, // OEM specific
/* 0x1dd */ {kKeyNone}, // OEM specific
/* 0x1de */ {kKeyNone}, // OEM specific
/* 0x1df */ {kKeyNone}, // OEM specific
/* 0x1e0 */ {kKeyNone}, // OEM specific
/* 0x1e1 */ {kKeyNone}, // OEM specific
/* 0x1e2 */ {kKeyNone}, // OEM specific
/* 0x1e3 */ {kKeyNone}, // OEM specific
/* 0x1e4 */ {kKeyNone}, // OEM specific
/* 0x1e5 */ {kKeyNone}, // unassigned
/* 0x1e6 */ {kKeyNone}, // OEM specific
/* 0x1e7 */ {kKeyNone}, // unassigned
/* 0x1e8 */ {kKeyNone}, // unassigned
/* 0x1e9 */ {kKeyNone}, // OEM specific
/* 0x1ea */ {kKeyNone}, // OEM specific
/* 0x1eb */ {kKeyNone}, // OEM specific
/* 0x1ec */ {kKeyNone}, // OEM specific
/* 0x1ed */ {kKeyNone}, // OEM specific
/* 0x1ee */ {kKeyNone}, // OEM specific
/* 0x1ef */ {kKeyNone}, // OEM specific
/* 0x1f0 */ {kKeyNone}, // OEM specific
/* 0x1f1 */ {kKeyNone}, // OEM specific
/* 0x1f2 */ {kKeyNone}, // VK_OEM_COPY
/* 0x1f3 */ {kKeyNone}, // VK_OEM_AUTO
/* 0x1f4 */ {kKeyNone}, // VK_OEM_ENLW
/* 0x1f5 */ {kKeyNone}, // OEM specific
/* 0x1f6 */ {kKeyNone}, // VK_ATTN
/* 0x1f7 */ {kKeyNone}, // VK_CRSEL
/* 0x1f8 */ {kKeyNone}, // VK_EXSEL
/* 0x1f9 */ {kKeyNone}, // VK_EREOF
/* 0x1fa */ {kKeyNone}, // VK_PLAY
/* 0x1fb */ {kKeyNone}, // VK_ZOOM
/* 0x1fc */ {kKeyNone}, // reserved
/* 0x1fd */ {kKeyNone}, // VK_PA1
/* 0x1fe */ {kKeyNone}, // VK_OEM_CLEAR
/* 0x1ff */ {kKeyNone} // reserved
};
struct Win32Modifiers
{
public:
UINT m_vk;
KeyModifierMask m_mask;
};
static const Win32Modifiers s_modifiers[] = {{VK_SHIFT, KeyModifierShift}, {VK_LSHIFT, KeyModifierShift},
{VK_RSHIFT, KeyModifierShift}, {VK_CONTROL, KeyModifierControl},
{VK_LCONTROL, KeyModifierControl}, {VK_RCONTROL, KeyModifierControl},
{VK_MENU, KeyModifierAlt}, {VK_LMENU, KeyModifierAlt},
{VK_RMENU, KeyModifierAlt}, {VK_LWIN, KeyModifierSuper},
{VK_RWIN, KeyModifierSuper}};
MSWindowsKeyState::MSWindowsKeyState(
MSWindowsDesks *desks, void *eventTarget, IEventQueue *events, std::vector<std::string> layouts,
bool isLangSyncEnabled
)
: KeyState(events, std::move(layouts), isLangSyncEnabled),
m_eventTarget(eventTarget),
m_desks(desks),
m_keyLayout(GetKeyboardLayout(0)),
m_fixTimer(nullptr),
m_lastDown(0),
m_useSavedModifiers(false),
m_savedModifiers(0),
m_originalSavedModifiers(0),
m_events(events)
{
init();
}
MSWindowsKeyState::MSWindowsKeyState(
MSWindowsDesks *desks, void *eventTarget, IEventQueue *events, deskflow::KeyMap &keyMap,
std::vector<std::string> layouts, bool isLangSyncEnabled
)
: KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled),
m_eventTarget(eventTarget),
m_desks(desks),
m_keyLayout(GetKeyboardLayout(0)),
m_fixTimer(nullptr),
m_lastDown(0),
m_useSavedModifiers(false),
m_savedModifiers(0),
m_originalSavedModifiers(0),
m_events(events)
{
init();
}
MSWindowsKeyState::~MSWindowsKeyState()
{
disable();
}
void MSWindowsKeyState::init()
{
// look up symbol that's available on winNT family but not win95
HMODULE userModule = GetModuleHandle("user32.dll");
m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx");
}
void MSWindowsKeyState::disable()
{
if (m_fixTimer != nullptr) {
m_events->removeHandler(EventTypes::Timer, m_fixTimer);
m_events->deleteTimer(m_fixTimer);
m_fixTimer = nullptr;
}
m_lastDown = 0;
}
KeyButton MSWindowsKeyState::virtualKeyToButton(UINT virtualKey) const
{
return m_virtualKeyToButton[virtualKey & 0xffu];
}
void MSWindowsKeyState::setKeyLayout(HKL keyLayout)
{
m_keyLayout = keyLayout;
}
bool MSWindowsKeyState::testAutoRepeat(bool press, bool isRepeat, KeyButton button)
{
if (!isRepeat) {
isRepeat = (press && m_lastDown != 0 && button == m_lastDown);
}
if (press) {
m_lastDown = button;
} else {
m_lastDown = 0;
}
return isRepeat;
}
void MSWindowsKeyState::saveModifiers()
{
m_savedModifiers = getActiveModifiers();
m_originalSavedModifiers = m_savedModifiers;
}
void MSWindowsKeyState::useSavedModifiers(bool enable)
{
if (enable != m_useSavedModifiers) {
m_useSavedModifiers = enable;
if (!m_useSavedModifiers) {
// transfer any modifier state changes to KeyState's state
KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers;
getActiveModifiersRValue() = (getActiveModifiers() & ~mask) | (m_savedModifiers & mask);
}
}
}
KeyID MSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info, KeyModifierMask *maskOut) const
{
static const KeyModifierMask s_controlAlt = KeyModifierControl | KeyModifierAlt;
// extract character, virtual key, and if we didn't use AltGr
auto wc = static_cast<WCHAR>((charAndVirtKey & 0xffffu));
UINT vkCode = ((charAndVirtKey >> 16) & 0xffu);
bool noAltGr = ((charAndVirtKey & 0xff000000u) != 0);
// handle some keys via table lookup
KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu));
// check if not in table; map character to key id
if (id == kKeyNone && wc != 0) {
// UTF16
id = static_cast<KeyID>(wc) & 0xffffu;
}
// set modifier mask
if (maskOut != nullptr) {
KeyModifierMask active = getActiveModifiers();
if (!noAltGr && (active & s_controlAlt) == s_controlAlt) {
// if !noAltGr then we're only interested in matching the
// key, not the AltGr. AltGr is down (i.e. control and alt
// are down) but we don't want the client to have to match
// that so we clear it.
active &= ~s_controlAlt;
}
if (id == kKeyHangul) {
// If shift-space is used to change input mode, clear shift modifier.
active &= ~KeyModifierShift;
}
*maskOut = active;
}
return id;
}
bool MSWindowsKeyState::didGroupsChange() const
{
GroupList groups;
return (getGroups(groups) && groups != m_groups);
}
UINT MSWindowsKeyState::mapKeyToVirtualKey(KeyID key) const
{
if (key == kKeyNone) {
return 0;
}
KeyToVKMap::const_iterator i = m_keyToVKMap.find(key);
if (i == m_keyToVKMap.end()) {
return 0;
} else {
return i->second;
}
}
void MSWindowsKeyState::onKey(KeyButton button, bool down, KeyModifierMask newState)
{
KeyState::onKey(button, down, newState);
}
void MSWindowsKeyState::sendKeyEvent(
void *target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, int32_t count, KeyButton button
)
{
if (press || isAutoRepeat) {
// send key
if (press && !isAutoRepeat) {
KeyState::sendKeyEvent(target, true, false, key, mask, 1, button);
if (count > 0) {
--count;
}
}
if (count >= 1) {
KeyState::sendKeyEvent(target, true, true, key, mask, count, button);
}
} else {
// do key up
KeyState::sendKeyEvent(target, false, false, key, mask, 1, button);
}
}
void MSWindowsKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, const std::string &lang)
{
KeyState::fakeKeyDown(id, mask, button, lang);
}
bool MSWindowsKeyState::fakeKeyRepeat(
KeyID id, KeyModifierMask mask, int32_t count, KeyButton button, const std::string &lang
)
{
return KeyState::fakeKeyRepeat(id, mask, count, button, lang);
}
// We must use SendSAS (Secure Attention Sequence) to simulate Ctrl+Alt+Del (since Windows Vista).
//
// According to the MS docs:
// > To successfully call the SendSAS function, an application must either be running as a
// > service or have the uiAccess attribute of the requestedExecutionLevel element set to "true"
// > in its application manifest.
//
// Since the daemon is running as a service, we can use it to send the event.
// We do this by calling `SetEvent` on the `SendSAS` event (created by the daemon).
//
// History: It used to be possible to use `PostMessage` to send `MOD_CONTROL | MOD_ALT, VK_DELETE`
// as a backup but this ability was removed by Microsoft for security in favor of requiring the
// `SendSAS` event to be used, which makes DoS and social engineering attacks more difficult.
bool MSWindowsKeyState::fakeCtrlAltDel()
{
// The daemon creates this event with default permissions, which means this process must be
// elevated to be able to open it. If not elevated, an access denied error will be returned.
MSWindowsHandle sendSasEvent(OpenEvent(EVENT_MODIFY_STATE, FALSE, kSendSasEventName));
if (!sendSasEvent.get()) {
LOG_ERR(
"couldn't open SAS event, unable to simulate ctrl+alt+del, error: %s",
windowsErrorToString(GetLastError()).c_str()
);
return false;
}
// Note: We don't directly call SendSAS, but rather we tell the daemon to do it by setting the event.
LOG_DEBUG("setting SAS event to simulate ctrl+alt+del");
if (!SetEvent(sendSasEvent.get())) {
LOG_ERR(
"failed to set SAS event, unable to simulate ctrl+alt+del, error: %s",
windowsErrorToString(GetLastError()).c_str()
);
return false;
}
return true;
}
KeyModifierMask MSWindowsKeyState::pollActiveModifiers() const
{
KeyModifierMask state = 0;
// get non-toggle modifiers from our own shadow key state
for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) {
KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk);
if (button != 0 && isKeyDown(button)) {
state |= s_modifiers[i].m_mask;
}
}
// we can get toggle modifiers from the system
if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) {
state |= KeyModifierCapsLock;
}
if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) {
state |= KeyModifierNumLock;
}
if ((GetKeyState(VK_SCROLL) & 0x01) != 0) {
state |= KeyModifierScrollLock;
}
return state;
}
int32_t MSWindowsKeyState::pollActiveGroup() const
{
// determine the thread that'll receive this event
HWND targetWindow = GetForegroundWindow();
DWORD targetThread = GetWindowThreadProcessId(targetWindow, nullptr);
// get keyboard layout for the thread
HKL hkl = GetKeyboardLayout(targetThread);
if (!hkl) {
// GetKeyboardLayout failed. Maybe targetWindow is a console window.
// We're getting the keyboard layout of the desktop instead.
targetWindow = GetDesktopWindow();
targetThread = GetWindowThreadProcessId(targetWindow, nullptr);
hkl = GetKeyboardLayout(targetThread);
}
// get group
GroupMap::const_iterator i = m_groupMap.find(hkl);
if (i == m_groupMap.end()) {
LOG((CLOG_DEBUG1 "can't find keyboard layout %08x", hkl));
return 0;
}
return i->second;
}
void MSWindowsKeyState::pollPressedKeys(KeyButtonSet &pressedKeys) const
{
BYTE keyState[256];
if (!GetKeyboardState(keyState)) {
LOG((CLOG_WARN "keyboard state is unexpected"));
LOG((CLOG_DEBUG "function 'GetKeyboardState' returned false on 'pollPressedKeys'"));
return;
}
for (KeyButton i = 1; i < 256; ++i) {
if ((keyState[i] & 0x80) != 0) {
KeyButton keyButton = virtualKeyToButton(i);
if (keyButton != 0) {
pressedKeys.insert(keyButton);
}
}
}
}
void MSWindowsKeyState::getKeyMap(deskflow::KeyMap &keyMap)
{
// update keyboard groups
if (getGroups(m_groups)) {
m_groupMap.clear();
int32_t numGroups = (int32_t)m_groups.size();
for (int32_t g = 0; g < numGroups; ++g) {
m_groupMap[m_groups[g]] = g;
}
}
HKL activeLayout = GetKeyboardLayout(0);
// clear table
memset(m_virtualKeyToButton, 0, sizeof(m_virtualKeyToButton));
m_keyToVKMap.clear();
deskflow::KeyMap::KeyItem item;
int32_t numGroups = (int32_t)m_groups.size();
for (int32_t g = 0; g < numGroups; ++g) {
item.m_group = g;
ActivateKeyboardLayout(m_groups[g], 0);
// clear tables
memset(m_buttonToVK, 0, sizeof(m_buttonToVK));
memset(m_buttonToNumpadVK, 0, sizeof(m_buttonToNumpadVK));
// map buttons (scancodes) to virtual keys
for (KeyButton i = 1; i < 256; ++i) {
UINT vk = MapVirtualKey(i, 1);
if (vk == 0) {
// unmapped
continue;
}
// deal with certain virtual keys specially
switch (vk) {
case VK_SHIFT:
// this is important for sending the correct modifier to the
// client, a patch from bug #242 (right shift broken for ms
// remote desktop) removed this to just use left shift, which
// caused bug #2799 (right shift broken for osx).
// we must not repeat this same mistake and must fix platform
// specific bugs in code that only affects that platform.
if (MapVirtualKey(VK_RSHIFT, 0) == i) {
vk = VK_RSHIFT;
} else {
vk = VK_LSHIFT;
}
break;
case VK_CONTROL:
vk = VK_LCONTROL;
break;
case VK_MENU:
vk = VK_LMENU;
break;
case VK_NUMLOCK:
vk = VK_PAUSE;
break;
case VK_NUMPAD0:
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
case VK_DECIMAL:
// numpad keys are saved in their own table
m_buttonToNumpadVK[i] = vk;
continue;
case VK_LWIN:
case VK_RWIN:
break;
case VK_RETURN:
case VK_PRIOR:
case VK_NEXT:
case VK_END:
case VK_HOME:
case VK_LEFT:
case VK_UP:
case VK_RIGHT:
case VK_DOWN:
case VK_INSERT:
case VK_DELETE:
// also add extended key for these
m_buttonToVK[i | 0x100u] = vk;
break;
}
if (m_buttonToVK[i] == 0) {
m_buttonToVK[i] = vk;
}
}
// now map virtual keys to buttons. multiple virtual keys may map
// to a single button. if the virtual key matches the one in
// m_buttonToVK then we use the button as is. if not then it's
// either a numpad key and we use the button as is or it's an
// extended button.
for (UINT i = 1; i < 255; ++i) {
// skip virtual keys we don't want
switch (i) {
case VK_LBUTTON:
case VK_RBUTTON:
case VK_MBUTTON:
case VK_XBUTTON1:
case VK_XBUTTON2:
case VK_SHIFT:
case VK_CONTROL:
case VK_MENU:
continue;
}
// get the button
KeyButton button = static_cast<KeyButton>(MapVirtualKey(i, 0));
if (button == 0) {
continue;
}
// deal with certain virtual keys specially
switch (i) {
case VK_NUMPAD0:
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
case VK_DECIMAL:
m_buttonToNumpadVK[button] = i;
break;
default:
// add extended key if virtual keys don't match
if (m_buttonToVK[button] != i) {
m_buttonToVK[button | 0x100u] = i;
}
break;
}
}
// add the extended printscreen (alt+printscreen)
// or maybe it's the non-extended printscreen?
// scancodes and keyboard inputs are complicated
if (m_buttonToVK[0x54u] == 0) {
m_buttonToVK[0x54u] = VK_SNAPSHOT;
}
// set virtual key to button table
if (activeLayout == m_groups[g]) {
for (KeyButton i = 0; i < 512; ++i) {
if (m_buttonToVK[i] != 0) {
if (m_virtualKeyToButton[m_buttonToVK[i]] == 0) {
m_virtualKeyToButton[m_buttonToVK[i]] = i;
}
}
if (m_buttonToNumpadVK[i] != 0) {
if (m_virtualKeyToButton[m_buttonToNumpadVK[i]] == 0) {
m_virtualKeyToButton[m_buttonToNumpadVK[i]] = i;
}
}
}
}
// add numpad keys
for (KeyButton i = 0; i < 512; ++i) {
if (m_buttonToNumpadVK[i] != 0) {
item.m_id = getKeyID(m_buttonToNumpadVK[i], i);
item.m_button = i;
item.m_required = KeyModifierNumLock;
item.m_sensitive = KeyModifierNumLock | KeyModifierShift;
item.m_generates = 0;
item.m_client = m_buttonToNumpadVK[i];
addKeyEntry(keyMap, item);
}
}
// add other keys
BYTE keys[256];
memset(keys, 0, sizeof(keys));
for (KeyButton i = 0; i < 512; ++i) {
if (m_buttonToVK[i] != 0) {
// initialize item
item.m_id = getKeyID(m_buttonToVK[i], i);
item.m_button = i;
item.m_required = 0;
item.m_sensitive = 0;
item.m_client = m_buttonToVK[i];
// get flags for modifier keys
deskflow::KeyMap::initModifierKey(item);
if (item.m_id == 0) {
// translate virtual key to a character with and without
// shift, caps lock, and AltGr.
struct Modifier
{
UINT m_vk1;
UINT m_vk2;
BYTE m_state;
KeyModifierMask m_mask;
};
static const Modifier modifiers[] = {
{VK_SHIFT, VK_SHIFT, 0x80u, KeyModifierShift},
{VK_CAPITAL, VK_CAPITAL, 0x01u, KeyModifierCapsLock},
{VK_CONTROL, VK_MENU, 0x80u, KeyModifierControl | KeyModifierAlt}
};
static const size_t s_numModifiers = sizeof(modifiers) / sizeof(modifiers[0]);
static const size_t s_numCombinations = 1 << s_numModifiers;
KeyID id[s_numCombinations];
bool anyFound = false;
KeyButton button = static_cast<KeyButton>(i & 0xffu);
for (size_t j = 0; j < s_numCombinations; ++j) {
for (size_t k = 0; k < s_numModifiers; ++k) {
// if ((j & (1 << k)) != 0) {
// http://msdn.microsoft.com/en-us/library/ke55d167.aspx
if ((j & (1i64 << k)) != 0) {
keys[modifiers[k].m_vk1] = modifiers[k].m_state;
keys[modifiers[k].m_vk2] = modifiers[k].m_state;
} else {
keys[modifiers[k].m_vk1] = 0;
keys[modifiers[k].m_vk2] = 0;
}
}
id[j] = getIDForKey(item, button, m_buttonToVK[i], keys, m_groups[g]);
if (id[j] != 0) {
anyFound = true;
}
}
if (anyFound) {
// determine what modifiers we're sensitive to.
// we're sensitive if the KeyID changes when the
// modifier does.
item.m_sensitive = 0;
for (size_t k = 0; k < s_numModifiers; ++k) {
for (size_t j = 0; j < s_numCombinations; ++j) {
// if (id[j] != id[j ^ (1u << k)]) {
// http://msdn.microsoft.com/en-us/library/ke55d167.aspx
if (id[j] != id[j ^ (1ui64 << k)]) {
item.m_sensitive |= modifiers[k].m_mask;
break;
}
}
}
// save each key. the map will automatically discard
// duplicates, like an unshift and shifted version of
// a key that's insensitive to shift.
for (size_t j = 0; j < s_numCombinations; ++j) {
item.m_id = id[j];
item.m_required = 0;
for (size_t k = 0; k < s_numModifiers; ++k) {
if ((j & (1i64 << k)) != 0) {
item.m_required |= modifiers[k].m_mask;
}
}
addKeyEntry(keyMap, item);
}
}
} else {
// found in table
switch (m_buttonToVK[i]) {
case VK_TAB:
// add kKeyLeftTab, too
item.m_id = kKeyLeftTab;
item.m_required |= KeyModifierShift;
item.m_sensitive |= KeyModifierShift;
addKeyEntry(keyMap, item);
item.m_id = kKeyTab;
item.m_required &= ~KeyModifierShift;
break;
case VK_CANCEL:
item.m_required |= KeyModifierControl;
item.m_sensitive |= KeyModifierControl;
break;
}
addKeyEntry(keyMap, item);
}
}
}
}
// restore keyboard layout
ActivateKeyboardLayout(activeLayout, 0);
}
void MSWindowsKeyState::fakeKey(const Keystroke &keystroke)
{
switch (keystroke.m_type) {
case Keystroke::kButton: {
LOG(
(CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client,
keystroke.m_data.m_button.m_press ? "down" : "up")
);
KeyButton scanCode = keystroke.m_data.m_button.m_button;
// windows doesn't send key ups for key repeats
if (keystroke.m_data.m_button.m_repeat && !keystroke.m_data.m_button.m_press) {
LOG((CLOG_DEBUG1 " discard key repeat release"));
break;
}
// get the virtual key for the button
WORD vk = (WORD)keystroke.m_data.m_button.m_client;
DWORD flags = 0;
if (keystroke.m_data.m_button.m_press == false)
flags |= KEYEVENTF_KEYUP;
// special handling of VK_SNAPSHOT
if (vk == VK_SNAPSHOT)
scanCode = (getActiveModifiers() & KeyModifierAlt) ? 0x54 : 0x137;
if (scanCode & 0x100)
flags |= KEYEVENTF_EXTENDEDKEY;
// vk,sc,flags,keystroke.m_data.m_button.m_repeat
m_desks->fakeKeyEvent(vk, scanCode, flags, keystroke.m_data.m_button.m_repeat);
// synthesize event
// m_desks->fakeKeyEvent(button, vk,
// keystroke.m_data.m_button.m_press,
// keystroke.m_data.m_button.m_repeat);
break;
}
case Keystroke::kGroup:
// we don't restore the group. we'd like to but we can't be
// sure the restoring group change will be processed after the
// key events.
if (!keystroke.m_data.m_group.m_restore) {
if (keystroke.m_data.m_group.m_absolute) {
LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group));
setWindowGroup(keystroke.m_data.m_group.m_group);
} else {
LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group));
setWindowGroup(getEffectiveGroup(pollActiveGroup(), keystroke.m_data.m_group.m_group));
}
}
break;
}
}
KeyModifierMask &MSWindowsKeyState::getActiveModifiersRValue()
{
if (m_useSavedModifiers) {
return m_savedModifiers;
} else {
return KeyState::getActiveModifiersRValue();
}
}
bool MSWindowsKeyState::getGroups(GroupList &groups) const
{
// get keyboard layouts
uint32_t newNumLayouts = GetKeyboardLayoutList(0, nullptr);
if (newNumLayouts == 0) {
LOG((CLOG_DEBUG1 "can't get keyboard layouts"));
return false;
}
HKL *newLayouts = new HKL[newNumLayouts];
newNumLayouts = GetKeyboardLayoutList(newNumLayouts, newLayouts);
if (newNumLayouts == 0) {
LOG((CLOG_DEBUG1 "can't get keyboard layouts"));
delete[] newLayouts;
return false;
}
groups.clear();
groups.insert(groups.end(), newLayouts, newLayouts + newNumLayouts);
delete[] newLayouts;
return true;
}
void MSWindowsKeyState::setWindowGroup(int32_t group)
{
HWND targetWindow = GetForegroundWindow();
bool sysCharSet = true;
// XXX -- determine if m_groups[group] can be used with the system
// character set.
if (!PostMessage(targetWindow, WM_INPUTLANGCHANGEREQUEST, sysCharSet ? 1 : 0, (LPARAM)m_groups[group])) {
LOG((CLOG_WARN "failed to post change language message"));
}
// XXX -- use a short delay to let the target window process the message
// before it sees the keyboard events. i'm not sure why this is
// necessary since the messages should arrive in order. if we don't
// delay, though, some of our keyboard events may disappear.
Sleep(100);
}
KeyID MSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) const
{
// Some virtual keycodes have same values.
// VK_HANGUL == VK_KANA, VK_HANJA == NK_KANJI
// which are used to change the input mode of IME.
// But they have different X11 keysym. So we should distinguish them.
if ((LOWORD(m_keyLayout) & 0xffffu) == 0x0412u) { // 0x0412 : Korean Locale ID
if (virtualKey == VK_HANGUL || virtualKey == VK_HANJA) {
// If shift-space is used to change the input mode,
// the extented bit is not set. So add it to get right key id.
button |= 0x100u;
}
}
if ((button & 0x100u) != 0) {
virtualKey += 0x100u;
}
return s_virtualKey[virtualKey];
}
UINT MSWindowsKeyState::mapButtonToVirtualKey(KeyButton button) const
{
return m_buttonToVK[button];
}
KeyID MSWindowsKeyState::getIDForKey(
deskflow::KeyMap::KeyItem &item, KeyButton button, UINT virtualKey, PBYTE keyState, HKL hkl
) const
{
WCHAR unicode[2];
int n = m_ToUnicodeEx(virtualKey, button, keyState, unicode, sizeof(unicode) / sizeof(unicode[0]), 0, hkl);
KeyID id = static_cast<KeyID>(unicode[0]);
switch (n) {
case -1: {
// dead key. add an space to the keyboard so we exit
// the dead key mode and future calls to this function
// with different modifiers are not affected.
BYTE emptyState[256] = {};
n = m_ToUnicodeEx(VK_SPACE, 0, emptyState, unicode, sizeof(unicode) / sizeof(unicode[0]), 0, hkl);
// as an alternative, we could use the returned
// buffer in unicode to look at the dead key character
// and not rely on getDeadKey to provide the mapping
return deskflow::KeyMap::getDeadKey(id);
}
default:
case 0:
// unmapped
return kKeyNone;
case 1:
return id;
case 2:
// left over dead key in buffer. this used to recurse,
// but apparently this causes a stack overflow, so just
// return no key instead.
return kKeyNone;
}
}
void MSWindowsKeyState::addKeyEntry(deskflow::KeyMap &keyMap, deskflow::KeyMap::KeyItem &item)
{
keyMap.addKeyEntry(item);
if (item.m_group == 0) {
m_keyToVKMap[item.m_id] = static_cast<UINT>(item.m_client);
}
}