forked from charmbracelet/bubbletea
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mouse.go
149 lines (129 loc) · 3 KB
/
mouse.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package tea
import (
"bytes"
"errors"
)
// MouseMsg contains information about a mouse event and are sent to a programs
// update function when mouse activity occurs. Note that the mouse must first
// be enabled via in order the mouse events to be received.
type MouseMsg MouseEvent
// MouseEvent represents a mouse event, which could be a click, a scroll wheel
// movement, a cursor movement, or a combination.
type MouseEvent struct {
X int
Y int
Type MouseEventType
Alt bool
Ctrl bool
}
// String returns a string representation of a mouse event.
func (m MouseEvent) String() (s string) {
if m.Ctrl {
s += "ctrl+"
}
if m.Alt {
s += "alt+"
}
s += mouseEventTypes[m.Type]
return s
}
// MouseEventType indicates the type of mouse event occurring.
type MouseEventType int
// Mouse event types.
const (
MouseUnknown MouseEventType = iota
MouseLeft
MouseRight
MouseMiddle
MouseRelease
MouseWheelUp
MouseWheelDown
MouseMotion
)
var mouseEventTypes = map[MouseEventType]string{
MouseUnknown: "unknown",
MouseLeft: "left",
MouseRight: "right",
MouseMiddle: "middle",
MouseRelease: "release",
MouseWheelUp: "wheel up",
MouseWheelDown: "wheel down",
MouseMotion: "motion",
}
// Parse X10-encoded mouse events; the simplest kind. The last release of X10
// was December 1986, by the way.
//
// X10 mouse events look like:
//
// ESC [M Cb Cx Cy
//
// See: http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking
func parseX10MouseEvents(buf []byte) ([]MouseEvent, error) {
var r []MouseEvent
seq := []byte("\x1b[M")
if !bytes.Contains(buf, seq) {
return r, errors.New("not an X10 mouse event")
}
for _, v := range bytes.Split(buf, seq) {
if len(v) == 0 {
continue
}
if len(v) != 3 {
return r, errors.New("not an X10 mouse event")
}
var m MouseEvent
const byteOffset = 32
e := v[0] - byteOffset
const (
bitShift = 0b0000_0100
bitAlt = 0b0000_1000
bitCtrl = 0b0001_0000
bitMotion = 0b0010_0000
bitWheel = 0b0100_0000
bitsMask = 0b0000_0011
bitsLeft = 0b0000_0000
bitsMiddle = 0b0000_0001
bitsRight = 0b0000_0010
bitsRelease = 0b0000_0011
bitsWheelUp = 0b0000_0000
bitsWheelDown = 0b0000_0001
)
if e&bitWheel != 0 {
// Check the low two bits.
switch e & bitsMask {
case bitsWheelUp:
m.Type = MouseWheelUp
case bitsWheelDown:
m.Type = MouseWheelDown
}
} else {
// Check the low two bits.
// We do not separate clicking and dragging.
switch e & bitsMask {
case bitsLeft:
m.Type = MouseLeft
case bitsMiddle:
m.Type = MouseMiddle
case bitsRight:
m.Type = MouseRight
case bitsRelease:
if e&bitMotion != 0 {
m.Type = MouseMotion
} else {
m.Type = MouseRelease
}
}
}
if e&bitAlt != 0 {
m.Alt = true
}
if e&bitCtrl != 0 {
m.Ctrl = true
}
// (1,1) is the upper left. We subtract 1 to normalize it to (0,0).
m.X = int(v[1]) - byteOffset - 1
m.Y = int(v[2]) - byteOffset - 1
r = append(r, m)
}
return r, nil
}