Files
cclip/vendor/github.com/charmbracelet/x/input/kitty.go
PhatPhuckDave 3c5e991ec5 Add vendor
Specifically because I want to modify a dependency
2024-08-26 01:01:04 +02:00

282 lines
6.0 KiB
Go

package input
import (
"unicode"
"unicode/utf8"
"github.com/charmbracelet/x/ansi"
)
// KittyKeyboardEvent represents Kitty keyboard progressive enhancement flags.
type KittyKeyboardEvent int
// IsDisambiguateEscapeCodes returns true if the DisambiguateEscapeCodes flag is set.
func (e KittyKeyboardEvent) IsDisambiguateEscapeCodes() bool {
return e&ansi.KittyDisambiguateEscapeCodes != 0
}
// IsReportEventTypes returns true if the ReportEventTypes flag is set.
func (e KittyKeyboardEvent) IsReportEventTypes() bool {
return e&ansi.KittyReportEventTypes != 0
}
// IsReportAlternateKeys returns true if the ReportAlternateKeys flag is set.
func (e KittyKeyboardEvent) IsReportAlternateKeys() bool {
return e&ansi.KittyReportAlternateKeys != 0
}
// IsReportAllKeys returns true if the ReportAllKeys flag is set.
func (e KittyKeyboardEvent) IsReportAllKeys() bool {
return e&ansi.KittyReportAllKeys != 0
}
// IsReportAssociatedKeys returns true if the ReportAssociatedKeys flag is set.
func (e KittyKeyboardEvent) IsReportAssociatedKeys() bool {
return e&ansi.KittyReportAssociatedKeys != 0
}
// Kitty Clipboard Control Sequences
var kittyKeyMap = map[int]KeySym{
ansi.BS: KeyBackspace,
ansi.HT: KeyTab,
ansi.CR: KeyEnter,
ansi.ESC: KeyEscape,
ansi.DEL: KeyBackspace,
57344: KeyEscape,
57345: KeyEnter,
57346: KeyTab,
57347: KeyBackspace,
57348: KeyInsert,
57349: KeyDelete,
57350: KeyLeft,
57351: KeyRight,
57352: KeyUp,
57353: KeyDown,
57354: KeyPgUp,
57355: KeyPgDown,
57356: KeyHome,
57357: KeyEnd,
57358: KeyCapsLock,
57359: KeyScrollLock,
57360: KeyNumLock,
57361: KeyPrintScreen,
57362: KeyPause,
57363: KeyMenu,
57364: KeyF1,
57365: KeyF2,
57366: KeyF3,
57367: KeyF4,
57368: KeyF5,
57369: KeyF6,
57370: KeyF7,
57371: KeyF8,
57372: KeyF9,
57373: KeyF10,
57374: KeyF11,
57375: KeyF12,
57376: KeyF13,
57377: KeyF14,
57378: KeyF15,
57379: KeyF16,
57380: KeyF17,
57381: KeyF18,
57382: KeyF19,
57383: KeyF20,
57384: KeyF21,
57385: KeyF22,
57386: KeyF23,
57387: KeyF24,
57388: KeyF25,
57389: KeyF26,
57390: KeyF27,
57391: KeyF28,
57392: KeyF29,
57393: KeyF30,
57394: KeyF31,
57395: KeyF32,
57396: KeyF33,
57397: KeyF34,
57398: KeyF35,
57399: KeyKp0,
57400: KeyKp1,
57401: KeyKp2,
57402: KeyKp3,
57403: KeyKp4,
57404: KeyKp5,
57405: KeyKp6,
57406: KeyKp7,
57407: KeyKp8,
57408: KeyKp9,
57409: KeyKpDecimal,
57410: KeyKpDivide,
57411: KeyKpMultiply,
57412: KeyKpMinus,
57413: KeyKpPlus,
57414: KeyKpEnter,
57415: KeyKpEqual,
57416: KeyKpSep,
57417: KeyKpLeft,
57418: KeyKpRight,
57419: KeyKpUp,
57420: KeyKpDown,
57421: KeyKpPgUp,
57422: KeyKpPgDown,
57423: KeyKpHome,
57424: KeyKpEnd,
57425: KeyKpInsert,
57426: KeyKpDelete,
57427: KeyKpBegin,
57428: KeyMediaPlay,
57429: KeyMediaPause,
57430: KeyMediaPlayPause,
57431: KeyMediaReverse,
57432: KeyMediaStop,
57433: KeyMediaFastForward,
57434: KeyMediaRewind,
57435: KeyMediaNext,
57436: KeyMediaPrev,
57437: KeyMediaRecord,
57438: KeyLowerVol,
57439: KeyRaiseVol,
57440: KeyMute,
57441: KeyLeftShift,
57442: KeyLeftCtrl,
57443: KeyLeftAlt,
57444: KeyLeftSuper,
57445: KeyLeftHyper,
57446: KeyLeftMeta,
57447: KeyRightShift,
57448: KeyRightCtrl,
57449: KeyRightAlt,
57450: KeyRightSuper,
57451: KeyRightHyper,
57452: KeyRightMeta,
57453: KeyIsoLevel3Shift,
57454: KeyIsoLevel5Shift,
}
const (
kittyShift = 1 << iota
kittyAlt
kittyCtrl
kittySuper
kittyHyper
kittyMeta
kittyCapsLock
kittyNumLock
)
func fromKittyMod(mod int) KeyMod {
var m KeyMod
if mod&kittyShift != 0 {
m |= Shift
}
if mod&kittyAlt != 0 {
m |= Alt
}
if mod&kittyCtrl != 0 {
m |= Ctrl
}
if mod&kittySuper != 0 {
m |= Super
}
if mod&kittyHyper != 0 {
m |= Hyper
}
if mod&kittyMeta != 0 {
m |= Meta
}
if mod&kittyCapsLock != 0 {
m |= CapsLock
}
if mod&kittyNumLock != 0 {
m |= NumLock
}
return m
}
// parseKittyKeyboard parses a Kitty Keyboard Protocol sequence.
//
// In `CSI u`, this is parsed as:
//
// CSI codepoint ; modifiers u
// codepoint: ASCII Dec value
//
// The Kitty Keyboard Protocol extends this with optional components that can be
// enabled progressively. The full sequence is parsed as:
//
// CSI unicode-key-code:alternate-key-codes ; modifiers:event-type ; text-as-codepoints u
//
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/
func parseKittyKeyboard(csi *ansi.CsiSequence) Event {
var isRelease bool
key := Key{}
if params := csi.Subparams(0); len(params) > 0 {
code := params[0]
if sym, ok := kittyKeyMap[code]; ok {
key.Sym = sym
} else {
r := rune(code)
if !utf8.ValidRune(r) {
r = utf8.RuneError
}
key.Rune = r
// alternate key reporting
switch len(params) {
case 3:
// shifted key + base key
if b := rune(params[2]); unicode.IsPrint(b) {
// XXX: When alternate key reporting is enabled, the protocol
// can return 3 things, the unicode codepoint of the key,
// the shifted codepoint of the key, and the standard
// PC-101 key layout codepoint.
// This is useful to create an unambiguous mapping of keys
// when using a different language layout.
key.BaseRune = b
}
fallthrough
case 2:
// shifted key
if s := rune(params[1]); unicode.IsPrint(s) {
// XXX: We swap keys here because we want the shifted key
// to be the Rune that is returned by the event.
// For example, shift+a should produce "A" not "a".
// In such a case, we set AltRune to the original key "a"
// and Rune to "A".
key.AltRune = key.Rune
key.Rune = s
}
}
}
}
if params := csi.Subparams(1); len(params) > 0 {
mod := params[0]
if mod > 1 {
key.Mod = fromKittyMod(mod - 1)
}
if len(params) > 1 {
switch params[1] {
case 2:
key.IsRepeat = true
case 3:
isRelease = true
}
}
}
// TODO: Associated keys are not support yet.
// if params := csi.Subparams(2); len(params) > 0 {
// r := rune(params[0])
// if unicode.IsPrint(r) {
// key.AltRune = r
// }
// }
if isRelease {
return KeyUpEvent(key)
}
return KeyDownEvent(key)
}