mouse.go

  1package ansi
  2
  3import (
  4	"fmt"
  5)
  6
  7// MouseButton represents the button that was pressed during a mouse message.
  8type MouseButton byte
  9
 10// Mouse event buttons
 11//
 12// This is based on X11 mouse button codes.
 13//
 14//	1 = left button
 15//	2 = middle button (pressing the scroll wheel)
 16//	3 = right button
 17//	4 = turn scroll wheel up
 18//	5 = turn scroll wheel down
 19//	6 = push scroll wheel left
 20//	7 = push scroll wheel right
 21//	8 = 4th button (aka browser backward button)
 22//	9 = 5th button (aka browser forward button)
 23//	10
 24//	11
 25//
 26// Other buttons are not supported.
 27const (
 28	MouseNone MouseButton = iota
 29	MouseButton1
 30	MouseButton2
 31	MouseButton3
 32	MouseButton4
 33	MouseButton5
 34	MouseButton6
 35	MouseButton7
 36	MouseButton8
 37	MouseButton9
 38	MouseButton10
 39	MouseButton11
 40
 41	MouseLeft       = MouseButton1
 42	MouseMiddle     = MouseButton2
 43	MouseRight      = MouseButton3
 44	MouseWheelUp    = MouseButton4
 45	MouseWheelDown  = MouseButton5
 46	MouseWheelLeft  = MouseButton6
 47	MouseWheelRight = MouseButton7
 48	MouseBackward   = MouseButton8
 49	MouseForward    = MouseButton9
 50	MouseRelease    = MouseNone
 51)
 52
 53var mouseButtons = map[MouseButton]string{
 54	MouseNone:       "none",
 55	MouseLeft:       "left",
 56	MouseMiddle:     "middle",
 57	MouseRight:      "right",
 58	MouseWheelUp:    "wheelup",
 59	MouseWheelDown:  "wheeldown",
 60	MouseWheelLeft:  "wheelleft",
 61	MouseWheelRight: "wheelright",
 62	MouseBackward:   "backward",
 63	MouseForward:    "forward",
 64	MouseButton10:   "button10",
 65	MouseButton11:   "button11",
 66}
 67
 68// String returns a string representation of the mouse button.
 69func (b MouseButton) String() string {
 70	return mouseButtons[b]
 71}
 72
 73// EncodeMouseButton returns a byte representing a mouse button.
 74// The button is a bitmask of the following leftmost values:
 75//
 76//   - The first two bits are the button number:
 77//     0 = left button, wheel up, or button no. 8 aka (backwards)
 78//     1 = middle button, wheel down, or button no. 9 aka (forwards)
 79//     2 = right button, wheel left, or button no. 10
 80//     3 = release event, wheel right, or button no. 11
 81//
 82//   - The third bit indicates whether the shift key was pressed.
 83//
 84//   - The fourth bit indicates the alt key was pressed.
 85//
 86//   - The fifth bit indicates the control key was pressed.
 87//
 88//   - The sixth bit indicates motion events. Combined with button number 3, i.e.
 89//     release event, it represents a drag event.
 90//
 91//   - The seventh bit indicates a wheel event.
 92//
 93//   - The eighth bit indicates additional buttons.
 94//
 95// If button is [MouseNone], and motion is false, this returns a release event.
 96// If button is undefined, this function returns 0xff.
 97func EncodeMouseButton(b MouseButton, motion, shift, alt, ctrl bool) (m byte) {
 98	// mouse bit shifts
 99	const (
100		bitShift  = 0b0000_0100
101		bitAlt    = 0b0000_1000
102		bitCtrl   = 0b0001_0000
103		bitMotion = 0b0010_0000
104		bitWheel  = 0b0100_0000
105		bitAdd    = 0b1000_0000 // additional buttons 8-11
106
107		bitsMask = 0b0000_0011
108	)
109
110	if b == MouseNone {
111		m = bitsMask
112	} else if b >= MouseLeft && b <= MouseRight {
113		m = byte(b - MouseLeft)
114	} else if b >= MouseWheelUp && b <= MouseWheelRight {
115		m = byte(b - MouseWheelUp)
116		m |= bitWheel
117	} else if b >= MouseBackward && b <= MouseButton11 {
118		m = byte(b - MouseBackward)
119		m |= bitAdd
120	} else {
121		m = 0xff // invalid button
122	}
123
124	if shift {
125		m |= bitShift
126	}
127	if alt {
128		m |= bitAlt
129	}
130	if ctrl {
131		m |= bitCtrl
132	}
133	if motion {
134		m |= bitMotion
135	}
136
137	return
138}
139
140// x10Offset is the offset for X10 mouse events.
141// See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
142const x10Offset = 32
143
144// MouseX10 returns an escape sequence representing a mouse event in X10 mode.
145// Note that this requires the terminal support X10 mouse modes.
146//
147//	CSI M Cb Cx Cy
148//
149// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
150func MouseX10(b byte, x, y int) string {
151	return "\x1b[M" + string(b+x10Offset) + string(byte(x)+x10Offset+1) + string(byte(y)+x10Offset+1)
152}
153
154// MouseSgr returns an escape sequence representing a mouse event in SGR mode.
155//
156//	CSI < Cb ; Cx ; Cy M
157//	CSI < Cb ; Cx ; Cy m (release)
158//
159// See: https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#Mouse%20Tracking
160func MouseSgr(b byte, x, y int, release bool) string {
161	s := 'M'
162	if release {
163		s = 'm'
164	}
165	if x < 0 {
166		x = -x
167	}
168	if y < 0 {
169		y = -y
170	}
171	return fmt.Sprintf("\x1b[<%d;%d;%d%c", b, x+1, y+1, s)
172}