Skip to content

Commit

Permalink
feat(ansi): add mouse button type and its encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
aymanbagabas committed Dec 9, 2024
1 parent af8254c commit d2630b9
Showing 1 changed file with 125 additions and 3 deletions.
128 changes: 125 additions & 3 deletions ansi/mouse.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,128 @@ import (
"fmt"
)

// MouseButton represents the button that was pressed during a mouse message.
type MouseButton byte

// Mouse event buttons
//
// This is based on X11 mouse button codes.
//
// 1 = left button
// 2 = middle button (pressing the scroll wheel)
// 3 = right button
// 4 = turn scroll wheel up
// 5 = turn scroll wheel down
// 6 = push scroll wheel left
// 7 = push scroll wheel right
// 8 = 4th button (aka browser backward button)
// 9 = 5th button (aka browser forward button)
// 10
// 11
//
// Other buttons are not supported.
const (
MouseNone MouseButton = iota
MouseLeft
MouseMiddle
MouseRight
MouseWheelUp
MouseWheelDown
MouseWheelLeft
MouseWheelRight
MouseBackward
MouseForward
MouseButton10
MouseButton11

MouseRelease = MouseNone
)

var mouseButtons = map[MouseButton]string{
MouseNone: "none",
MouseLeft: "left",
MouseMiddle: "middle",
MouseRight: "right",
MouseWheelUp: "wheelup",
MouseWheelDown: "wheeldown",
MouseWheelLeft: "wheelleft",
MouseWheelRight: "wheelright",
MouseBackward: "backward",
MouseForward: "forward",
MouseButton10: "button10",
MouseButton11: "button11",
}

// String returns a string representation of the mouse button.
func (b MouseButton) String() string {
return mouseButtons[b]
}

// Button returns a byte representing a mouse button.
// The button is a bitmask of the following leftmost values:
//
// - The first two bits are the button number:
// 0 = left button, wheel up, or button no. 8 aka (backwards)
// 1 = middle button, wheel down, or button no. 9 aka (forwards)
// 2 = right button, wheel left, or button no. 10
// 3 = release event, wheel right, or button no. 11
//
// - The third bit indicates whether the shift key was pressed.
//
// - The fourth bit indicates the alt key was pressed.
//
// - The fifth bit indicates the control key was pressed.
//
// - The sixth bit indicates motion events. Combined with button number 3, i.e.
// release event, it represents a drag event.
//
// - The seventh bit indicates a wheel event.
//
// - The eighth bit indicates additional buttons.
//
// If button is [MouseRelease], and motion is false, this returns a release
// event.
func (b MouseButton) Button(motion, shift, alt, ctrl bool) (m byte) {
// 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
)

if b == MouseRelease {
m = bitsMask
} else if b >= MouseLeft && b <= MouseRight {
m = byte(b - MouseLeft)
} else if b >= MouseWheelUp && b <= MouseWheelRight {
m = byte(b - MouseWheelUp)
m |= bitWheel
} else if b >= MouseBackward && b <= MouseButton11 {
m = byte(b - MouseBackward)
m |= bitAdd
}

if shift {
m |= bitShift
}
if alt {
m |= bitAlt
}
if ctrl {
m |= bitCtrl
}
if motion {
m |= bitMotion
}

return
}

// MouseX10 returns an escape sequence representing a mouse event in X10 mode.
// Note that this requires the terminal support X10 mouse modes.
//
Expand All @@ -22,15 +144,15 @@ func MouseX10(b byte, x, y int) string {
//
// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
func MouseSgr(b byte, x, y int, release bool) string {
s := "M"
s := 'M'
if release {
s = "m"
s = 'm'
}
if x < 0 {
x = -x
}
if y < 0 {
y = -y
}
return fmt.Sprintf("\x1b[<%d;%d;%d%s", b, x+1, y+1, s)
return fmt.Sprintf("\x1b[<%d;%d;%d%c", b, x+1, y+1, s)
}

0 comments on commit d2630b9

Please sign in to comment.