diff --git a/input/driver_windows.go b/input/driver_windows.go index 0b3f40ea..f940ca53 100644 --- a/input/driver_windows.go +++ b/input/driver_windows.go @@ -131,17 +131,11 @@ func parseConInputEvent(event coninput.InputRecord, ps *coninput.ButtonState) Ev return event } - // Get active keyboard layout - fgWin := windows.GetForegroundWindow() - fgThread, err := windows.GetWindowThreadProcessId(fgWin, nil) - if err != nil { - return event - } - - layout := termwindows.GetKeyboardLayout(fgThread) - if layout == windows.InvalidHandle { - return event - } + // Always use US layout for translation + // This is to follow the behavior of the Kitty Keyboard base layout + // feature :eye_roll: + // https://learn.microsoft.com/en-us/windows-hardware/manufacture/desktop/windows-language-pack-default-values?view=windows-11 + const usLayout = 0x409 // Translate key to rune var keyState [256]byte @@ -154,7 +148,7 @@ func parseConInputEvent(event coninput.InputRecord, ps *coninput.ButtonState) Ev &utf16Buf[0], int32(len(utf16Buf)), dontChangeKernelKeyboardLayout, - layout, + usLayout, ) // -1 indicates a dead key @@ -169,7 +163,7 @@ func parseConInputEvent(event coninput.InputRecord, ps *coninput.ButtonState) Ev return event } - key.BaseRune = runes[0] + key.baseRune = runes[0] if e.KeyDown { return KeyDownEvent(key) } diff --git a/input/key.go b/input/key.go index cbf43952..6b9d7d37 100644 --- a/input/key.go +++ b/input/key.go @@ -179,18 +179,51 @@ const ( // Key represents a key event. type Key struct { - Sym KeySym - Rune rune - AltRune rune - BaseRune rune + // Sym is a special key, like enter, tab, backspace, and so on. + Sym KeySym + + // Mod is a modifier key, like ctrl, alt, and so on. + Mod KeyMod + + // Rune is the actual character received. If the user presses shift+a, the + // Rune will be 'A'. + Rune rune + + // AltRune is the actual, unshifted key pressed by the user. For example, + // if the user presses shift+a, or caps lock is on, the AltRune will be + // 'a'. + // + // In the case of non-latin keyboards, like Arabic, AltRune is the + // unshifted key on the keyboard. + // + // This is only available with the Kitty Keyboard Protocol or the Windows + // Console API. + AltRune rune + + // baseRune is the key pressed according to the standard PC-101 key layout. + // On internaltional keyboards, this is the key that would be pressed if + // the keyboard was set to US layout. + // + // For example, if the user presses 'q' on a French AZERTY keyboard, the + // baseRune will be 'q'. + // + // This is only available with the Kitty Keyboard Protocol or the Windows + // Console API. + baseRune rune + + // IsRepeat indicates whether the key is being held down and sending events + // repeatedly. + // + // This is only available with the Kitty Keyboard Protocol or the Windows + // Console API. IsRepeat bool - Mod KeyMod } // KeyDownEvent represents a key down event. type KeyDownEvent Key -// String implements fmt.Stringer. +// String implements fmt.Stringer and is quite useful for matching key +// events. For details, on what this returns see [Key.String]. func (k KeyDownEvent) String() string { return Key(k).String() } @@ -198,12 +231,27 @@ func (k KeyDownEvent) String() string { // KeyUpEvent represents a key up event. type KeyUpEvent Key -// String implements fmt.Stringer. +// String implements fmt.Stringer and is quite useful for matching complex key +// events. For details, on what this returns see [Key.String]. func (k KeyUpEvent) String() string { return Key(k).String() } -// String implements fmt.Stringer. +// String implements fmt.Stringer and is used to convert a key to a string. +// While less type safe than looking at the individual fields, it will usually +// be more convenient and readable to use this method when matching against +// keys. +// +// Note that modifier keys are always printed in the following order: +// - ctrl +// - alt +// - shift +// - meta +// - hyper +// - super +// +// For example, you'll always see "ctrl+shift+alt+a" and never +// "shift+ctrl+alt+a". func (k Key) String() string { var s string if k.Mod.IsCtrl() && k.Sym != KeyLeftCtrl && k.Sym != KeyRightCtrl { @@ -232,10 +280,10 @@ func (k Key) String() string { } return string(r) } - if k.BaseRune != 0 { - // If a BaseRune is present, use it to represent a key using the standard + if k.baseRune != 0 { + // If a baseRune is present, use it to represent a key using the standard // PC-101 key layout. - s += runeStr(k.BaseRune) + s += runeStr(k.baseRune) } else if k.AltRune != 0 { // Otherwise, use the AltRune aka the non-shifted one if present. s += runeStr(k.AltRune) @@ -248,7 +296,8 @@ func (k Key) String() string { return s } -// String implements fmt.Stringer. +// String implements fmt.Stringer and prints the string representation of a of +// a Symbol key. func (k KeySym) String() string { s, ok := keySymString[k] if !ok { diff --git a/input/kitty.go b/input/kitty.go index e9edbfb8..01e04e92 100644 --- a/input/kitty.go +++ b/input/kitty.go @@ -236,7 +236,7 @@ func parseKittyKeyboard(csi *ansi.CsiSequence) Event { // PC-101 key layout codepoint. // This is useful to create an unambiguous mapping of keys // when using a different language layout. - key.BaseRune = b + key.baseRune = b } fallthrough case 2: