/*
 * Deskflow -- mouse and keyboard sharing utility
 * Copyright (C) 2012-2016 Symless Ltd.
 * Copyright (C) 2003 Chris Schoeneman
 *
 * This package is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * found in the file LICENSE that should have accompanied this file.
 *
 * This package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "platform/MSWindowsKeyState.h"

#include "arch/win32/ArchMiscWindows.h"
#include "base/FunctionJob.h"
#include "base/IEventQueue.h"
#include "base/Log.h"
#include "base/String.h"
#include "base/TMethodEventJob.h"
#include "mt/Thread.h"
#include "platform/MSWindowsDesks.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<String> layouts, bool isLangSyncEnabled
)
    : KeyState(events, std::move(layouts), isLangSyncEnabled),
      m_eventTarget(eventTarget),
      m_desks(desks),
      m_keyLayout(GetKeyboardLayout(0)),
      m_fixTimer(NULL),
      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<String> layouts, bool isLangSyncEnabled
)
    : KeyState(events, keyMap, std::move(layouts), isLangSyncEnabled),
      m_eventTarget(eventTarget),
      m_desks(desks),
      m_keyLayout(GetKeyboardLayout(0)),
      m_fixTimer(NULL),
      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 != NULL) {
    m_events->removeHandler(Event::kTimer, m_fixTimer);
    m_events->deleteTimer(m_fixTimer);
    m_fixTimer = NULL;
  }
  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 != NULL) {
    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, SInt32 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 String &lang)
{
  KeyState::fakeKeyDown(id, mask, button, lang);
}

bool MSWindowsKeyState::fakeKeyRepeat(
    KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button, const String &lang
)
{
  return KeyState::fakeKeyRepeat(id, mask, count, button, lang);
}

bool MSWindowsKeyState::fakeCtrlAltDel()
{
  // to fake ctrl+alt+del on the NT family we broadcast a suitable
  // hotkey to all windows on the winlogon desktop.  however, the
  // current thread must be on that desktop to do the broadcast
  // and we can't switch just any thread because some own windows
  // or hooks.  so start a new thread to do the real work.
  HANDLE hEvtSendSas = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SendSAS");
  if (hEvtSendSas) {
    LOG((CLOG_DEBUG "found the SendSAS event - signaling my launcher to "
                    "simulate ctrl+alt+del"));
    SetEvent(hEvtSendSas);
    CloseHandle(hEvtSendSas);
  } else {
    Thread cad(new FunctionJob(&MSWindowsKeyState::ctrlAltDelThread));
    cad.wait();
  }

  return true;
}

void MSWindowsKeyState::ctrlAltDelThread(void *)
{
  // get the Winlogon desktop at whatever privilege we can
  HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED);
  if (desk != NULL) {
    if (SetThreadDesktop(desk)) {
      PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELPARAM(MOD_CONTROL | MOD_ALT, VK_DELETE));
    } else {
      LOG((CLOG_DEBUG "can't switch to Winlogon desk: %d", GetLastError()));
    }
    CloseDesktop(desk);
  } else {
    LOG((CLOG_DEBUG "can't open Winlogon desk: %d", GetLastError()));
  }
}

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;
}

SInt32 MSWindowsKeyState::pollActiveGroup() const
{
  // determine the thread that'll receive this event
  HWND targetWindow = GetForegroundWindow();
  DWORD targetThread = GetWindowThreadProcessId(targetWindow, NULL);

  // 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, NULL);
    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();
    SInt32 numGroups = (SInt32)m_groups.size();
    for (SInt32 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;
  SInt32 numGroups = (SInt32)m_groups.size();
  for (SInt32 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 newNumLayouts = GetKeyboardLayoutList(0, NULL);
  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(SInt32 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);
  }
}
