mouse.go 4.3 KB

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