mouse.go 3.0 KB

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