From f44d1a0ef836999b4973c33943ee260629541b2e Mon Sep 17 00:00:00 2001 From: Ayman Bagabas Date: Tue, 4 Feb 2025 15:06:14 -0500 Subject: [PATCH] refactor(vt): dry and use input package for key and mouse events --- vt/key.go | 344 +++++++++++++++++++++++----------------------------- vt/mouse.go | 140 +++++---------------- 2 files changed, 185 insertions(+), 299 deletions(-) diff --git a/vt/key.go b/vt/key.go index 93ba6ce0..d9a35121 100644 --- a/vt/key.go +++ b/vt/key.go @@ -1,27 +1,23 @@ package vt import ( - "unicode" - "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/input" ) // KeyMod represents a key modifier. -type KeyMod int +type KeyMod = input.KeyMod // Modifier keys. const ( - ModShift KeyMod = 1 << iota - ModAlt - ModCtrl - ModMeta + ModShift = input.ModShift + ModAlt = input.ModAlt + ModCtrl = input.ModCtrl + ModMeta = input.ModMeta ) // Key represents a key press event. -type Key struct { - Code rune - Mod KeyMod -} +type Key = input.Key // SendKey returns the default key map. func (t *Terminal) SendKey(k Key) { @@ -278,183 +274,153 @@ func (t *Terminal) SendKey(k Key) { t.buf.WriteString(seq) //nolint:errcheck } +// Key codes. const ( - // KeyExtended is a special key code used to signify that a key event - // contains multiple runes. - KeyExtended = unicode.MaxRune + 1 -) - -// Special key symbols. -const ( - - // Special keys - - KeyUp rune = KeyExtended + iota + 1 - KeyDown - KeyRight - KeyLeft - KeyBegin - KeyFind - KeyInsert - KeyDelete - KeySelect - KeyPgUp - KeyPgDown - KeyHome - KeyEnd - - // Keypad keys - - KeyKpEnter - KeyKpEqual - KeyKpMultiply - KeyKpPlus - KeyKpComma - KeyKpMinus - KeyKpDecimal - KeyKpDivide - KeyKp0 - KeyKp1 - KeyKp2 - KeyKp3 - KeyKp4 - KeyKp5 - KeyKp6 - KeyKp7 - KeyKp8 - KeyKp9 - - // The following are keys defined in the Kitty keyboard protocol. - // TODO: Investigate the names of these keys - KeyKpSep - KeyKpUp - KeyKpDown - KeyKpLeft - KeyKpRight - KeyKpPgUp - KeyKpPgDown - KeyKpHome - KeyKpEnd - KeyKpInsert - KeyKpDelete - KeyKpBegin - - // Function keys - - KeyF1 - KeyF2 - KeyF3 - KeyF4 - KeyF5 - KeyF6 - KeyF7 - KeyF8 - KeyF9 - KeyF10 - KeyF11 - KeyF12 - KeyF13 - KeyF14 - KeyF15 - KeyF16 - KeyF17 - KeyF18 - KeyF19 - KeyF20 - KeyF21 - KeyF22 - KeyF23 - KeyF24 - KeyF25 - KeyF26 - KeyF27 - KeyF28 - KeyF29 - KeyF30 - KeyF31 - KeyF32 - KeyF33 - KeyF34 - KeyF35 - KeyF36 - KeyF37 - KeyF38 - KeyF39 - KeyF40 - KeyF41 - KeyF42 - KeyF43 - KeyF44 - KeyF45 - KeyF46 - KeyF47 - KeyF48 - KeyF49 - KeyF50 - KeyF51 - KeyF52 - KeyF53 - KeyF54 - KeyF55 - KeyF56 - KeyF57 - KeyF58 - KeyF59 - KeyF60 - KeyF61 - KeyF62 - KeyF63 - - // The following are keys defined in the Kitty keyboard protocol. - // TODO: Investigate the names of these keys - - KeyCapsLock - KeyScrollLock - KeyNumLock - KeyPrintScreen - KeyPause - KeyMenu - - KeyMediaPlay - KeyMediaPause - KeyMediaPlayPause - KeyMediaReverse - KeyMediaStop - KeyMediaFastForward - KeyMediaRewind - KeyMediaNext - KeyMediaPrev - KeyMediaRecord - - KeyLowerVol - KeyRaiseVol - KeyMute - - KeyLeftShift - KeyLeftAlt - KeyLeftCtrl - KeyLeftSuper - KeyLeftHyper - KeyLeftMeta - KeyRightShift - KeyRightAlt - KeyRightCtrl - KeyRightSuper - KeyRightHyper - KeyRightMeta - KeyIsoLevel3Shift - KeyIsoLevel5Shift - - // Special names in C0 - - KeyBackspace = rune(ansi.DEL) - KeyTab = rune(ansi.HT) - KeyEnter = rune(ansi.CR) - KeyReturn = KeyEnter - KeyEscape = rune(ansi.ESC) - KeyEsc = KeyEscape - - // Special names in G0 - - KeySpace = rune(ansi.SP) + KeyExtended = input.KeyExtended + KeyUp = input.KeyUp + KeyDown = input.KeyDown + KeyRight = input.KeyRight + KeyLeft = input.KeyLeft + KeyBegin = input.KeyBegin + KeyFind = input.KeyFind + KeyInsert = input.KeyInsert + KeyDelete = input.KeyDelete + KeySelect = input.KeySelect + KeyPgUp = input.KeyPgUp + KeyPgDown = input.KeyPgDown + KeyHome = input.KeyHome + KeyEnd = input.KeyEnd + KeyKpEnter = input.KeyKpEnter + KeyKpEqual = input.KeyKpEqual + KeyKpMultiply = input.KeyKpMultiply + KeyKpPlus = input.KeyKpPlus + KeyKpComma = input.KeyKpComma + KeyKpMinus = input.KeyKpMinus + KeyKpDecimal = input.KeyKpDecimal + KeyKpDivide = input.KeyKpDivide + KeyKp0 = input.KeyKp0 + KeyKp1 = input.KeyKp1 + KeyKp2 = input.KeyKp2 + KeyKp3 = input.KeyKp3 + KeyKp4 = input.KeyKp4 + KeyKp5 = input.KeyKp5 + KeyKp6 = input.KeyKp6 + KeyKp7 = input.KeyKp7 + KeyKp8 = input.KeyKp8 + KeyKp9 = input.KeyKp9 + KeyKpSep = input.KeyKpSep + KeyKpUp = input.KeyKpUp + KeyKpDown = input.KeyKpDown + KeyKpLeft = input.KeyKpLeft + KeyKpRight = input.KeyKpRight + KeyKpPgUp = input.KeyKpPgUp + KeyKpPgDown = input.KeyKpPgDown + KeyKpHome = input.KeyKpHome + KeyKpEnd = input.KeyKpEnd + KeyKpInsert = input.KeyKpInsert + KeyKpDelete = input.KeyKpDelete + KeyKpBegin = input.KeyKpBegin + KeyF1 = input.KeyF1 + KeyF2 = input.KeyF2 + KeyF3 = input.KeyF3 + KeyF4 = input.KeyF4 + KeyF5 = input.KeyF5 + KeyF6 = input.KeyF6 + KeyF7 = input.KeyF7 + KeyF8 = input.KeyF8 + KeyF9 = input.KeyF9 + KeyF10 = input.KeyF10 + KeyF11 = input.KeyF11 + KeyF12 = input.KeyF12 + KeyF13 = input.KeyF13 + KeyF14 = input.KeyF14 + KeyF15 = input.KeyF15 + KeyF16 = input.KeyF16 + KeyF17 = input.KeyF17 + KeyF18 = input.KeyF18 + KeyF19 = input.KeyF19 + KeyF20 = input.KeyF20 + KeyF21 = input.KeyF21 + KeyF22 = input.KeyF22 + KeyF23 = input.KeyF23 + KeyF24 = input.KeyF24 + KeyF25 = input.KeyF25 + KeyF26 = input.KeyF26 + KeyF27 = input.KeyF27 + KeyF28 = input.KeyF28 + KeyF29 = input.KeyF29 + KeyF30 = input.KeyF30 + KeyF31 = input.KeyF31 + KeyF32 = input.KeyF32 + KeyF33 = input.KeyF33 + KeyF34 = input.KeyF34 + KeyF35 = input.KeyF35 + KeyF36 = input.KeyF36 + KeyF37 = input.KeyF37 + KeyF38 = input.KeyF38 + KeyF39 = input.KeyF39 + KeyF40 = input.KeyF40 + KeyF41 = input.KeyF41 + KeyF42 = input.KeyF42 + KeyF43 = input.KeyF43 + KeyF44 = input.KeyF44 + KeyF45 = input.KeyF45 + KeyF46 = input.KeyF46 + KeyF47 = input.KeyF47 + KeyF48 = input.KeyF48 + KeyF49 = input.KeyF49 + KeyF50 = input.KeyF50 + KeyF51 = input.KeyF51 + KeyF52 = input.KeyF52 + KeyF53 = input.KeyF53 + KeyF54 = input.KeyF54 + KeyF55 = input.KeyF55 + KeyF56 = input.KeyF56 + KeyF57 = input.KeyF57 + KeyF58 = input.KeyF58 + KeyF59 = input.KeyF59 + KeyF60 = input.KeyF60 + KeyF61 = input.KeyF61 + KeyF62 = input.KeyF62 + KeyF63 = input.KeyF63 + KeyCapsLock = input.KeyCapsLock + KeyScrollLock = input.KeyScrollLock + KeyNumLock = input.KeyNumLock + KeyPrintScreen = input.KeyPrintScreen + KeyPause = input.KeyPause + KeyMenu = input.KeyMenu + KeyMediaPlay = input.KeyMediaPlay + KeyMediaPause = input.KeyMediaPause + KeyMediaPlayPause = input.KeyMediaPlayPause + KeyMediaReverse = input.KeyMediaReverse + KeyMediaStop = input.KeyMediaStop + KeyMediaFastForward = input.KeyMediaFastForward + KeyMediaRewind = input.KeyMediaRewind + KeyMediaNext = input.KeyMediaNext + KeyMediaPrev = input.KeyMediaPrev + KeyMediaRecord = input.KeyMediaRecord + KeyLowerVol = input.KeyLowerVol + KeyRaiseVol = input.KeyRaiseVol + KeyMute = input.KeyMute + KeyLeftShift = input.KeyLeftShift + KeyLeftAlt = input.KeyLeftAlt + KeyLeftCtrl = input.KeyLeftCtrl + KeyLeftSuper = input.KeyLeftSuper + KeyLeftHyper = input.KeyLeftHyper + KeyLeftMeta = input.KeyLeftMeta + KeyRightShift = input.KeyRightShift + KeyRightAlt = input.KeyRightAlt + KeyRightCtrl = input.KeyRightCtrl + KeyRightSuper = input.KeyRightSuper + KeyRightHyper = input.KeyRightHyper + KeyRightMeta = input.KeyRightMeta + KeyIsoLevel3Shift = input.KeyIsoLevel3Shift + KeyIsoLevel5Shift = input.KeyIsoLevel5Shift + KeyBackspace = input.KeyBackspace + KeyTab = input.KeyTab + KeyEnter = input.KeyEnter + KeyReturn = input.KeyReturn + KeyEscape = input.KeyEscape + KeyEsc = input.KeyEsc + KeySpace = input.KeySpace ) diff --git a/vt/mouse.go b/vt/mouse.go index c873fa25..17e9c251 100644 --- a/vt/mouse.go +++ b/vt/mouse.go @@ -2,10 +2,11 @@ package vt import ( "github.com/charmbracelet/x/ansi" + "github.com/charmbracelet/x/input" ) // MouseButton represents the button that was pressed during a mouse message. -type MouseButton byte +type MouseButton = input.MouseButton // Mouse event buttons // @@ -25,72 +26,40 @@ type MouseButton byte // // Other buttons are not supported. const ( - MouseNone MouseButton = iota - MouseLeft - MouseMiddle - MouseRight - MouseWheelUp - MouseWheelDown - MouseWheelLeft - MouseWheelRight - MouseBackward - MouseForward - MouseExtra1 - MouseExtra2 + MouseNone = input.MouseNone + MouseLeft = input.MouseLeft + MouseMiddle = input.MouseMiddle + MouseRight = input.MouseRight + MouseWheelUp = input.MouseWheelUp + MouseWheelDown = input.MouseWheelDown + MouseWheelLeft = input.MouseWheelLeft + MouseWheelRight = input.MouseWheelRight + MouseBackward = input.MouseBackward + MouseForward = input.MouseForward + MouseButton10 = input.MouseButton10 + MouseButton11 = input.MouseButton11 ) // Mouse represents a mouse event. -type Mouse interface { - Mouse() mouse -} - -// mouse represents a mouse message. Use [Mouse] to represent all mouse -// messages. -// -// The X and Y coordinates are zero-based, with (0,0) being the upper left -// corner of the terminal. -type mouse struct { - X, Y int - Button MouseButton - Mod KeyMod -} +type Mouse = input.MouseEvent // MouseClick represents a mouse click event. -type MouseClick mouse - -// Mouse returns the mouse event. -func (m MouseClick) Mouse() mouse { - return mouse(m) -} +type MouseClick = input.MouseClickEvent // MouseRelease represents a mouse release event. -type MouseRelease mouse - -// Mouse returns the mouse event. -func (m MouseRelease) Mouse() mouse { - return mouse(m) -} +type MouseRelease = input.MouseReleaseEvent // MouseWheel represents a mouse wheel event. -type MouseWheel mouse - -// Mouse returns the mouse event. -func (m MouseWheel) Mouse() mouse { - return mouse(m) -} +type MouseWheel = input.MouseWheelEvent // MouseMotion represents a mouse motion event. -type MouseMotion mouse +type MouseMotion = input.MouseMotionEvent -// Mouse returns the mouse event. -func (m MouseMotion) Mouse() mouse { - return mouse(m) -} - -// SendMouse sends a mouse event to the terminal. -// TODO: Support [Utf8ExtMouseMode], [UrxvtExtMouseMode], and -// [SgrPixelExtMouseMode]. +// SendMouse sends a mouse event to the terminal. This can be any kind of mouse +// events such as [MouseClick], [MouseRelease], [MouseWheel], or [MouseMotion]. func (t *Terminal) SendMouse(m Mouse) { + // TODO: Support [Utf8ExtMouseMode], [UrxvtExtMouseMode], and + // [SgrPixelExtMouseMode]. var ( enc ansi.Mode mode ansi.Mode @@ -123,63 +92,14 @@ func (t *Terminal) SendMouse(m Mouse) { } } - // mouse bit shifts - const ( - bitShift = 0b0000_0100 - bitAlt = 0b0000_1000 - bitCtrl = 0b0001_0000 - bitMotion = 0b0010_0000 - bitWheel = 0b0100_0000 - bitAdd = 0b1000_0000 // additional buttons 8-11 - - bitsMask = 0b0000_0011 - ) - - var b byte - var release bool - if _, ok := m.(MouseRelease); ok { - release = true - } - // Encode button mouse := m.Mouse() - if release && enc == nil { - // X10 mouse encoding reports release as a b == 3 - b = bitsMask - } else if mouse.Button >= MouseLeft && mouse.Button <= MouseRight { - b = byte(mouse.Button) - byte(MouseLeft) - } else if mouse.Button >= MouseWheelUp && mouse.Button <= MouseWheelRight { - b = byte(mouse.Button) - byte(MouseWheelUp) - b |= bitWheel - } else if mouse.Button >= MouseBackward && mouse.Button <= MouseExtra2 { - b = byte(mouse.Button) - byte(MouseBackward) - b |= bitAdd - } - - switch m.(type) { - case MouseMotion: - switch { - case mouse.Button == MouseNone && mode == ansi.AnyEventMouseMode: - b = bitsMask - fallthrough - case mouse.Button > MouseNone && mode == ansi.ButtonEventMouseMode: - b |= bitMotion - default: - // No motion events - return - } - } - - // Encode modifiers - if mouse.Mod&ModShift != 0 { - b |= bitShift - } - if mouse.Mod&ModAlt != 0 { - b |= bitAlt - } - if mouse.Mod&ModCtrl != 0 { - b |= bitCtrl - } + _, isMotion := m.(MouseMotion) + _, isRelease := m.(MouseRelease) + b := ansi.EncodeMouseButton(mouse.Button, isMotion, + mouse.Mod.Contains(ModShift), + mouse.Mod.Contains(ModAlt), + mouse.Mod.Contains(ModCtrl)) switch enc { // TODO: Support [ansi.HighlightMouseMode]. @@ -188,6 +108,6 @@ func (t *Terminal) SendMouse(m Mouse) { case nil: // X10 mouse encoding t.buf.WriteString(ansi.MouseX10(b, mouse.X, mouse.Y)) case ansi.SgrExtMouseMode: // SGR mouse encoding - t.buf.WriteString(ansi.MouseSgr(b, mouse.X, mouse.Y, release)) + t.buf.WriteString(ansi.MouseSgr(b, mouse.X, mouse.Y, isRelease)) } }