// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build windows // +build windows package win32 import ( "fmt" "syscall" "unicode/utf16" "golang.org/x/mobile/event/key" ) // convVirtualKeyCode converts a Win32 virtual key code number // into the standard keycodes used by the key package. func convVirtualKeyCode(vKey uint32) key.Code { switch vKey { case 0x01: // VK_LBUTTON left mouse button case 0x02: // VK_RBUTTON right mouse button case 0x03: // VK_CANCEL control-break processing case 0x04: // VK_MBUTTON middle mouse button case 0x05: // VK_XBUTTON1 X1 mouse button case 0x06: // VK_XBUTTON2 X2 mouse button case 0x08: // VK_BACK return key.CodeDeleteBackspace case 0x09: // VK_TAB return key.CodeTab case 0x0C: // VK_CLEAR case 0x0D: // VK_RETURN return key.CodeReturnEnter case 0x10: // VK_SHIFT return key.CodeLeftShift case 0x11: // VK_CONTROL return key.CodeLeftControl case 0x12: // VK_MENU return key.CodeLeftAlt case 0x13: // VK_PAUSE case 0x14: // VK_CAPITAL return key.CodeCapsLock case 0x15: // VK_KANA, VK_HANGUEL, VK_HANGUL case 0x17: // VK_JUNJA case 0x18: // VK_FINA, L case 0x19: // VK_HANJA, VK_KANJI case 0x1B: // VK_ESCAPE return key.CodeEscape case 0x1C: // VK_CONVERT case 0x1D: // VK_NONCONVERT case 0x1E: // VK_ACCEPT case 0x1F: // VK_MODECHANGE case 0x20: // VK_SPACE return key.CodeSpacebar case 0x21: // VK_PRIOR return key.CodePageUp case 0x22: // VK_NEXT return key.CodePageDown case 0x23: // VK_END return key.CodeEnd case 0x24: // VK_HOME return key.CodeHome case 0x25: // VK_LEFT return key.CodeLeftArrow case 0x26: // VK_UP return key.CodeUpArrow case 0x27: // VK_RIGHT return key.CodeRightArrow case 0x28: // VK_DOWN return key.CodeDownArrow case 0x29: // VK_SELECT case 0x2A: // VK_PRINT case 0x2B: // VK_EXECUTE case 0x2C: // VK_SNAPSHOT case 0x2D: // VK_INSERT case 0x2E: // VK_DELETE return key.CodeDeleteForward case 0x2F: // VK_HELP return key.CodeHelp case 0x30: return key.Code0 case 0x31: return key.Code1 case 0x32: return key.Code2 case 0x33: return key.Code3 case 0x34: return key.Code4 case 0x35: return key.Code5 case 0x36: return key.Code6 case 0x37: return key.Code7 case 0x38: return key.Code8 case 0x39: return key.Code9 case 0x41: return key.CodeA case 0x42: return key.CodeB case 0x43: return key.CodeC case 0x44: return key.CodeD case 0x45: return key.CodeE case 0x46: return key.CodeF case 0x47: return key.CodeG case 0x48: return key.CodeH case 0x49: return key.CodeI case 0x4A: return key.CodeJ case 0x4B: return key.CodeK case 0x4C: return key.CodeL case 0x4D: return key.CodeM case 0x4E: return key.CodeN case 0x4F: return key.CodeO case 0x50: return key.CodeP case 0x51: return key.CodeQ case 0x52: return key.CodeR case 0x53: return key.CodeS case 0x54: return key.CodeT case 0x55: return key.CodeU case 0x56: return key.CodeV case 0x57: return key.CodeW case 0x58: return key.CodeX case 0x59: return key.CodeY case 0x5A: return key.CodeZ case 0x5B: // VK_LWIN return key.CodeLeftGUI case 0x5C: // VK_RWIN return key.CodeRightGUI case 0x5D: // VK_APPS case 0x5F: // VK_SLEEP case 0x60: // VK_NUMPAD0 return key.CodeKeypad0 case 0x61: // VK_NUMPAD1 return key.CodeKeypad1 case 0x62: // VK_NUMPAD2 return key.CodeKeypad2 case 0x63: // VK_NUMPAD3 return key.CodeKeypad3 case 0x64: // VK_NUMPAD4 return key.CodeKeypad4 case 0x65: // VK_NUMPAD5 return key.CodeKeypad5 case 0x66: // VK_NUMPAD6 return key.CodeKeypad6 case 0x67: // VK_NUMPAD7 return key.CodeKeypad7 case 0x68: // VK_NUMPAD8 return key.CodeKeypad8 case 0x69: // VK_NUMPAD9 return key.CodeKeypad9 case 0x6A: // VK_MULTIPLY return key.CodeKeypadAsterisk case 0x6B: // VK_ADD return key.CodeKeypadPlusSign case 0x6C: // VK_SEPARATOR case 0x6D: // VK_SUBTRACT return key.CodeKeypadHyphenMinus case 0x6E: // VK_DECIMAL return key.CodeFullStop case 0x6F: // VK_DIVIDE return key.CodeKeypadSlash case 0x70: // VK_F1 return key.CodeF1 case 0x71: // VK_F2 return key.CodeF2 case 0x72: // VK_F3 return key.CodeF3 case 0x73: // VK_F4 return key.CodeF4 case 0x74: // VK_F5 return key.CodeF5 case 0x75: // VK_F6 return key.CodeF6 case 0x76: // VK_F7 return key.CodeF7 case 0x77: // VK_F8 return key.CodeF8 case 0x78: // VK_F9 return key.CodeF9 case 0x79: // VK_F10 return key.CodeF10 case 0x7A: // VK_F11 return key.CodeF11 case 0x7B: // VK_F12 return key.CodeF12 case 0x7C: // VK_F13 return key.CodeF13 case 0x7D: // VK_F14 return key.CodeF14 case 0x7E: // VK_F15 return key.CodeF15 case 0x7F: // VK_F16 return key.CodeF16 case 0x80: // VK_F17 return key.CodeF17 case 0x81: // VK_F18 return key.CodeF18 case 0x82: // VK_F19 return key.CodeF19 case 0x83: // VK_F20 return key.CodeF20 case 0x84: // VK_F21 return key.CodeF21 case 0x85: // VK_F22 return key.CodeF22 case 0x86: // VK_F23 return key.CodeF23 case 0x87: // VK_F24 return key.CodeF24 case 0x90: // VK_NUMLOCK return key.CodeKeypadNumLock case 0x91: // VK_SCROLL case 0xA0: // VK_LSHIFT return key.CodeLeftShift case 0xA1: // VK_RSHIFT return key.CodeRightShift case 0xA2: // VK_LCONTROL return key.CodeLeftControl case 0xA3: // VK_RCONTROL return key.CodeRightControl case 0xA4: // VK_LMENU case 0xA5: // VK_RMENU case 0xA6: // VK_BROWSER_BACK case 0xA7: // VK_BROWSER_FORWARD case 0xA8: // VK_BROWSER_REFRESH case 0xA9: // VK_BROWSER_STOP case 0xAA: // VK_BROWSER_SEARCH case 0xAB: // VK_BROWSER_FAVORITES case 0xAC: // VK_BROWSER_HOME case 0xAD: // VK_VOLUME_MUTE return key.CodeMute case 0xAE: // VK_VOLUME_DOWN return key.CodeVolumeDown case 0xAF: // VK_VOLUME_UP return key.CodeVolumeUp case 0xB0: // VK_MEDIA_NEXT_TRACK case 0xB1: // VK_MEDIA_PREV_TRACK case 0xB2: // VK_MEDIA_STOP case 0xB3: // VK_MEDIA_PLAY_PAUSE case 0xB4: // VK_LAUNCH_MAIL case 0xB5: // VK_LAUNCH_MEDIA_SELECT case 0xB6: // VK_LAUNCH_APP1 case 0xB7: // VK_LAUNCH_APP2 case 0xBA: // VK_OEM_1 ';:' return key.CodeSemicolon case 0xBB: // VK_OEM_PLUS '+' return key.CodeEqualSign case 0xBC: // VK_OEM_COMMA ',' return key.CodeComma case 0xBD: // VK_OEM_MINUS '-' return key.CodeHyphenMinus case 0xBE: // VK_OEM_PERIOD '.' return key.CodeFullStop case 0xBF: // VK_OEM_2 '/?' return key.CodeSlash case 0xC0: // VK_OEM_3 '`~' return key.CodeGraveAccent case 0xDB: // VK_OEM_4 '[{' return key.CodeLeftSquareBracket case 0xDC: // VK_OEM_5 '\|' return key.CodeBackslash case 0xDD: // VK_OEM_6 ']}' return key.CodeRightSquareBracket case 0xDE: // VK_OEM_7 'single-quote/double-quote' return key.CodeApostrophe case 0xDF: // VK_OEM_8 return key.CodeUnknown case 0xE2: // VK_OEM_102 case 0xE5: // VK_PROCESSKEY case 0xE7: // VK_PACKET case 0xF6: // VK_ATTN case 0xF7: // VK_CRSEL case 0xF8: // VK_EXSEL case 0xF9: // VK_EREOF case 0xFA: // VK_PLAY case 0xFB: // VK_ZOOM case 0xFC: // VK_NONAME case 0xFD: // VK_PA1 case 0xFE: // VK_OEM_CLEAR } return key.CodeUnknown } func readRune(vKey uint32, scanCode uint8) rune { var ( keystate [256]byte buf [4]uint16 ) if err := _GetKeyboardState(&keystate[0]); err != nil { panic(fmt.Sprintf("win32: %v", err)) } // TODO: cache GetKeyboardLayout result, update on WM_INPUTLANGCHANGE layout := _GetKeyboardLayout(0) ret := _ToUnicodeEx(vKey, uint32(scanCode), &keystate[0], &buf[0], int32(len(buf)), 0, layout) if ret < 1 { return -1 } return utf16.Decode(buf[:ret])[0] } func sendKeyEvent(hwnd syscall.Handle, uMsg uint32, wParam, lParam uintptr) (lResult uintptr) { e := key.Event{ Rune: readRune(uint32(wParam), uint8(lParam>>16)), Code: convVirtualKeyCode(uint32(wParam)), Modifiers: keyModifiers(), } switch uMsg { case _WM_KEYDOWN, _WM_SYSKEYDOWN: const prevMask = 1 << 30 if repeat := lParam&prevMask == prevMask; repeat { e.Direction = key.DirNone } else { e.Direction = key.DirPress } case _WM_KEYUP, _WM_SYSKEYUP: e.Direction = key.DirRelease default: panic(fmt.Sprintf("win32: unexpected key message: %d", uMsg)) } KeyEvent(hwnd, e) return 0 }