2018-09-18 02:09:59 +08:00
/* Copyright (C) 2006-2017 Alexander Barker.
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*/
2017-02-06 16:55:01 +08:00
# ifdef HAVE_CONFIG_H
# include <config.h>
# endif
# include <stdbool.h>
# include <stddef.h>
# include <stdint.h>
# include <stdio.h>
# include <string.h>
# include <windows.h>
# include "../iohook.h"
# include "../logger_c.h"
# include "input.h"
static const uint16_t keycode_scancode_table [ ] [ 2 ] = {
/* idx { vk_code, scancode }, */
/* 0 */ { VC_UNDEFINED , 0x0000 } , // 0x00
/* 1 */ { MOUSE_BUTTON1 , VK_ESCAPE } , // 0x01
/* 2 */ { MOUSE_BUTTON2 , 0x0031 } , // 0x02
/* 3 */ { VC_UNDEFINED , 0x0032 } , // 0x03 VK_CANCEL
/* 4 */ { MOUSE_BUTTON3 , 0x0033 } , // 0x04
/* 5 */ { MOUSE_BUTTON4 , 0x0034 } , // 0x05
/* 6 */ { MOUSE_BUTTON5 , 0x0035 } , // 0x06
/* 7 */ { VC_UNDEFINED , 0x0036 } , // 0x07 Undefined
/* 8 */ { VC_BACKSPACE , 0x0037 } , // 0x08 VK_BACK
/* 9 */ { VC_TAB , 0x0038 } , // 0x09 VK_TAB
/* 10 */ { VC_UNDEFINED , 0x0039 } , // 0x0A Reserved
/* 11 */ { VC_UNDEFINED , 0x0030 } , // 0x0B Reserved
/* 12 */ { VC_CLEAR , VK_OEM_MINUS } , // 0x0C VK_CLEAR
/* 13 */ { VC_ENTER , VK_OEM_PLUS } , // 0x0D VK_RETURN
/* 14 */ { VC_UNDEFINED , VK_BACK } , // 0x0E Undefined
/* 15 */ { VC_UNDEFINED , VK_TAB } , // 0x0F Undefined
/* 16 */ { VC_SHIFT_L , 0x0051 } , // 0x10 VK_SHIFT
/* 17 */ { VC_CONTROL_L , 0x0057 } , // 0x11 VK_CONTROL
/* 18 */ { VC_ALT_L , 0x0045 } , // 0x12 VK_MENU ALT key
/* 19 */ { VC_PAUSE , 0x0052 } , // 0x13 VK_PAUSE
/* 20 */ { VC_CAPS_LOCK , 0x0054 } , // 0x14 VK_CAPITAL CAPS LOCK key
/* 21 */ { VC_KATAKANA , 0x0059 } , // 0x15 VK_KANA IME Kana mode
/* 22 */ { VC_UNDEFINED , 0x0055 } , // 0x16 Undefined
/* 23 */ { VC_UNDEFINED , 0x0049 } , // 0x17 VK_JUNJA IME Junja mode
/* 24 */ { VC_UNDEFINED , 0x004F } , // 0x18 VK_FINAL
/* 25 */ { VC_KANJI , 0x0050 } , // 0x19 VK_KANJI / VK_HANJA IME Kanji / Hanja mode
/* 26 */ { VC_UNDEFINED , 0x00DB } , // 0x1A Undefined
/* 27 */ { VC_ESCAPE , 0x00DD } , // 0x1B VK_ESCAPE ESC key
/* 28 */ { VC_UNDEFINED , VK_RETURN } , // 0x1C VK_CONVERT IME convert// 0x1C
/* 29 */ { VC_UNDEFINED , VK_LCONTROL } , // 0x1D VK_NONCONVERT IME nonconvert
/* 30 */ { VC_UNDEFINED , 0x0041 } , // 0x1E VK_ACCEPT IME accept
/* 31 */ { VC_UNDEFINED , 0x0053 } , // 0x1F VK_MODECHANGE IME mode change request
/* 32 */ { VC_SPACE , 0x0044 } , // 0x20 VK_SPACE SPACEBAR
/* 33 */ { VC_PAGE_UP , 0x0046 } , // 0x21 VK_PRIOR PAGE UP key
/* 34 */ { VC_PAGE_DOWN , 0x0047 } , // 0x22 VK_NEXT PAGE DOWN key
/* 35 */ { VC_END , 0x0048 } , // 0x23 VK_END END key
/* 36 */ { VC_HOME , 0x004A } , // 0x24 VK_HOME HOME key
/* 37 */ { VC_LEFT , 0x004B } , // 0x25 VK_LEFT LEFT ARROW key
/* 38 */ { VC_UP , 0x004C } , // 0x26 VK_UP UP ARROW key
/* 39 */ { VC_RIGHT , VK_OEM_1 } , // 0x27 VK_RIGHT RIGHT ARROW key
/* 40 */ { VC_DOWN , VK_OEM_7 } , // 0x28 VK_DOWN DOWN ARROW key
/* 41 */ { VC_UNDEFINED , VK_OEM_3 } , // 0x29 VK_SELECT SELECT key
/* 42 */ { VC_UNDEFINED , VK_LSHIFT } , // 0x2A VK_PRINT PRINT key
/* 43 */ { VC_UNDEFINED , VK_OEM_5 } , // 0x2B VK_EXECUTE EXECUTE key
/* 44 */ { VC_PRINTSCREEN , 0x005A } , // 0x2C VK_SNAPSHOT PRINT SCREEN key
/* 45 */ { VC_INSERT , 0x0058 } , // 0x2D VK_INSERT INS key
/* 46 */ { VC_DELETE , 0x0043 } , // 0x2E VK_DELETE DEL key
/* 47 */ { VC_UNDEFINED , 0x0056 } , // 0x2F VK_HELP HELP key
/* 48 */ { VC_0 , 0x0042 } , // 0x30 0 key
/* 49 */ { VC_1 , 0x004E } , // 0x31 1 key
/* 50 */ { VC_2 , 0x004D } , // 0x32 2 key
/* 51 */ { VC_3 , VK_OEM_COMMA } , // 0x33 3 key
/* 52 */ { VC_4 , VK_OEM_PERIOD } , // 0x34 4 key
/* 53 */ { VC_5 , VK_OEM_2 } , // 0x35 5 key
/* 54 */ { VC_6 , VK_RSHIFT } , // 0x36 6 key
/* 55 */ { VC_7 , VK_MULTIPLY } , // 0x37 7 key
/* 56 */ { VC_8 , VK_LMENU } , // 0x38 8 key
/* 57 */ { VC_9 , VK_SPACE } , // 0x39 9 key
/* 58 */ { VC_UNDEFINED , VK_CAPITAL } , // 0x3A Undefined
/* 59 */ { VC_UNDEFINED , VK_F1 } , // 0x3B Undefined
/* 60 */ { VC_UNDEFINED , VK_F2 } , // 0x3C Undefined
/* 61 */ { VC_UNDEFINED , VK_F3 } , // 0x3D Undefined
/* 62 */ { VC_UNDEFINED , VK_F4 } , // 0x3E Undefined
/* 63 */ { VC_UNDEFINED , VK_F5 } , // 0x3F Undefined
/* 64 */ { VC_UNDEFINED , VK_F6 } , // 0x40 Undefined
/* 65 */ { VC_A , VK_F7 } , // 0x41 A key
/* 66 */ { VC_B , VK_F8 } , // 0x42 B key
/* 67 */ { VC_C , VK_F9 } , // 0x43 C key
/* 68 */ { VC_D , VK_F10 } , // 0x44 D key
/* 69 */ { VC_E , VK_NUMLOCK } , // 0x45 E key
/* 70 */ { VC_F , VK_SCROLL } , // 0x46 F key
/* 71 */ { VC_G , VK_NUMPAD7 } , // 0x47 G key
/* 72 */ { VC_H , VK_NUMPAD8 } , // 0x48 H key
/* 73 */ { VC_I , VK_NUMPAD9 } , // 0x49 I key
/* 74 */ { VC_J , VK_SUBTRACT } , // 0x4A J key
/* 75 */ { VC_K , VK_NUMPAD4 } , // 0x4B K key
/* 76 */ { VC_L , VK_NUMPAD5 } , // 0x4C L key
/* 77 */ { VC_M , VK_NUMPAD6 } , // 0x4D M key
/* 78 */ { VC_N , VK_ADD } , // 0x4E N key
/* 79 */ { VC_O , VK_NUMPAD1 } , // 0x4F O key
/* 80 */ { VC_P , VK_NUMPAD2 } , // 0x50 P key
/* 81 */ { VC_Q , VK_NUMPAD3 } , // 0x51 Q key
/* 82 */ { VC_R , VK_NUMPAD0 } , // 0x52 R key
/* 83 */ { VC_S , VK_DECIMAL } , // 0x53 S key
/* 84 */ { VC_T , 0x0000 } , // 0x54 T key
/* 85 */ { VC_U , 0x0000 } , // 0x55 U key
/* 86 */ { VC_V , 0x0000 } , // 0x56 V key
/* 87 */ { VC_W , VK_F11 } , // 0x57 W key
/* 88 */ { VC_X , VK_F12 } , // 0x58 X key
/* 89 */ { VC_Y , 0x0000 } , // 0x59 Y key
/* 90 */ { VC_Z , 0x0000 } , // 0x5A Z key
/* 91 */ { VC_META_L , VK_F13 } , // 0x5B VK_LWIN Left Windows key (Natural keyboard)
/* 92 */ { VC_META_R , VK_F14 } , // 0x5C VK_RWIN Right Windows key (Natural keyboard)
/* 93 */ { VC_CONTEXT_MENU , VK_F15 } , // 0x5D VK_APPS Applications key (Natural keyboard)
/* 94 */ { VC_UNDEFINED , 0x0000 } , // 0x5E Reserved
/* 95 */ { VC_SLEEP , 0x0000 } , // 0x5F VK_SLEEP Computer Sleep key
/* 96 */ { VC_KP_0 , 0x0000 } , // 0x60 VK_NUMPAD0 Numeric keypad 0 key
/* 97 */ { VC_KP_1 , 0x0000 } , // 0x61 VK_NUMPAD1 Numeric keypad 1 key
/* 98 */ { VC_KP_2 , 0x0000 } , // 0x62 VK_NUMPAD2 Numeric keypad 2 key
/* 99 */ { VC_KP_3 , VK_F16 } , // 0x63 VK_NUMPAD3 Numeric keypad 3 key
/* 100 */ { VC_KP_4 , VK_F17 } , // 0x64 VK_NUMPAD4 Numeric keypad 4 key
/* 101 */ { VC_KP_5 , VK_F18 } , // 0x65 VK_NUMPAD5 Numeric keypad 5 key
/* 102 */ { VC_KP_6 , VK_F19 } , // 0x66 VK_NUMPAD6 Numeric keypad 6 key
/* 103 */ { VC_KP_7 , VK_F20 } , // 0x67 VK_NUMPAD7 Numeric keypad 7 key
/* 104 */ { VC_KP_8 , VK_F21 } , // 0x68 VK_NUMPAD8 Numeric keypad 8 key
/* 105 */ { VC_KP_9 , VK_F22 } , // 0x69 VK_NUMPAD9 Numeric keypad 9 key
/* 106 */ { VC_KP_MULTIPLY , VK_F23 } , // 0x6A VK_MULTIPLY Multiply key
/* 107 */ { VC_KP_ADD , VK_F24 } , // 0x6B VK_ADD Add key
/* 108 */ { VC_UNDEFINED , 0x0000 } , // 0x6C VK_SEPARATOR Separator key
/* 109 */ { VC_KP_SUBTRACT , 0x0000 } , // 0x6D VK_SUBTRACT Subtract key
/* 110 */ { VC_KP_SEPARATOR , 0x0000 } , // 0x6E VK_DECIMAL Decimal key
/* 111 */ { VC_KP_DIVIDE , 0x0000 } , // 0x6F VK_DIVIDE Divide key
/* 112 */ { VC_F1 , VK_KANA } , // 0x70 VK_F1 F1 key
/* 113 */ { VC_F2 , 0x0000 } , // 0x71 VK_F2 F2 key
/* 114 */ { VC_F3 , 0x0000 } , // 0x72 VK_F3 F3 key
/* 115 */ { VC_F4 , 0x0000 } , // 0x73 VK_F4 F4 key
/* 116 */ { VC_F5 , 0x0000 } , // 0x74 VK_F5 F5 key
/* 117 */ { VC_F6 , 0x0000 } , // 0x75 VK_F6 F6 key
/* 118 */ { VC_F7 , 0x0000 } , // 0x76 VK_F7 F7 key
/* 119 */ { VC_F8 , 0x0000 } , // 0x77 VK_F8 F8 key
/* 120 */ { VC_F9 , 0x0000 } , // 0x78 VK_F9 F9 key
/* 121 */ { VC_F10 , VK_KANJI } , // 0x79 VK_F10 F10 key
/* 122 */ { VC_F11 , 0x0000 } , // 0x7A VK_F11 F11 key
/* 123 */ { VC_F12 , 0x0000 } , // 0x7B VK_F12 F12 key
/* 124 */ { VC_F13 , 0x0000 } , // 0x7C VK_F13 F13 key
/* 125 */ { VC_F14 , VK_OEM_8 } , // 0x7D VK_F14 F14 key
/* 126 */ { VC_F15 , 0x0000 } , // 0x7E VK_F15 F15 key
/* 127 */ { VC_F16 , 0x0000 } , // 0x7F VK_F16 F16 key
// No Offset Offset (i & 0x007F) | 0x80
/* 128 */ { VC_F17 , 0x0000 } , // 0x80 VK_F17 F17 key
/* 129 */ { VC_F18 , 0x0000 } , // 0x81 VK_F18 F18 key
/* 130 */ { VC_F19 , 0x0000 } , // 0x82 VK_F19 F19 key
/* 131 */ { VC_F20 , 0x0000 } , // 0x83 VK_F20 F20 key
/* 132 */ { VC_F21 , 0x0000 } , // 0x84 VK_F21 F21 key
/* 133 */ { VC_F22 , 0x0000 } , // 0x85 VK_F22 F22 key
/* 134 */ { VC_F23 , 0x0000 } , // 0x86 VK_F23 F23 key
/* 135 */ { VC_F24 , 0x0000 } , // 0x87 VK_F24 F24 key
/* 136 */ { VC_UNDEFINED , 0x0000 } , // 0x88 Unassigned
/* 137 */ { VC_UNDEFINED , 0x0000 } , // 0x89 Unassigned
/* 138 */ { VC_UNDEFINED , 0x0000 } , // 0x8A Unassigned
/* 139 */ { VC_UNDEFINED , 0x0000 } , // 0x8B Unassigned
/* 140 */ { VC_UNDEFINED , 0x0000 } , // 0x8C Unassigned
/* 141 */ { VC_UNDEFINED , 0x0000 } , // 0x8D Unassigned
/* 142 */ { VC_UNDEFINED , 0x0000 } , // 0x8E Unassigned
/* 143 */ { VC_UNDEFINED , 0x0000 } , // 0x8F Unassigned
/* 144 */ { VC_NUM_LOCK , VK_MEDIA_PREV_TRACK } , // 0x90 VK_NUMLOCK NUM LOCK key
/* 145 */ { VC_SCROLL_LOCK , 0x0000 } , // 0x91 VK_SCROLL SCROLL LOCK key
/* 146 */ { VC_UNDEFINED , 0x0000 } , // 0x92 OEM specific
/* 147 */ { VC_UNDEFINED , 0x0000 } , // 0x93 OEM specific
/* 148 */ { VC_UNDEFINED , 0x0000 } , // 0x94 OEM specific
/* 149 */ { VC_UNDEFINED , 0x0000 } , // 0x95 OEM specific
/* 150 */ { VC_UNDEFINED , 0x0000 } , // 0x96 OEM specific
/* 151 */ { VC_UNDEFINED , 0x0000 } , // 0x97 Unassigned
/* 152 */ { VC_UNDEFINED , 0x0000 } , // 0x98 Unassigned
/* 153 */ { VC_UNDEFINED , VK_MEDIA_NEXT_TRACK } , // 0x99 Unassigned
/* 154 */ { VC_UNDEFINED , 0x0000 } , // 0x9A Unassigned
/* 155 */ { VC_UNDEFINED , 0x0000 } , // 0x9B Unassigned
/* 156 */ { VC_UNDEFINED , 0x0000 } , // 0x9C Unassigned
/* 157 */ { VC_UNDEFINED , VK_RCONTROL } , // 0x9D Unassigned
/* 158 */ { VC_UNDEFINED , 0x0000 } , // 0x9E Unassigned
/* 159 */ { VC_UNDEFINED , 0x0000 } , // 0x9F Unassigned
/* 160 */ { VC_SHIFT_L , VK_VOLUME_MUTE } , // 0xA0 VK_LSHIFT Left SHIFT key
/* 161 */ { VC_SHIFT_R , VK_LAUNCH_APP2 } , // 0xA1 VK_RSHIFT Right SHIFT key
/* 162 */ { VC_CONTROL_L , VK_MEDIA_PLAY_PAUSE } , // 0xA2 VK_LCONTROL Left CONTROL key
/* 163 */ { VC_CONTROL_R , 0x0000 } , // 0xA3 VK_RCONTROL Right CONTROL key
/* 164 */ { VC_ALT_L , VK_MEDIA_STOP } , // 0xA4 VK_LMENU Left MENU key
/* 165 */ { VC_ALT_R , 0x0000 } , // 0xA5 VK_RMENU Right MENU key
/* 166 */ { VC_BROWSER_BACK , 0x0000 } , // 0xA6 VK_BROWSER_BACK Browser Back key
/* 167 */ { VC_BROWSER_FORWARD , 0x0000 } , // 0xA7 VK_BROWSER_FORWARD Browser Forward key
/* 168 */ { VC_BROWSER_REFRESH , 0x0000 } , // 0xA8 VK_BROWSER_REFRESH Browser Refresh key
/* 169 */ { VC_BROWSER_STOP , 0x0000 } , // 0xA9 VK_BROWSER_STOP Browser Stop key
/* 170 */ { VC_BROWSER_SEARCH , 0x0000 } , // 0xAA VK_BROWSER_SEARCH Browser Search key
/* 171 */ { VC_BROWSER_FAVORITES , 0x0000 } , // 0xAB VK_BROWSER_FAVORITES Browser Favorites key
/* 172 */ { VC_BROWSER_HOME , 0x0000 } , // 0xAC VK_BROWSER_HOME Browser Start and Home key
/* 173 */ { VC_VOLUME_MUTE , 0x0000 } , // 0xAD VK_VOLUME_MUTE Volume Mute key
/* 174 */ { VC_VOLUME_DOWN , VK_VOLUME_DOWN } , // 0xAE VK_VOLUME_DOWN Volume Down key
/* 175 */ { VC_VOLUME_UP , 0x0000 } , // 0xAF VK_VOLUME_UP Volume Up key
/* 176 */ { VC_MEDIA_NEXT , VK_VOLUME_UP } , // 0xB0 VK_MEDIA_NEXT_TRACK Next Track key
/* 177 */ { VC_MEDIA_PREVIOUS , 0x0000 } , // 0xB1 VK_MEDIA_PREV_TRACK Previous Track key
/* 178 */ { VC_MEDIA_STOP , VK_BROWSER_HOME } , // 0xB2 VK_MEDIA_STOP Stop Media key
/* 179 */ { VC_MEDIA_PLAY , 0x0000 } , // 0xB3 VK_MEDIA_PLAY_PAUSE Play/Pause Media key
/* 180 */ { VC_UNDEFINED , 0x0000 } , // 0xB4 VK_LAUNCH_MAIL Start Mail key
/* 181 */ { VC_MEDIA_SELECT , VK_DIVIDE } , // 0xB5 VK_LAUNCH_MEDIA_SELECT Select Media key
/* 182 */ { VC_APP_MAIL , 0x0000 } , // 0xB6 VK_LAUNCH_APP1 Start Application 1 key
/* 183 */ { VC_APP_CALCULATOR , VK_SNAPSHOT } , // 0xB7 VK_LAUNCH_APP2 Start Application 2 key
/* 184 */ { VC_UNDEFINED , VK_RMENU } , // 0xB8 Reserved
/* 185 */ { VC_UNDEFINED , 0x0000 } , // 0xB9 Reserved
/* 186 */ { VC_SEMICOLON , 0x0000 } , // 0xBA VK_OEM_1 Varies by keyboard. For the US standard keyboard, the ';:' key
/* 187 */ { VC_EQUALS , 0x0000 } , // 0xBB VK_OEM_PLUS For any country/region, the '+' key
/* 188 */ { VC_COMMA , 0x00E6 } , // 0xBC VK_OEM_COMMA For any country/region, the ',' key
/* 189 */ { VC_MINUS , 0x0000 } , // 0xBD VK_OEM_MINUS For any country/region, the '-' key
/* 190 */ { VC_PERIOD , 0x0000 } , // 0xBE VK_OEM_PERIOD For any country/region, the '.' key
/* 191 */ { VC_SLASH , 0x0000 } , // 0xBF VK_OEM_2 Varies by keyboard. For the US standard keyboard, the '/?' key
/* 192 */ { VC_BACKQUOTE , 0x0000 } , // 0xC0 VK_OEM_3 Varies by keyboard. For the US standard keyboard, the '`~' key
/* 193 */ { VC_UNDEFINED , 0x0000 } , // 0xC1 Reserved
/* 194 */ { VC_UNDEFINED , 0x0000 } , // 0xC2 Reserved
/* 195 */ { VC_UNDEFINED , 0x0000 } , // 0xC3 Reserved
/* 196 */ { VC_UNDEFINED , 0x0000 } , // 0xC4 Reserved
/* 197 */ { VC_UNDEFINED , VK_PAUSE } , // 0xC5 Reserved
/* 198 */ { VC_UNDEFINED , 0x0000 } , // 0xC6 Reserved
/* 199 */ { VC_UNDEFINED , VK_HOME } , // 0xC7 Reserved
/* 200 */ { VC_UNDEFINED , VK_UP } , // 0xC8 Reserved
/* 201 */ { VC_UNDEFINED , VK_PRIOR } , // 0xC9 Reserved
/* 202 */ { VC_UNDEFINED , 0x0000 } , // 0xCA Reserved
/* 203 */ { VC_UNDEFINED , VK_LEFT } , // 0xCB Reserved
/* 204 */ { VC_UNDEFINED , VK_CLEAR } , // 0xCC Reserved
/* 205 */ { VC_UNDEFINED , VK_RIGHT } , // 0xCD Reserved
/* 206 */ { VC_UNDEFINED , 0x0000 } , // 0xCE Reserved
/* 207 */ { VC_UNDEFINED , VK_END } , // 0xCF Reserved
/* 208 */ { VC_UNDEFINED , VK_DOWN } , // 0xD0 Reserved
/* 209 */ { VC_UNDEFINED , VK_NEXT } , // 0xD1 Reserved
/* 210 */ { VC_UNDEFINED , VK_INSERT } , // 0xD2 Reserved
/* 211 */ { VC_UNDEFINED , VK_DELETE } , // 0xD3 Reserved
/* 212 */ { VC_UNDEFINED , 0x0000 } , // 0xD4 Reserved
/* 213 */ { VC_UNDEFINED , 0x0000 } , // 0xD5 Reserved
/* 214 */ { VC_UNDEFINED , 0x0000 } , // 0xD6 Reserved
/* 215 */ { VC_UNDEFINED , 0x0000 } , // 0xD7 Reserved
/* 216 */ { VC_UNDEFINED , 0x0000 } , // 0xD8 Unassigned
/* 217 */ { VC_UNDEFINED , 0x0000 } , // 0xD9 Unassigned
/* 218 */ { VC_UNDEFINED , 0x0000 } , // 0xDA Unassigned
/* 219 */ { VC_OPEN_BRACKET , VK_LWIN } , // 0xDB VK_OEM_4 Varies by keyboard. For the US standard keyboard, the '[{' key
/* 220 */ { VC_BACK_SLASH , VK_RWIN } , // 0xDC VK_OEM_5 Varies by keyboard. For the US standard keyboard, the '\|' key
/* 221 */ { VC_CLOSE_BRACKET , VK_APPS } , // 0xDD VK_OEM_6 Varies by keyboard. For the US standard keyboard, the ']}' key
/* 222 */ { VC_QUOTE , 0x0000 } , // 0xDE VK_OEM_7 Varies by keyboard. For the US standard keyboard, the 'single-quote/double-quote' key
/* 223 */ { VC_YEN , VK_SLEEP } , // 0xDF VK_OEM_8 Varies by keyboard.
/* 224 */ { VC_UNDEFINED , 0x0000 } , // 0xE0 Reserved
/* 225 */ { VC_UNDEFINED , 0x0000 } , // 0xE1 OEM specific
/* 226 */ { VC_UNDEFINED , 0x0000 } , // 0xE2 VK_OEM_102 Either the angle bracket key or the backslash key on the RT 102-key keyboard
/* 227 */ { VC_UNDEFINED , 0x0000 } , // 0xE3 OEM specific
/* 228 */ { VC_UNDEFINED , 0x00E5 } , // 0xE4 VC_APP_PICTURES OEM specific
/* 229 */ { VC_APP_PICTURES , VK_BROWSER_SEARCH } , // 0xE5 VK_PROCESSKEY IME PROCESS key
/* 230 */ { VC_APP_MUSIC , VK_BROWSER_FAVORITES } , // 0xE6 OEM specific
/* 231 */ { VC_UNDEFINED , VK_BROWSER_REFRESH } , // 0xE7 VK_PACKET Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods.
/* 232 */ { VC_UNDEFINED , VK_BROWSER_STOP } , // 0xE8 Unassigned
/* 233 */ { VC_UNDEFINED , VK_BROWSER_FORWARD } , // 0xE9 OEM specific
/* 234 */ { VC_UNDEFINED , VK_BROWSER_BACK } , // 0xEA OEM specific
/* 235 */ { VC_UNDEFINED , 0x0000 } , // 0xEB OEM specific
/* 236 */ { VC_UNDEFINED , VK_LAUNCH_APP1 } , // 0xEC OEM specific
/* 237 */ { VC_UNDEFINED , VK_LAUNCH_MEDIA_SELECT } , // 0xED OEM specific
/* 238 */ { VC_UNDEFINED , 0x0000 } , // 0xEE OEM specific
/* 239 */ { VC_UNDEFINED , 0x0000 } , // 0xEF OEM specific
/* 240 */ { VC_UNDEFINED , 0x0000 } , // 0xF0 OEM specific
/* 241 */ { VC_UNDEFINED , 0x0000 } , // 0xF1 OEM specific
/* 242 */ { VC_UNDEFINED , 0x0000 } , // 0xF2 OEM specific
/* 243 */ { VC_UNDEFINED , 0x0000 } , // 0xF3 OEM specific
/* 244 */ { VC_UNDEFINED , 0x0000 } , // 0xF4 OEM specific
/* 245 */ { VC_UNDEFINED , 0x0000 } , // 0xF5 OEM specific
/* 246 */ { VC_UNDEFINED , 0x0000 } , // 0xF6 VK_ATTN Attn key
/* 247 */ { VC_UNDEFINED , 0x0000 } , // 0xF7 VK_CRSEL CrSel key
/* 248 */ { VC_UNDEFINED , 0x0000 } , // 0xF8 VK_EXSEL ExSel key
/* 249 */ { VC_UNDEFINED , 0x0000 } , // 0xF9 VK_EREOF Erase EOF key
/* 250 */ { VC_UNDEFINED , 0x0000 } , // 0xFA VK_PLAY Play key
/* 251 */ { VC_UNDEFINED , 0x0000 } , // 0xFB VK_ZOOM Zoom key
/* 252 */ { VC_UNDEFINED , 0x0000 } , // 0xFC VK_NONAME Reserved
/* 253 */ { VC_UNDEFINED , 0x0000 } , // 0xFD
/* 254 */ { VC_CLEAR , 0x0000 } , // 0xFE VK_OEM_CLEAR Clear key
/* 255 */ { VC_UNDEFINED , 0x0000 } // 0xFE Unassigned
} ;
unsigned short keycode_to_scancode ( DWORD vk_code , DWORD flags ) {
unsigned short scancode = VC_UNDEFINED ;
// Check the vk_code is in range.
// NOTE vk_code >= 0 is assumed because DWORD is unsigned.
if ( vk_code < sizeof ( keycode_scancode_table ) / sizeof ( keycode_scancode_table [ 0 ] ) ) {
scancode = keycode_scancode_table [ vk_code ] [ 0 ] ;
if ( flags & LLKHF_EXTENDED ) {
2019-02-19 22:31:25 +08:00
// logger(LOG_LEVEL_WARN, "%s [%u]: EXTD2, vk_code %li\n",
// __FUNCTION__, __LINE__, vk_code);
2017-02-06 16:55:01 +08:00
switch ( vk_code ) {
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 :
scancode | = 0xEE00 ;
break ;
case VK_RETURN :
scancode | = 0x0E00 ;
break ;
}
}
else {
// logger(LOG_LEVEL_WARN, "%s [%u]: Test2, vk_code %li\n",
// __FUNCTION__, __LINE__, vk_code);
}
}
return scancode ;
}
DWORD scancode_to_keycode ( unsigned short scancode ) {
unsigned short keycode = 0x0000 ;
// Check the vk_code is in range.
// NOTE vk_code >= 0 is assumed because the scancode is unsigned.
if ( scancode < 128 ) {
keycode = keycode_scancode_table [ scancode ] [ 1 ] ;
}
else {
// Calculate the upper offset based on the lower half of the scancode + 128.
unsigned short int i = ( scancode & 0x007F ) | 0x80 ;
if ( i < sizeof ( keycode_scancode_table ) / sizeof ( keycode_scancode_table [ 1 ] ) ) {
keycode = keycode_scancode_table [ i ] [ 1 ] ;
}
}
return keycode ;
}
/************************************************************************/
// Structure and pointers for the keyboard locale cache.
typedef struct _KeyboardLocale {
HKL id ; // Locale ID
HINSTANCE library ; // Keyboard DLL instance.
PVK_TO_BIT pVkToBit ; // Pointers struct arrays.
PVK_TO_WCHAR_TABLE pVkToWcharTable ;
PDEADKEY pDeadKey ;
struct _KeyboardLocale * next ;
} KeyboardLocale ;
static KeyboardLocale * locale_first = NULL ;
static KeyboardLocale * locale_current = NULL ;
static WCHAR deadChar = WCH_NONE ;
// Amount of pointer padding to apply for Wow64 instances.
static unsigned short int ptr_padding = 0 ;
# if defined(_WIN32) && !defined(_WIN64)
// Small function to check and see if we are executing under Wow64.
static BOOL is_wow64 ( ) {
BOOL status = FALSE ;
LPFN_ISWOW64PROCESS pIsWow64Process = ( LPFN_ISWOW64PROCESS )
GetProcAddress ( GetModuleHandle ( " kernel32 " ) , " IsWow64Process " ) ;
if ( pIsWow64Process ! = NULL ) {
HANDLE current_proc = GetCurrentProcess ( ) ;
if ( ! pIsWow64Process ( current_proc , & status ) ) {
status = FALSE ;
logger ( LOG_LEVEL_DEBUG , " %s [%u]: pIsWow64Process(%#p, %#p) failed! \n " ,
__FUNCTION__ , __LINE__ , current_proc , & status ) ;
}
}
return status ;
}
# endif
// Locate the DLL that contains the current keyboard layout.
static int get_keyboard_layout_file ( char * layoutFile , DWORD bufferSize ) {
int status = IOHOOK_FAILURE ;
HKEY hKey ;
DWORD varType = REG_SZ ;
char kbdName [ KL_NAMELENGTH ] ;
if ( GetKeyboardLayoutName ( kbdName ) ) {
char kbdKeyPath [ 51 + KL_NAMELENGTH ] ;
snprintf ( kbdKeyPath , 51 + KL_NAMELENGTH , " SYSTEM \\ CurrentControlSet \\ Control \\ Keyboard Layouts \\ %s " , kbdName ) ;
if ( RegOpenKeyEx ( HKEY_LOCAL_MACHINE , ( LPCTSTR ) kbdKeyPath , 0 , KEY_QUERY_VALUE , & hKey ) = = ERROR_SUCCESS ) {
if ( RegQueryValueEx ( hKey , " Layout File " , NULL , & varType , ( LPBYTE ) layoutFile , & bufferSize ) = = ERROR_SUCCESS ) {
RegCloseKey ( hKey ) ;
status = IOHOOK_SUCCESS ;
}
}
}
return status ;
}
static int refresh_locale_list ( ) {
int count = 0 ;
// Get the number of layouts the user has activated.
int hkl_size = GetKeyboardLayoutList ( 0 , NULL ) ;
if ( hkl_size > 0 ) {
logger ( LOG_LEVEL_INFO , " %s [%u]: GetKeyboardLayoutList(0, NULL) found %i layouts. \n " ,
__FUNCTION__ , __LINE__ , hkl_size ) ;
// Get the thread id that currently has focus for our default.
DWORD focus_pid = GetWindowThreadProcessId ( GetForegroundWindow ( ) , NULL ) ;
HKL hlk_focus = GetKeyboardLayout ( focus_pid ) ;
HKL hlk_default = GetKeyboardLayout ( 0 ) ;
HKL * hkl_list = malloc ( sizeof ( HKL ) * hkl_size ) ;
int new_size = GetKeyboardLayoutList ( hkl_size , hkl_list ) ;
if ( new_size > 0 ) {
if ( new_size ! = hkl_size ) {
logger ( LOG_LEVEL_WARN , " %s [%u]: Locale size mismatch! "
" Expected %i, received %i! \n " ,
__FUNCTION__ , __LINE__ , hkl_size , new_size ) ;
}
else {
logger ( LOG_LEVEL_INFO , " %s [%u]: Received %i locales. \n " ,
__FUNCTION__ , __LINE__ , new_size ) ;
}
KeyboardLocale * locale_previous = NULL ;
KeyboardLocale * locale_item = locale_first ;
// Go though the linked list and remove KeyboardLocale's that are
// no longer loaded.
while ( locale_item ! = NULL ) {
// Check to see if the old HKL is in the new list.
bool is_loaded = false ;
int i ;
for ( i = 0 ; i < new_size & & ! is_loaded ; i + + ) {
if ( locale_item - > id = = hkl_list [ i ] ) {
// Flag and jump out of the loop.
hkl_list [ i ] = NULL ;
is_loaded = true ;
}
}
if ( is_loaded ) {
logger ( LOG_LEVEL_DEBUG , " %s [%u]: Found locale ID %#p in the cache. \n " ,
__FUNCTION__ , __LINE__ , locale_item - > id ) ;
// Set the previous local to the current locale.
locale_previous = locale_item ;
// Check and see if the locale is our current active locale.
if ( locale_item - > id = = hlk_focus ) {
locale_current = locale_item ;
}
count + + ;
}
else {
logger ( LOG_LEVEL_DEBUG , " %s [%u]: Removing locale ID %#p from the cache. \n " ,
__FUNCTION__ , __LINE__ , locale_item - > id ) ;
// If the old id is not in the new list, remove it.
locale_previous - > next = locale_item - > next ;
// Make sure the locale_current points NULL or something valid.
if ( locale_item = = locale_current ) {
locale_current = NULL ;
}
// Free the memory used by locale_item;
free ( locale_item ) ;
// Set the item to the pervious item to guarantee a next.
locale_item = locale_previous ;
}
// Iterate to the next linked list item.
locale_item = locale_item - > next ;
}
// Insert anything new into the linked list.
int i ;
for ( i = 0 ; i < new_size ; i + + ) {
// Check to see if the item was already in the list.
if ( hkl_list [ i ] ! = NULL ) {
// Set the active keyboard layout for this thread to the HKL.
ActivateKeyboardLayout ( hkl_list [ i ] , 0x00 ) ;
// Try to pull the current keyboard layout DLL from the registry.
char layoutFile [ MAX_PATH ] ;
if ( get_keyboard_layout_file ( layoutFile , sizeof ( layoutFile ) ) = = IOHOOK_SUCCESS ) {
// You can't trust the %SYSPATH%, look it up manually.
char systemDirectory [ MAX_PATH ] ;
if ( GetSystemDirectory ( systemDirectory , MAX_PATH ) ! = 0 ) {
char kbdLayoutFilePath [ MAX_PATH ] ;
snprintf ( kbdLayoutFilePath , MAX_PATH , " %s \\ %s " , systemDirectory , layoutFile ) ;
logger ( LOG_LEVEL_DEBUG , " %s [%u]: Loading layout for %#p: %s. \n " ,
__FUNCTION__ , __LINE__ , hkl_list [ i ] , layoutFile ) ;
// Create the new locale item.
locale_item = malloc ( sizeof ( KeyboardLocale ) ) ;
locale_item - > id = hkl_list [ i ] ;
locale_item - > library = LoadLibrary ( kbdLayoutFilePath ) ;
// Get the function pointer from the library to get the keyboard layer descriptor.
KbdLayerDescriptor pKbdLayerDescriptor = ( KbdLayerDescriptor ) GetProcAddress ( locale_item - > library , " KbdLayerDescriptor " ) ;
if ( pKbdLayerDescriptor ! = NULL ) {
PKBDTABLES pKbd = pKbdLayerDescriptor ( ) ;
// Store the memory address of the following 3 structures.
BYTE * base = ( BYTE * ) pKbd ;
// First element of each structure, no offset adjustment needed.
locale_item - > pVkToBit = pKbd - > pCharModifiers - > pVkToBit ;
// Second element of pKbd, +4 byte offset on wow64.
locale_item - > pVkToWcharTable = * ( ( PVK_TO_WCHAR_TABLE * ) ( base + offsetof ( KBDTABLES , pVkToWcharTable ) + ptr_padding ) ) ;
// Third element of pKbd, +8 byte offset on wow64.
locale_item - > pDeadKey = * ( ( PDEADKEY * ) ( base + offsetof ( KBDTABLES , pDeadKey ) + ( ptr_padding * 2 ) ) ) ;
// This will always be added to the end of the list.
locale_item - > next = NULL ;
// Insert the item into the linked list.
if ( locale_previous = = NULL ) {
// If nothing came before, the list is empty.
locale_first = locale_item ;
}
else {
// Append the new locale to the end of the list.
locale_previous - > next = locale_item ;
}
// Check and see if the locale is our current active locale.
if ( locale_item - > id = = hlk_focus ) {
locale_current = locale_item ;
}
// Set the pervious locale item to the new one.
locale_previous = locale_item ;
count + + ;
}
else {
logger ( LOG_LEVEL_ERROR ,
" %s [%u]: GetProcAddress() failed for KbdLayerDescriptor! \n " ,
__FUNCTION__ , __LINE__ ) ;
FreeLibrary ( locale_item - > library ) ;
free ( locale_item ) ;
locale_item = NULL ;
}
}
else {
logger ( LOG_LEVEL_ERROR ,
" %s [%u]: GetSystemDirectory() failed! \n " ,
__FUNCTION__ , __LINE__ ) ;
}
}
else {
logger ( LOG_LEVEL_ERROR ,
" %s [%u]: Could not find keyboard map for locale %#p! \n " ,
__FUNCTION__ , __LINE__ , hkl_list [ i ] ) ;
}
}
}
}
else {
logger ( LOG_LEVEL_ERROR ,
" %s [%u]: GetKeyboardLayoutList() failed! \n " ,
__FUNCTION__ , __LINE__ ) ;
// TODO Try and recover by using the current layout.
// Hint: Use locale_id instead of hkl_list[i] in the loop above.
}
free ( hkl_list ) ;
ActivateKeyboardLayout ( hlk_default , 0x00 ) ;
}
return count ;
}
SIZE_T keycode_to_unicode ( DWORD keycode , PWCHAR buffer , SIZE_T size ) {
// Get the thread id that currently has focus and ask for its current
// locale.
DWORD focus_pid = GetWindowThreadProcessId ( GetForegroundWindow ( ) , NULL ) ;
HKL locale_id = GetKeyboardLayout ( focus_pid ) ;
// If the current Locale is not the new locale, search the linked list.
if ( locale_current = = NULL | | locale_current - > id ! = locale_id ) {
locale_current = NULL ;
KeyboardLocale * locale_item = locale_first ;
// Search the linked list...
while ( locale_item ! = NULL & & locale_item - > id ! = locale_id ) {
locale_item = locale_item - > next ;
}
// You may already be a winner!
if ( locale_item ! = NULL & & locale_item - > id ! = locale_id ) {
logger ( LOG_LEVEL_INFO ,
" %s [%u]: Activating keyboard layout %#p. \n " ,
__FUNCTION__ , __LINE__ , locale_item - > id ) ;
// Switch the current locale.
locale_current = locale_item ;
locale_item = NULL ;
// If they layout changes the dead key state needs to be reset.
// This is consistent with the way Windows handles locale changes.
deadChar = WCH_NONE ;
}
else {
logger ( LOG_LEVEL_DEBUG ,
" %s [%u]: Refreshing locale cache. \n " ,
__FUNCTION__ , __LINE__ ) ;
refresh_locale_list ( ) ;
}
}
// Initialize to empty.
SIZE_T charCount = 0 ;
// buffer[i] = WCH_NONE;
// Check and make sure the Unicode helper was loaded.
if ( locale_current ! = NULL ) {
logger ( LOG_LEVEL_INFO ,
" %s [%u]: Using keyboard layout %#p. \n " ,
__FUNCTION__ , __LINE__ , locale_current - > id ) ;
int mod = 0 ;
int capsLock = ( GetKeyState ( VK_CAPITAL ) & 0x01 ) ;
PVK_TO_BIT pVkToBit = locale_current - > pVkToBit ;
PVK_TO_WCHAR_TABLE pVkToWcharTable = locale_current - > pVkToWcharTable ;
PDEADKEY pDeadKey = locale_current - > pDeadKey ;
/* Loop over the modifier keys for this locale and determine what is
* currently depressed . Because this is only a structure of two
* bytes , we don ' t need to worry about the structure padding of __ptr64
* offsets on Wow64 .
*/
bool is_shift = false , is_ctrl = false , is_alt = false ;
int i ;
for ( i = 0 ; pVkToBit [ i ] . Vk ! = 0 ; i + + ) {
short state = GetAsyncKeyState ( pVkToBit [ i ] . Vk ) ;
// Check to see if the most significant bit is active.
if ( state & ~ SHRT_MAX ) {
if ( pVkToBit [ i ] . Vk = = VK_SHIFT ) {
is_shift = true ;
}
else if ( pVkToBit [ i ] . Vk = = VK_CONTROL ) {
is_ctrl = true ;
}
else if ( pVkToBit [ i ] . Vk = = VK_MENU ) {
is_alt = true ;
}
}
}
// Check the Shift modifier.
if ( is_shift ) {
mod = 1 ;
}
// Check for the AltGr modifier.
if ( is_ctrl & & is_alt ) {
mod + = 3 ;
}
// Default 32 bit structure size should be 6 bytes (4 for the pointer and 2
// additional byte fields) that are padded out to 8 bytes by the compiler.
unsigned short sizeVkToWcharTable = sizeof ( VK_TO_WCHAR_TABLE ) ;
# if defined(_WIN32) && !defined(_WIN64)
if ( is_wow64 ( ) ) {
// If we are running under Wow64 the size of the first pointer will be
// 8 bringing the total size to 10 bytes padded out to 16.
sizeVkToWcharTable = ( sizeVkToWcharTable + ptr_padding + 7 ) & - 8 ;
}
# endif
BYTE * ptrCurrentVkToWcharTable = ( BYTE * ) pVkToWcharTable ;
int cbSize , n ;
do {
// cbSize is used to calculate n, and n is used for the size of pVkToWchars[j].wch[n]
cbSize = * ( ptrCurrentVkToWcharTable + offsetof ( VK_TO_WCHAR_TABLE , cbSize ) + ptr_padding ) ;
n = ( cbSize - 2 ) / 2 ;
// Same as VK_TO_WCHARS pVkToWchars[] = pVkToWcharTable[i].pVkToWchars
PVK_TO_WCHARS pVkToWchars = ( PVK_TO_WCHARS ) ( ( PVK_TO_WCHAR_TABLE ) ptrCurrentVkToWcharTable ) - > pVkToWchars ;
if ( pVkToWchars ! = NULL & & mod < n ) {
// pVkToWchars[j].VirtualKey
BYTE * pCurrentVkToWchars = ( BYTE * ) pVkToWchars ;
do {
if ( ( ( PVK_TO_WCHARS ) pCurrentVkToWchars ) - > VirtualKey = = keycode ) {
if ( ( ( ( PVK_TO_WCHARS ) pCurrentVkToWchars ) - > Attributes = = CAPLOK ) & & capsLock ) {
if ( is_shift & & mod > 0 ) {
mod - = 1 ;
}
else {
mod + = 1 ;
}
}
// Set the initial unicode char.
WCHAR unicode = ( ( PVK_TO_WCHARS ) pCurrentVkToWchars ) - > wch [ mod ] ;
// Increment the pCurrentVkToWchars by the size of wch[n].
pCurrentVkToWchars + = sizeof ( VK_TO_WCHARS ) + ( sizeof ( WCHAR ) * n ) ;
if ( unicode = = WCH_DEAD ) {
// The current unicode char is a dead key...
if ( deadChar = = WCH_NONE ) {
// No previous dead key was set so cache the next
// wchar so we know what to do next time its pressed.
deadChar = ( ( PVK_TO_WCHARS ) pCurrentVkToWchars ) - > wch [ mod ] ;
}
else {
if ( size > = 2 ) {
// Received a second dead key.
memset ( buffer , deadChar , 2 ) ;
//buffer[0] = deadChar;
//buffer[1] = deadChar;
deadChar = WCH_NONE ;
charCount = 2 ;
}
}
}
else if ( unicode ! = WCH_NONE ) {
// We are not WCH_NONE or WCH_DEAD
if ( size > = 1 ) {
buffer [ 0 ] = unicode ;
charCount = 1 ;
}
}
break ;
}
else {
// Add sizeof WCHAR because we are really an array of WCHAR[n] not WCHAR[]
pCurrentVkToWchars + = sizeof ( VK_TO_WCHARS ) + ( sizeof ( WCHAR ) * n ) ;
}
} while ( ( ( PVK_TO_WCHARS ) pCurrentVkToWchars ) - > VirtualKey ! = 0 ) ;
}
// This is effectively the same as: ptrCurrentVkToWcharTable = pVkToWcharTable[++i];
ptrCurrentVkToWcharTable + = sizeVkToWcharTable ;
} while ( cbSize ! = 0 ) ;
// If the current local has a dead key set.
if ( deadChar ! = WCH_NONE ) {
// Loop over the pDeadKey lookup table for the locale.
int i ;
for ( i = 0 ; pDeadKey [ i ] . dwBoth ! = 0 ; i + + ) {
WCHAR baseChar = ( WCHAR ) pDeadKey [ i ] . dwBoth ;
WCHAR diacritic = ( WCHAR ) ( pDeadKey [ i ] . dwBoth > > 16 ) ;
// If we locate an extended dead char, set it.
if ( size > = 1 & & baseChar = = buffer [ 0 ] & & diacritic = = deadChar ) {
deadChar = WCH_NONE ;
if ( charCount < = size ) {
memset ( buffer , ( WCHAR ) pDeadKey [ i ] . wchComposed , charCount ) ;
//buffer[i] = (WCHAR) pDeadKey[i].wchComposed;
}
}
}
}
}
return charCount ;
}
int load_input_helper ( ) {
int count = 0 ;
# if defined(_WIN32) && !defined(_WIN64)
if ( is_wow64 ( ) ) {
ptr_padding = sizeof ( void * ) ;
}
# endif
count = refresh_locale_list ( ) ;
logger ( LOG_LEVEL_INFO ,
" %s [%u]: refresh_locale_list() found %i locale(s). \n " ,
__FUNCTION__ , __LINE__ , count ) ;
return count ;
}
// This returns the number of locales that were removed.
int unload_input_helper ( ) {
int count = 0 ;
// Cleanup and free memory from the old list.
KeyboardLocale * locale_item = locale_first ;
while ( locale_item ! = NULL ) {
// Remove the first item from the linked list.
FreeLibrary ( locale_item - > library ) ;
locale_first = locale_item - > next ;
free ( locale_item ) ;
locale_item = locale_first ;
count + + ;
}
// Reset the current local.
locale_current = NULL ;
return count ;
}