blob: cb8f6e52e0567f877e3ccf71a99def3fa5d690e9 [file] [log] [blame]
// 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.
// +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
}