key.go (8284B)
1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build windows 6 7 package win32 8 9 import ( 10 "fmt" 11 "syscall" 12 "unicode/utf16" 13 14 "golang.org/x/mobile/event/key" 15 ) 16 17 // convVirtualKeyCode converts a Win32 virtual key code number 18 // into the standard keycodes used by the key package. 19 func convVirtualKeyCode(vKey uint32) key.Code { 20 switch vKey { 21 case 0x01: // VK_LBUTTON left mouse button 22 case 0x02: // VK_RBUTTON right mouse button 23 case 0x03: // VK_CANCEL control-break processing 24 case 0x04: // VK_MBUTTON middle mouse button 25 case 0x05: // VK_XBUTTON1 X1 mouse button 26 case 0x06: // VK_XBUTTON2 X2 mouse button 27 case 0x08: // VK_BACK 28 return key.CodeDeleteBackspace 29 case 0x09: // VK_TAB 30 return key.CodeTab 31 case 0x0C: // VK_CLEAR 32 case 0x0D: // VK_RETURN 33 return key.CodeReturnEnter 34 case 0x10: // VK_SHIFT 35 return key.CodeLeftShift 36 case 0x11: // VK_CONTROL 37 return key.CodeLeftControl 38 case 0x12: // VK_MENU 39 return key.CodeLeftAlt 40 case 0x13: // VK_PAUSE 41 case 0x14: // VK_CAPITAL 42 return key.CodeCapsLock 43 case 0x15: // VK_KANA, VK_HANGUEL, VK_HANGUL 44 case 0x17: // VK_JUNJA 45 case 0x18: // VK_FINA, L 46 case 0x19: // VK_HANJA, VK_KANJI 47 case 0x1B: // VK_ESCAPE 48 return key.CodeEscape 49 case 0x1C: // VK_CONVERT 50 case 0x1D: // VK_NONCONVERT 51 case 0x1E: // VK_ACCEPT 52 case 0x1F: // VK_MODECHANGE 53 case 0x20: // VK_SPACE 54 return key.CodeSpacebar 55 case 0x21: // VK_PRIOR 56 return key.CodePageUp 57 case 0x22: // VK_NEXT 58 return key.CodePageDown 59 case 0x23: // VK_END 60 return key.CodeEnd 61 case 0x24: // VK_HOME 62 return key.CodeHome 63 case 0x25: // VK_LEFT 64 return key.CodeLeftArrow 65 case 0x26: // VK_UP 66 return key.CodeUpArrow 67 case 0x27: // VK_RIGHT 68 return key.CodeRightArrow 69 case 0x28: // VK_DOWN 70 return key.CodeDownArrow 71 case 0x29: // VK_SELECT 72 case 0x2A: // VK_PRINT 73 case 0x2B: // VK_EXECUTE 74 case 0x2C: // VK_SNAPSHOT 75 case 0x2D: // VK_INSERT 76 case 0x2E: // VK_DELETE 77 return key.CodeDeleteForward 78 case 0x2F: // VK_HELP 79 return key.CodeHelp 80 case 0x30: 81 return key.Code0 82 case 0x31: 83 return key.Code1 84 case 0x32: 85 return key.Code2 86 case 0x33: 87 return key.Code3 88 case 0x34: 89 return key.Code4 90 case 0x35: 91 return key.Code5 92 case 0x36: 93 return key.Code6 94 case 0x37: 95 return key.Code7 96 case 0x38: 97 return key.Code8 98 case 0x39: 99 return key.Code9 100 case 0x41: 101 return key.CodeA 102 case 0x42: 103 return key.CodeB 104 case 0x43: 105 return key.CodeC 106 case 0x44: 107 return key.CodeD 108 case 0x45: 109 return key.CodeE 110 case 0x46: 111 return key.CodeF 112 case 0x47: 113 return key.CodeG 114 case 0x48: 115 return key.CodeH 116 case 0x49: 117 return key.CodeI 118 case 0x4A: 119 return key.CodeJ 120 case 0x4B: 121 return key.CodeK 122 case 0x4C: 123 return key.CodeL 124 case 0x4D: 125 return key.CodeM 126 case 0x4E: 127 return key.CodeN 128 case 0x4F: 129 return key.CodeO 130 case 0x50: 131 return key.CodeP 132 case 0x51: 133 return key.CodeQ 134 case 0x52: 135 return key.CodeR 136 case 0x53: 137 return key.CodeS 138 case 0x54: 139 return key.CodeT 140 case 0x55: 141 return key.CodeU 142 case 0x56: 143 return key.CodeV 144 case 0x57: 145 return key.CodeW 146 case 0x58: 147 return key.CodeX 148 case 0x59: 149 return key.CodeY 150 case 0x5A: 151 return key.CodeZ 152 case 0x5B: // VK_LWIN 153 return key.CodeLeftGUI 154 case 0x5C: // VK_RWIN 155 return key.CodeRightGUI 156 case 0x5D: // VK_APPS 157 case 0x5F: // VK_SLEEP 158 case 0x60: // VK_NUMPAD0 159 return key.CodeKeypad0 160 case 0x61: // VK_NUMPAD1 161 return key.CodeKeypad1 162 case 0x62: // VK_NUMPAD2 163 return key.CodeKeypad2 164 case 0x63: // VK_NUMPAD3 165 return key.CodeKeypad3 166 case 0x64: // VK_NUMPAD4 167 return key.CodeKeypad4 168 case 0x65: // VK_NUMPAD5 169 return key.CodeKeypad5 170 case 0x66: // VK_NUMPAD6 171 return key.CodeKeypad6 172 case 0x67: // VK_NUMPAD7 173 return key.CodeKeypad7 174 case 0x68: // VK_NUMPAD8 175 return key.CodeKeypad8 176 case 0x69: // VK_NUMPAD9 177 return key.CodeKeypad9 178 case 0x6A: // VK_MULTIPLY 179 return key.CodeKeypadAsterisk 180 case 0x6B: // VK_ADD 181 return key.CodeKeypadPlusSign 182 case 0x6C: // VK_SEPARATOR 183 case 0x6D: // VK_SUBTRACT 184 return key.CodeKeypadHyphenMinus 185 case 0x6E: // VK_DECIMAL 186 return key.CodeFullStop 187 case 0x6F: // VK_DIVIDE 188 return key.CodeKeypadSlash 189 case 0x70: // VK_F1 190 return key.CodeF1 191 case 0x71: // VK_F2 192 return key.CodeF2 193 case 0x72: // VK_F3 194 return key.CodeF3 195 case 0x73: // VK_F4 196 return key.CodeF4 197 case 0x74: // VK_F5 198 return key.CodeF5 199 case 0x75: // VK_F6 200 return key.CodeF6 201 case 0x76: // VK_F7 202 return key.CodeF7 203 case 0x77: // VK_F8 204 return key.CodeF8 205 case 0x78: // VK_F9 206 return key.CodeF9 207 case 0x79: // VK_F10 208 return key.CodeF10 209 case 0x7A: // VK_F11 210 return key.CodeF11 211 case 0x7B: // VK_F12 212 return key.CodeF12 213 case 0x7C: // VK_F13 214 return key.CodeF13 215 case 0x7D: // VK_F14 216 return key.CodeF14 217 case 0x7E: // VK_F15 218 return key.CodeF15 219 case 0x7F: // VK_F16 220 return key.CodeF16 221 case 0x80: // VK_F17 222 return key.CodeF17 223 case 0x81: // VK_F18 224 return key.CodeF18 225 case 0x82: // VK_F19 226 return key.CodeF19 227 case 0x83: // VK_F20 228 return key.CodeF20 229 case 0x84: // VK_F21 230 return key.CodeF21 231 case 0x85: // VK_F22 232 return key.CodeF22 233 case 0x86: // VK_F23 234 return key.CodeF23 235 case 0x87: // VK_F24 236 return key.CodeF24 237 case 0x90: // VK_NUMLOCK 238 return key.CodeKeypadNumLock 239 case 0x91: // VK_SCROLL 240 case 0xA0: // VK_LSHIFT 241 return key.CodeLeftShift 242 case 0xA1: // VK_RSHIFT 243 return key.CodeRightShift 244 case 0xA2: // VK_LCONTROL 245 return key.CodeLeftControl 246 case 0xA3: // VK_RCONTROL 247 return key.CodeRightControl 248 case 0xA4: // VK_LMENU 249 case 0xA5: // VK_RMENU 250 case 0xA6: // VK_BROWSER_BACK 251 case 0xA7: // VK_BROWSER_FORWARD 252 case 0xA8: // VK_BROWSER_REFRESH 253 case 0xA9: // VK_BROWSER_STOP 254 case 0xAA: // VK_BROWSER_SEARCH 255 case 0xAB: // VK_BROWSER_FAVORITES 256 case 0xAC: // VK_BROWSER_HOME 257 case 0xAD: // VK_VOLUME_MUTE 258 return key.CodeMute 259 case 0xAE: // VK_VOLUME_DOWN 260 return key.CodeVolumeDown 261 case 0xAF: // VK_VOLUME_UP 262 return key.CodeVolumeUp 263 case 0xB0: // VK_MEDIA_NEXT_TRACK 264 case 0xB1: // VK_MEDIA_PREV_TRACK 265 case 0xB2: // VK_MEDIA_STOP 266 case 0xB3: // VK_MEDIA_PLAY_PAUSE 267 case 0xB4: // VK_LAUNCH_MAIL 268 case 0xB5: // VK_LAUNCH_MEDIA_SELECT 269 case 0xB6: // VK_LAUNCH_APP1 270 case 0xB7: // VK_LAUNCH_APP2 271 case 0xBA: // VK_OEM_1 ';:' 272 return key.CodeSemicolon 273 case 0xBB: // VK_OEM_PLUS '+' 274 return key.CodeEqualSign 275 case 0xBC: // VK_OEM_COMMA ',' 276 return key.CodeComma 277 case 0xBD: // VK_OEM_MINUS '-' 278 return key.CodeHyphenMinus 279 case 0xBE: // VK_OEM_PERIOD '.' 280 return key.CodeFullStop 281 case 0xBF: // VK_OEM_2 '/?' 282 return key.CodeSlash 283 case 0xC0: // VK_OEM_3 '`~' 284 return key.CodeGraveAccent 285 case 0xDB: // VK_OEM_4 '[{' 286 return key.CodeLeftSquareBracket 287 case 0xDC: // VK_OEM_5 '\|' 288 return key.CodeBackslash 289 case 0xDD: // VK_OEM_6 ']}' 290 return key.CodeRightSquareBracket 291 case 0xDE: // VK_OEM_7 'single-quote/double-quote' 292 return key.CodeApostrophe 293 case 0xDF: // VK_OEM_8 294 return key.CodeUnknown 295 case 0xE2: // VK_OEM_102 296 case 0xE5: // VK_PROCESSKEY 297 case 0xE7: // VK_PACKET 298 case 0xF6: // VK_ATTN 299 case 0xF7: // VK_CRSEL 300 case 0xF8: // VK_EXSEL 301 case 0xF9: // VK_EREOF 302 case 0xFA: // VK_PLAY 303 case 0xFB: // VK_ZOOM 304 case 0xFC: // VK_NONAME 305 case 0xFD: // VK_PA1 306 case 0xFE: // VK_OEM_CLEAR 307 } 308 return key.CodeUnknown 309 } 310 311 func readRune(vKey uint32, scanCode uint8) rune { 312 var ( 313 keystate [256]byte 314 buf [4]uint16 315 ) 316 if err := _GetKeyboardState(&keystate[0]); err != nil { 317 panic(fmt.Sprintf("win32: %v", err)) 318 } 319 // TODO: cache GetKeyboardLayout result, update on WM_INPUTLANGCHANGE 320 layout := _GetKeyboardLayout(0) 321 ret := _ToUnicodeEx(vKey, uint32(scanCode), &keystate[0], &buf[0], int32(len(buf)), 0, layout) 322 if ret < 1 { 323 return -1 324 } 325 return utf16.Decode(buf[:ret])[0] 326 } 327 328 func sendKeyEvent(hwnd syscall.Handle, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) { 329 e := key.Event{ 330 Rune: readRune(uint32(wParam), uint8(lParam>>16)), 331 Code: convVirtualKeyCode(uint32(wParam)), 332 Modifiers: keyModifiers(), 333 } 334 switch uMsg { 335 case _WM_KEYDOWN: 336 const prevMask = 1 << 30 337 if repeat := lParam&prevMask == prevMask; repeat { 338 e.Direction = key.DirNone 339 } else { 340 e.Direction = key.DirPress 341 } 342 case _WM_KEYUP: 343 e.Direction = key.DirRelease 344 default: 345 panic(fmt.Sprintf("win32: unexpected key message: %d", uMsg)) 346 } 347 348 KeyEvent(hwnd, e) 349 return 0 350 }