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}