282 lines
4.1 KiB
Go
282 lines
4.1 KiB
Go
package input
|
|
|
|
import (
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
type Scancode uint16
|
|
|
|
const ScancodeCount = 512
|
|
|
|
const KeyUnknown Scancode = 0
|
|
|
|
const (
|
|
KeyA Scancode = iota + 4
|
|
KeyB
|
|
KeyC
|
|
KeyD
|
|
KeyE
|
|
KeyF
|
|
KeyG
|
|
KeyH
|
|
KeyI
|
|
KeyJ
|
|
KeyK
|
|
KeyL
|
|
KeyM
|
|
KeyN
|
|
KeyO
|
|
KeyP
|
|
KeyQ
|
|
KeyR
|
|
KeyS
|
|
KeyT
|
|
KeyU
|
|
KeyV
|
|
KeyW
|
|
KeyX
|
|
KeyY
|
|
KeyZ
|
|
Key1
|
|
Key2
|
|
Key3
|
|
Key4
|
|
Key5
|
|
Key6
|
|
Key7
|
|
Key8
|
|
Key9
|
|
Key0
|
|
KeyEnter
|
|
KeyEscape
|
|
KeyBackspace
|
|
KeyTab
|
|
KeySpace
|
|
KeyMinus
|
|
KeyEquals
|
|
KeyLeftBracket
|
|
KeyRightBracket
|
|
KeyBackslash
|
|
KeyNonUSHash
|
|
KeySemicolon
|
|
KeyApostrophe
|
|
KeyGrave
|
|
KeyComma
|
|
KeyPeriod
|
|
KeySlash
|
|
KeyCapsLock
|
|
KeyF1
|
|
KeyF2
|
|
KeyF3
|
|
KeyF4
|
|
KeyF5
|
|
KeyF6
|
|
KeyF7
|
|
KeyF8
|
|
KeyF9
|
|
KeyF10
|
|
KeyF11
|
|
KeyF12
|
|
KeyPrintScreen
|
|
KeyScrollLock
|
|
KeyPause
|
|
KeyInsert
|
|
KeyHome
|
|
KeyPageUp
|
|
KeyDelete
|
|
KeyEnd
|
|
KeyPageDown
|
|
KeyRight
|
|
KeyLeft
|
|
KeyDown
|
|
KeyUp
|
|
KeyNumLock
|
|
KeyKPDivide
|
|
KeyKPMultiply
|
|
KeyKPMinus
|
|
KeyKPPlus
|
|
KeyKPEnter
|
|
KeyKP1
|
|
KeyKP2
|
|
KeyKP3
|
|
KeyKP4
|
|
KeyKP5
|
|
KeyKP6
|
|
KeyKP7
|
|
KeyKP8
|
|
KeyKP9
|
|
KeyKP0
|
|
KeyKPPeriod
|
|
)
|
|
|
|
const (
|
|
KeyLCtrl Scancode = iota + 224
|
|
KeyLShift
|
|
KeyLAlt
|
|
KeyLGUI
|
|
KeyRCtrl
|
|
KeyRShift
|
|
KeyRAlt
|
|
KeyRGUI
|
|
)
|
|
|
|
const (
|
|
letterNames = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
digitNames = "1234567890"
|
|
)
|
|
|
|
var fkeyNames = [...]string{
|
|
"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12",
|
|
}
|
|
|
|
var namedKeys = map[Scancode]string{
|
|
KeyEnter: "Enter",
|
|
KeyEscape: "Escape",
|
|
KeyBackspace: "Backspace",
|
|
KeyTab: "Tab",
|
|
KeySpace: "Space",
|
|
KeyMinus: "-",
|
|
KeyEquals: "=",
|
|
KeyLeftBracket: "[",
|
|
KeyRightBracket: "]",
|
|
KeyBackslash: "\\",
|
|
KeyNonUSHash: "#",
|
|
KeySemicolon: ";",
|
|
KeyApostrophe: "'",
|
|
KeyGrave: "`",
|
|
KeyComma: ",",
|
|
KeyPeriod: ".",
|
|
KeySlash: "/",
|
|
KeyCapsLock: "CapsLock",
|
|
KeyPrintScreen: "PrintScreen",
|
|
KeyScrollLock: "ScrollLock",
|
|
KeyPause: "Pause",
|
|
KeyInsert: "Insert",
|
|
KeyHome: "Home",
|
|
KeyPageUp: "PageUp",
|
|
KeyDelete: "Delete",
|
|
KeyEnd: "End",
|
|
KeyPageDown: "PageDown",
|
|
KeyRight: "Right",
|
|
KeyLeft: "Left",
|
|
KeyDown: "Down",
|
|
KeyUp: "Up",
|
|
KeyNumLock: "NumLock",
|
|
KeyKPDivide: "KP/",
|
|
KeyKPMultiply: "KP*",
|
|
KeyKPMinus: "KP-",
|
|
KeyKPPlus: "KP+",
|
|
KeyKPEnter: "KPEnter",
|
|
KeyKPPeriod: "KP.",
|
|
KeyLCtrl: "LCtrl",
|
|
KeyLShift: "LShift",
|
|
KeyLAlt: "LAlt",
|
|
KeyLGUI: "LGUI",
|
|
KeyRCtrl: "RCtrl",
|
|
KeyRShift: "RShift",
|
|
KeyRAlt: "RAlt",
|
|
KeyRGUI: "RGUI",
|
|
}
|
|
|
|
func PrimaryMod() Mods {
|
|
if runtime.GOOS == "darwin" {
|
|
return ModSuper
|
|
}
|
|
return ModCtrl
|
|
}
|
|
|
|
func WordMod() Mods {
|
|
if runtime.GOOS == "darwin" {
|
|
return ModAlt
|
|
}
|
|
return ModCtrl
|
|
}
|
|
|
|
func (m Mods) Primary() bool {
|
|
return m&PrimaryMod() != 0
|
|
}
|
|
|
|
func (s Scancode) Valid() bool {
|
|
return s != KeyUnknown && int(s) < ScancodeCount
|
|
}
|
|
|
|
func (s Scancode) String() string {
|
|
switch {
|
|
case s >= KeyA && s <= KeyZ:
|
|
i := int(s - KeyA)
|
|
return letterNames[i : i+1]
|
|
case s >= Key1 && s <= Key0:
|
|
i := int(s - Key1)
|
|
return digitNames[i : i+1]
|
|
case s >= KeyF1 && s <= KeyF12:
|
|
return fkeyNames[s-KeyF1]
|
|
case s >= KeyKP1 && s <= KeyKP0:
|
|
i := int(s - KeyKP1)
|
|
return "KP" + digitNames[i:i+1]
|
|
}
|
|
if n, ok := namedKeys[s]; ok {
|
|
return n
|
|
}
|
|
return "Unknown"
|
|
}
|
|
|
|
type Keycode uint32
|
|
|
|
const keycodeScancodeBit Keycode = 1 << 30
|
|
|
|
func (k Keycode) IsScancodeBased() bool {
|
|
return k&keycodeScancodeBit != 0
|
|
}
|
|
|
|
func (k Keycode) Rune() (rune, bool) {
|
|
if k == 0 || k.IsScancodeBased() {
|
|
return 0, false
|
|
}
|
|
return rune(k), true
|
|
}
|
|
|
|
type Mods uint16
|
|
|
|
const (
|
|
ModShift Mods = 1 << iota
|
|
ModCtrl
|
|
ModAlt
|
|
ModSuper
|
|
ModCaps
|
|
ModNum
|
|
)
|
|
|
|
var modNames = [...]struct {
|
|
bit Mods
|
|
name string
|
|
}{
|
|
{ModShift, "shift"},
|
|
{ModCtrl, "ctrl"},
|
|
{ModAlt, "alt"},
|
|
{ModSuper, "super"},
|
|
{ModCaps, "caps"},
|
|
{ModNum, "num"},
|
|
}
|
|
|
|
func (m Mods) Has(o Mods) bool {
|
|
return m&o == o
|
|
}
|
|
|
|
func (m Mods) String() string {
|
|
if m == 0 {
|
|
return "none"
|
|
}
|
|
var sb strings.Builder
|
|
for _, mod := range modNames {
|
|
if !m.Has(mod.bit) {
|
|
continue
|
|
}
|
|
if sb.Len() > 0 {
|
|
sb.WriteByte('+')
|
|
}
|
|
sb.WriteString(mod.name)
|
|
}
|
|
return sb.String()
|
|
}
|