github.com/rajveermalviya/gamen@v0.1.2-0.20220930195403-9be15877c1aa/internal/win32/keycodes.go (about) 1 //go:build windows 2 3 package win32 4 5 import ( 6 "sync/atomic" 7 "unicode/utf16" 8 "unsafe" 9 10 "github.com/rajveermalviya/gamen/events" 11 "github.com/rajveermalviya/gamen/internal/win32/procs" 12 ) 13 14 func mapVK(vk uintptr, scancode uintptr, extended bool) events.VirtualKey { 15 switch vk { 16 case procs.VK_CANCEL: 17 return events.VirtualKeyCancel 18 case procs.VK_HELP: 19 return events.VirtualKeyHelp 20 case procs.VK_BACK: 21 return events.VirtualKeyBackSpace 22 case procs.VK_TAB: 23 return events.VirtualKeyTab 24 case procs.VK_CLEAR: 25 return events.VirtualKeyClear 26 case procs.VK_RETURN: 27 return events.VirtualKeyReturn 28 case procs.VK_PAUSE: 29 return events.VirtualKeyPause 30 case procs.VK_CAPITAL: 31 return events.VirtualKeyCapsLock 32 case procs.VK_KANA: 33 return events.VirtualKeyKana 34 case procs.VK_JUNJA: 35 return events.VirtualKeyJunja 36 case procs.VK_FINAL: 37 return events.VirtualKeyFinal 38 case procs.VK_KANJI: 39 return events.VirtualKeyKanji 40 case procs.VK_ESCAPE: 41 return events.VirtualKeyEscape 42 case procs.VK_CONVERT: 43 return events.VirtualKeyConvert 44 case procs.VK_NONCONVERT: 45 return events.VirtualKeyNonconvert 46 case procs.VK_ACCEPT: 47 return events.VirtualKeyAccept 48 case procs.VK_MODECHANGE: 49 return events.VirtualKeyModechange 50 case procs.VK_SPACE: 51 return events.VirtualKeySpace 52 case procs.VK_PRIOR: 53 return events.VirtualKeyPageUp 54 case procs.VK_NEXT: 55 return events.VirtualKeyPageDown 56 case procs.VK_END: 57 return events.VirtualKeyEnd 58 case procs.VK_HOME: 59 return events.VirtualKeyHome 60 case procs.VK_LEFT: 61 return events.VirtualKeyLeft 62 case procs.VK_UP: 63 return events.VirtualKeyUp 64 case procs.VK_RIGHT: 65 return events.VirtualKeyRight 66 case procs.VK_DOWN: 67 return events.VirtualKeyDown 68 case procs.VK_SELECT: 69 return events.VirtualKeySelect 70 case procs.VK_PRINT: 71 return events.VirtualKeyPrint 72 case procs.VK_EXECUTE: 73 return events.VirtualKeyExecute 74 case procs.VK_INSERT: 75 return events.VirtualKeyInsert 76 case procs.VK_DELETE: 77 return events.VirtualKeyDelete 78 case procs.VK_0: 79 return events.VirtualKey0 80 case procs.VK_1: 81 return events.VirtualKey1 82 case procs.VK_2: 83 return events.VirtualKey2 84 case procs.VK_3: 85 return events.VirtualKey3 86 case procs.VK_4: 87 return events.VirtualKey4 88 case procs.VK_5: 89 return events.VirtualKey5 90 case procs.VK_6: 91 return events.VirtualKey6 92 case procs.VK_7: 93 return events.VirtualKey7 94 case procs.VK_8: 95 return events.VirtualKey8 96 case procs.VK_9: 97 return events.VirtualKey9 98 case procs.VK_A: 99 return events.VirtualKeyA 100 case procs.VK_B: 101 return events.VirtualKeyB 102 case procs.VK_C: 103 return events.VirtualKeyC 104 case procs.VK_D: 105 return events.VirtualKeyD 106 case procs.VK_E: 107 return events.VirtualKeyE 108 case procs.VK_F: 109 return events.VirtualKeyF 110 case procs.VK_G: 111 return events.VirtualKeyG 112 case procs.VK_H: 113 return events.VirtualKeyH 114 case procs.VK_I: 115 return events.VirtualKeyI 116 case procs.VK_J: 117 return events.VirtualKeyJ 118 case procs.VK_K: 119 return events.VirtualKeyK 120 case procs.VK_L: 121 return events.VirtualKeyL 122 case procs.VK_M: 123 return events.VirtualKeyM 124 case procs.VK_N: 125 return events.VirtualKeyN 126 case procs.VK_O: 127 return events.VirtualKeyO 128 case procs.VK_P: 129 return events.VirtualKeyP 130 case procs.VK_Q: 131 return events.VirtualKeyQ 132 case procs.VK_R: 133 return events.VirtualKeyR 134 case procs.VK_S: 135 return events.VirtualKeyS 136 case procs.VK_T: 137 return events.VirtualKeyT 138 case procs.VK_U: 139 return events.VirtualKeyU 140 case procs.VK_V: 141 return events.VirtualKeyV 142 case procs.VK_W: 143 return events.VirtualKeyW 144 case procs.VK_X: 145 return events.VirtualKeyX 146 case procs.VK_Y: 147 return events.VirtualKeyY 148 case procs.VK_Z: 149 return events.VirtualKeyZ 150 case procs.VK_LWIN: 151 return events.VirtualKeyLWin 152 case procs.VK_RWIN: 153 return events.VirtualKeyRWin 154 case procs.VK_APPS: 155 return events.VirtualKeyContextMenu 156 case procs.VK_SLEEP: 157 return events.VirtualKeySleep 158 case procs.VK_NUMPAD0: 159 return events.VirtualKeyNumpad0 160 case procs.VK_NUMPAD1: 161 return events.VirtualKeyNumpad1 162 case procs.VK_NUMPAD2: 163 return events.VirtualKeyNumpad2 164 case procs.VK_NUMPAD3: 165 return events.VirtualKeyNumpad3 166 case procs.VK_NUMPAD4: 167 return events.VirtualKeyNumpad4 168 case procs.VK_NUMPAD5: 169 return events.VirtualKeyNumpad5 170 case procs.VK_NUMPAD6: 171 return events.VirtualKeyNumpad6 172 case procs.VK_NUMPAD7: 173 return events.VirtualKeyNumpad7 174 case procs.VK_NUMPAD8: 175 return events.VirtualKeyNumpad8 176 case procs.VK_NUMPAD9: 177 return events.VirtualKeyNumpad9 178 case procs.VK_MULTIPLY: 179 return events.VirtualKeyMultiply 180 case procs.VK_ADD: 181 return events.VirtualKeyAdd 182 case procs.VK_SUBTRACT: 183 return events.VirtualKeySubtract 184 case procs.VK_DECIMAL: 185 return events.VirtualKeyDecimal 186 case procs.VK_DIVIDE: 187 return events.VirtualKeyDivide 188 case procs.VK_F1: 189 return events.VirtualKeyF1 190 case procs.VK_F2: 191 return events.VirtualKeyF2 192 case procs.VK_F3: 193 return events.VirtualKeyF3 194 case procs.VK_F4: 195 return events.VirtualKeyF4 196 case procs.VK_F5: 197 return events.VirtualKeyF5 198 case procs.VK_F6: 199 return events.VirtualKeyF6 200 case procs.VK_F7: 201 return events.VirtualKeyF7 202 case procs.VK_F8: 203 return events.VirtualKeyF8 204 case procs.VK_F9: 205 return events.VirtualKeyF9 206 case procs.VK_F10: 207 return events.VirtualKeyF10 208 case procs.VK_F11: 209 return events.VirtualKeyF11 210 case procs.VK_F12: 211 return events.VirtualKeyF12 212 case procs.VK_F13: 213 return events.VirtualKeyF13 214 case procs.VK_F14: 215 return events.VirtualKeyF14 216 case procs.VK_F15: 217 return events.VirtualKeyF15 218 case procs.VK_F16: 219 return events.VirtualKeyF16 220 case procs.VK_F17: 221 return events.VirtualKeyF17 222 case procs.VK_F18: 223 return events.VirtualKeyF18 224 case procs.VK_F19: 225 return events.VirtualKeyF19 226 case procs.VK_F20: 227 return events.VirtualKeyF20 228 case procs.VK_F21: 229 return events.VirtualKeyF21 230 case procs.VK_F22: 231 return events.VirtualKeyF22 232 case procs.VK_F23: 233 return events.VirtualKeyF23 234 case procs.VK_F24: 235 return events.VirtualKeyF24 236 case procs.VK_NUMLOCK: 237 return events.VirtualKeyNumLock 238 case procs.VK_SCROLL: 239 return events.VirtualKeyScrollLock 240 case procs.VK_VOLUME_MUTE: 241 return events.VirtualKeyVolumeMute 242 case procs.VK_VOLUME_DOWN: 243 return events.VirtualKeyVolumeDown 244 case procs.VK_VOLUME_UP: 245 return events.VirtualKeyVolumeUp 246 247 case procs.VK_SHIFT: 248 switch procs.MapVirtualKeyW(scancode, procs.MAPVK_VSC_TO_VK_EX) { 249 case procs.VK_LSHIFT: 250 return events.VirtualKeyLShift 251 case procs.VK_RSHIFT: 252 return events.VirtualKeyRShift 253 } 254 255 case procs.VK_CONTROL: 256 if extended { 257 return events.VirtualKeyRControl 258 } else { 259 return events.VirtualKeyLControl 260 } 261 262 case procs.VK_MENU: 263 if extended { 264 if layoutUsesAltgr() { 265 return events.VirtualKeyAltgr 266 } else { 267 return events.VirtualKeyRAlt 268 } 269 } else { 270 return events.VirtualKeyLAlt 271 } 272 273 default: 274 switch rune(procs.MapVirtualKeyW(vk, procs.MAPVK_VK_TO_CHAR) & 0x7FFF) { 275 case '-': 276 return events.VirtualKeyHyphenMinus 277 case ';': 278 return events.VirtualKeySemicolon 279 case '=': 280 return events.VirtualKeyEquals 281 case ',': 282 return events.VirtualKeyComma 283 case '.': 284 return events.VirtualKeyPeriod 285 case '/': 286 return events.VirtualKeySlash 287 case '`': 288 return events.VirtualKeyBackQuote 289 case '[': 290 return events.VirtualKeyOpenBracket 291 case ']': 292 return events.VirtualKeyCloseBracket 293 case '\\': 294 return events.VirtualKeyBackSlash 295 case '\'': 296 return events.VirtualKeyQuote 297 } 298 } 299 300 return events.VirtualKey(vk) 301 } 302 303 func getChar(keyboardState *[256]byte, vKey uintptr, hkl uintptr) rune { 304 var unicodeBytes [5]uint16 305 l := procs.ToUnicodeEx( 306 vKey, 307 0, 308 uintptr(unsafe.Pointer(&keyboardState)), 309 uintptr(unsafe.Pointer(&unicodeBytes)), 310 uintptr(len(unicodeBytes)), 311 0, 312 hkl, 313 ) 314 if l >= 1 { 315 r := utf16.Decode(unicodeBytes[:l]) 316 if len(r) > 0 { 317 return r[0] 318 } 319 } 320 return -1 321 } 322 323 var currentLayout uintptr 324 var usesAltGr uint32 325 326 func layoutUsesAltgr() bool { 327 hkl := procs.GetKeyboardLayout(0) 328 oldHkl := atomic.SwapUintptr(¤tLayout, hkl) 329 330 if hkl == oldHkl { 331 return atomic.LoadUint32(&usesAltGr) != 0 332 } 333 334 var keyboardStateAltgr [256]byte 335 var keyboardStateEmpty [256]byte 336 337 keyboardStateAltgr[procs.VK_MENU] = 0x80 338 keyboardStateAltgr[procs.VK_CONTROL] = 0x80 339 340 for vKey := uintptr(0); vKey < 255; vKey++ { 341 keyNoAltgr := getChar(&keyboardStateEmpty, vKey, hkl) 342 keyAltgr := getChar(&keyboardStateAltgr, vKey, hkl) 343 if keyAltgr != -1 && keyNoAltgr != -1 { 344 if keyAltgr != keyNoAltgr { 345 atomic.StoreUint32(&usesAltGr, 1) 346 return true 347 } 348 } 349 } 350 351 atomic.StoreUint32(&usesAltGr, 0) 352 return false 353 }