gohook/hook/windows/input_c.h
2024-06-16 04:44:20 +08:00

824 lines
35 KiB
C

/* 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.
*/
#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) {
// logger(LOG_LEVEL_WARN, "%s [%u]: EXTD2, vk_code %li\n",
// __FUNCTION__, __LINE__, vk_code);
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;
}