driver.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. //nolint:unused,revive,nolintlint
  2. package input
  3. import (
  4. "bytes"
  5. "io"
  6. "unicode/utf8"
  7. "github.com/muesli/cancelreader"
  8. )
  9. // Logger is a simple logger interface.
  10. type Logger interface {
  11. Printf(format string, v ...any)
  12. }
  13. // win32InputState is a state machine for parsing key events from the Windows
  14. // Console API into escape sequences and utf8 runes, and keeps track of the last
  15. // control key state to determine modifier key changes. It also keeps track of
  16. // the last mouse button state and window size changes to determine which mouse
  17. // buttons were released and to prevent multiple size events from firing.
  18. type win32InputState struct {
  19. ansiBuf [256]byte
  20. ansiIdx int
  21. utf16Buf [2]rune
  22. utf16Half bool
  23. lastCks uint32 // the last control key state for the previous event
  24. lastMouseBtns uint32 // the last mouse button state for the previous event
  25. lastWinsizeX, lastWinsizeY int16 // the last window size for the previous event to prevent multiple size events from firing
  26. }
  27. // Reader represents an input event reader. It reads input events and parses
  28. // escape sequences from the terminal input buffer and translates them into
  29. // human‑readable events.
  30. type Reader struct {
  31. rd cancelreader.CancelReader
  32. table map[string]Key // table is a lookup table for key sequences.
  33. term string // $TERM
  34. paste []byte // bracketed paste buffer; nil when disabled
  35. buf [256]byte // read buffer
  36. partialSeq []byte // holds incomplete escape sequences
  37. keyState win32InputState
  38. parser Parser
  39. logger Logger
  40. }
  41. // NewReader returns a new input event reader.
  42. func NewReader(r io.Reader, termType string, flags int) (*Reader, error) {
  43. d := new(Reader)
  44. cr, err := newCancelreader(r, flags)
  45. if err != nil {
  46. return nil, err
  47. }
  48. d.rd = cr
  49. d.table = buildKeysTable(flags, termType)
  50. d.term = termType
  51. d.parser.flags = flags
  52. return d, nil
  53. }
  54. // SetLogger sets a logger for the reader.
  55. func (d *Reader) SetLogger(l Logger) { d.logger = l }
  56. // Read implements io.Reader.
  57. func (d *Reader) Read(p []byte) (int, error) { return d.rd.Read(p) }
  58. // Cancel cancels the underlying reader.
  59. func (d *Reader) Cancel() bool { return d.rd.Cancel() }
  60. // Close closes the underlying reader.
  61. func (d *Reader) Close() error { return d.rd.Close() }
  62. func (d *Reader) readEvents() ([]Event, error) {
  63. nb, err := d.rd.Read(d.buf[:])
  64. if err != nil {
  65. return nil, err
  66. }
  67. var events []Event
  68. // Combine any partial sequence from previous read with new data.
  69. var buf []byte
  70. if len(d.partialSeq) > 0 {
  71. buf = make([]byte, len(d.partialSeq)+nb)
  72. copy(buf, d.partialSeq)
  73. copy(buf[len(d.partialSeq):], d.buf[:nb])
  74. d.partialSeq = nil
  75. } else {
  76. buf = d.buf[:nb]
  77. }
  78. // Fast path: direct lookup for simple escape sequences.
  79. if bytes.HasPrefix(buf, []byte{0x1b}) {
  80. if k, ok := d.table[string(buf)]; ok {
  81. if d.logger != nil {
  82. d.logger.Printf("input: %q", buf)
  83. }
  84. events = append(events, KeyPressEvent(k))
  85. return events, nil
  86. }
  87. }
  88. var i int
  89. for i < len(buf) {
  90. consumed, ev := d.parser.parseSequence(buf[i:])
  91. if d.logger != nil && consumed > 0 {
  92. d.logger.Printf("input: %q", buf[i:i+consumed])
  93. }
  94. // Incomplete sequence – store remainder and exit.
  95. if consumed == 0 && ev == nil {
  96. rem := len(buf) - i
  97. if rem > 0 {
  98. d.partialSeq = make([]byte, rem)
  99. copy(d.partialSeq, buf[i:])
  100. }
  101. break
  102. }
  103. // Handle bracketed paste specially so we don’t emit a paste event for
  104. // every byte.
  105. if d.paste != nil {
  106. if _, ok := ev.(PasteEndEvent); !ok {
  107. d.paste = append(d.paste, buf[i])
  108. i++
  109. continue
  110. }
  111. }
  112. switch ev.(type) {
  113. case PasteStartEvent:
  114. d.paste = []byte{}
  115. case PasteEndEvent:
  116. var paste []rune
  117. for len(d.paste) > 0 {
  118. r, w := utf8.DecodeRune(d.paste)
  119. if r != utf8.RuneError {
  120. paste = append(paste, r)
  121. }
  122. d.paste = d.paste[w:]
  123. }
  124. d.paste = nil
  125. events = append(events, PasteEvent(paste))
  126. case nil:
  127. i++
  128. continue
  129. }
  130. if mevs, ok := ev.(MultiEvent); ok {
  131. events = append(events, []Event(mevs)...)
  132. } else {
  133. events = append(events, ev)
  134. }
  135. i += consumed
  136. }
  137. // Collapse bursts of wheel/motion events into a single event each.
  138. events = coalesceMouseEvents(events)
  139. return events, nil
  140. }
  141. // coalesceMouseEvents reduces the volume of MouseWheelEvent and MouseMotionEvent
  142. // objects that arrive in rapid succession by keeping only the most recent
  143. // event in each contiguous run.
  144. func coalesceMouseEvents(in []Event) []Event {
  145. if len(in) < 2 {
  146. return in
  147. }
  148. out := make([]Event, 0, len(in))
  149. for _, ev := range in {
  150. switch ev.(type) {
  151. case MouseWheelEvent:
  152. if len(out) > 0 {
  153. if _, ok := out[len(out)-1].(MouseWheelEvent); ok {
  154. out[len(out)-1] = ev // replace previous wheel event
  155. continue
  156. }
  157. }
  158. case MouseMotionEvent:
  159. if len(out) > 0 {
  160. if _, ok := out[len(out)-1].(MouseMotionEvent); ok {
  161. out[len(out)-1] = ev // replace previous motion event
  162. continue
  163. }
  164. }
  165. }
  166. out = append(out, ev)
  167. }
  168. return out
  169. }