2020-06-22 20:30:16 -04:00
|
|
|
package tea
|
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"errors"
|
|
|
|
)
|
2020-06-22 20:30:16 -04:00
|
|
|
|
2021-09-07 15:28:08 -04:00
|
|
|
// 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.
|
2020-06-22 20:30:16 -04:00
|
|
|
type MouseMsg MouseEvent
|
|
|
|
|
2020-07-13 11:26:57 -04:00
|
|
|
// MouseEvent represents a mouse event, which could be a click, a scroll wheel
|
|
|
|
// movement, a cursor movement, or a combination.
|
2020-06-22 20:30:16 -04:00
|
|
|
type MouseEvent struct {
|
2020-09-28 16:42:39 -04:00
|
|
|
X int
|
|
|
|
Y int
|
|
|
|
Type MouseEventType
|
|
|
|
Alt bool
|
|
|
|
Ctrl bool
|
2020-06-22 20:30:16 -04:00
|
|
|
}
|
|
|
|
|
2020-07-13 11:26:57 -04:00
|
|
|
// String returns a string representation of a mouse event.
|
2020-06-22 20:30:16 -04:00
|
|
|
func (m MouseEvent) String() (s string) {
|
|
|
|
if m.Ctrl {
|
|
|
|
s += "ctrl+"
|
|
|
|
}
|
|
|
|
if m.Alt {
|
|
|
|
s += "alt+"
|
|
|
|
}
|
2020-09-28 16:42:39 -04:00
|
|
|
s += mouseEventTypes[m.Type]
|
2020-06-22 20:30:16 -04:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2020-09-28 16:42:39 -04:00
|
|
|
// MouseEventType indicates the type of mouse event occurring.
|
|
|
|
type MouseEventType int
|
2020-06-22 20:30:16 -04:00
|
|
|
|
2021-09-07 15:28:08 -04:00
|
|
|
// Mouse event types.
|
2020-06-22 20:30:16 -04:00
|
|
|
const (
|
2020-09-28 16:42:39 -04:00
|
|
|
MouseUnknown MouseEventType = iota
|
2020-06-23 10:34:46 -04:00
|
|
|
MouseLeft
|
2020-06-22 20:30:16 -04:00
|
|
|
MouseRight
|
|
|
|
MouseMiddle
|
|
|
|
MouseRelease
|
|
|
|
MouseWheelUp
|
|
|
|
MouseWheelDown
|
|
|
|
MouseMotion
|
|
|
|
)
|
|
|
|
|
2020-09-28 16:42:39 -04:00
|
|
|
var mouseEventTypes = map[MouseEventType]string{
|
2020-06-23 10:34:46 -04:00
|
|
|
MouseUnknown: "unknown",
|
2020-06-22 20:30:16 -04:00
|
|
|
MouseLeft: "left",
|
|
|
|
MouseRight: "right",
|
|
|
|
MouseMiddle: "middle",
|
|
|
|
MouseRelease: "release",
|
|
|
|
MouseWheelUp: "wheel up",
|
|
|
|
MouseWheelDown: "wheel down",
|
|
|
|
MouseMotion: "motion",
|
|
|
|
}
|
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
// Parse X10-encoded mouse events; the simplest kind. The last release of X10
|
|
|
|
// was December 1986, by the way.
|
2020-06-23 10:34:46 -04:00
|
|
|
//
|
|
|
|
// X10 mouse events look like:
|
|
|
|
//
|
|
|
|
// ESC [M Cb Cx Cy
|
|
|
|
//
|
2020-11-07 00:43:12 -05:00
|
|
|
// See: http://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking
|
2022-02-02 22:14:49 -05:00
|
|
|
func parseX10MouseEvents(buf []byte) ([]MouseEvent, error) {
|
|
|
|
var r []MouseEvent
|
2020-06-22 20:30:16 -04:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
seq := []byte("\x1b[M")
|
|
|
|
if !bytes.Contains(buf, seq) {
|
|
|
|
return r, errors.New("not an X10 mouse event")
|
|
|
|
}
|
2020-11-07 00:43:12 -05:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
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")
|
|
|
|
}
|
2020-11-07 00:43:12 -05:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-11-07 00:43:12 -05:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
if e&bitAlt != 0 {
|
|
|
|
m.Alt = true
|
2020-11-07 00:43:12 -05:00
|
|
|
}
|
2022-02-02 22:14:49 -05:00
|
|
|
if e&bitCtrl != 0 {
|
|
|
|
m.Ctrl = true
|
2020-06-22 20:30:16 -04:00
|
|
|
}
|
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
// (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
|
2020-06-22 20:30:16 -04:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
r = append(r, m)
|
|
|
|
}
|
2020-06-22 20:30:16 -04:00
|
|
|
|
2022-02-02 22:14:49 -05:00
|
|
|
return r, nil
|
2020-06-22 20:30:16 -04:00
|
|
|
}
|