driver.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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 is the terminal name $TERM.
  34. // paste is the bracketed paste mode buffer.
  35. // When nil, bracketed paste mode is disabled.
  36. paste []byte
  37. buf [256]byte // do we need a larger buffer?
  38. // partialSeq holds incomplete escape sequences that need more data
  39. partialSeq []byte
  40. // keyState keeps track of the current Windows Console API key events state.
  41. // It is used to decode ANSI escape sequences and utf16 sequences.
  42. keyState win32InputState
  43. parser Parser
  44. logger Logger
  45. }
  46. // NewReader returns a new input event reader. The reader reads input events
  47. // from the terminal and parses escape sequences into human-readable events. It
  48. // supports reading Terminfo databases. See [Parser] for more information.
  49. //
  50. // Example:
  51. //
  52. // r, _ := input.NewReader(os.Stdin, os.Getenv("TERM"), 0)
  53. // defer r.Close()
  54. // events, _ := r.ReadEvents()
  55. // for _, ev := range events {
  56. // log.Printf("%v", ev)
  57. // }
  58. func NewReader(r io.Reader, termType string, flags int) (*Reader, error) {
  59. d := new(Reader)
  60. cr, err := newCancelreader(r, flags)
  61. if err != nil {
  62. return nil, err
  63. }
  64. d.rd = cr
  65. d.table = buildKeysTable(flags, termType)
  66. d.term = termType
  67. d.parser.flags = flags
  68. return d, nil
  69. }
  70. // SetLogger sets a logger for the reader.
  71. func (d *Reader) SetLogger(l Logger) {
  72. d.logger = l
  73. }
  74. // Read implements [io.Reader].
  75. func (d *Reader) Read(p []byte) (int, error) {
  76. return d.rd.Read(p) //nolint:wrapcheck
  77. }
  78. // Cancel cancels the underlying reader.
  79. func (d *Reader) Cancel() bool {
  80. return d.rd.Cancel()
  81. }
  82. // Close closes the underlying reader.
  83. func (d *Reader) Close() error {
  84. return d.rd.Close() //nolint:wrapcheck
  85. }
  86. func (d *Reader) readEvents() ([]Event, error) {
  87. nb, err := d.rd.Read(d.buf[:])
  88. if err != nil {
  89. return nil, err //nolint:wrapcheck
  90. }
  91. var events []Event
  92. // Combine any partial sequence from previous read with new data
  93. var buf []byte
  94. if len(d.partialSeq) > 0 {
  95. buf = make([]byte, len(d.partialSeq)+nb)
  96. copy(buf, d.partialSeq)
  97. copy(buf[len(d.partialSeq):], d.buf[:nb])
  98. d.partialSeq = nil // clear the partial sequence
  99. } else {
  100. buf = d.buf[:nb]
  101. }
  102. // Lookup table first
  103. if bytes.HasPrefix(buf, []byte{'\x1b'}) {
  104. if k, ok := d.table[string(buf)]; ok {
  105. if d.logger != nil {
  106. d.logger.Printf("input: %q", buf)
  107. }
  108. events = append(events, KeyPressEvent(k))
  109. return events, nil
  110. }
  111. }
  112. var i int
  113. for i < len(buf) {
  114. nb, ev := d.parser.parseSequence(buf[i:])
  115. if d.logger != nil && nb > 0 {
  116. d.logger.Printf("input: %q", buf[i:i+nb])
  117. }
  118. // Handle incomplete sequences - when parseSequence returns (0, nil)
  119. // it means we need more data to complete the sequence
  120. if nb == 0 && ev == nil {
  121. // Store the remaining data for the next read
  122. remaining := len(buf) - i
  123. if remaining > 0 {
  124. d.partialSeq = make([]byte, remaining)
  125. copy(d.partialSeq, buf[i:])
  126. }
  127. break
  128. }
  129. // Handle bracketed-paste
  130. if d.paste != nil {
  131. if _, ok := ev.(PasteEndEvent); !ok {
  132. d.paste = append(d.paste, buf[i])
  133. i++
  134. continue
  135. }
  136. }
  137. switch ev.(type) {
  138. // case UnknownEvent:
  139. // // If the sequence is not recognized by the parser, try looking it up.
  140. // if k, ok := d.table[string(buf[i:i+nb])]; ok {
  141. // ev = KeyPressEvent(k)
  142. // }
  143. case PasteStartEvent:
  144. d.paste = []byte{}
  145. case PasteEndEvent:
  146. // Decode the captured data into runes.
  147. var paste []rune
  148. for len(d.paste) > 0 {
  149. r, w := utf8.DecodeRune(d.paste)
  150. if r != utf8.RuneError {
  151. paste = append(paste, r)
  152. }
  153. d.paste = d.paste[w:]
  154. }
  155. d.paste = nil // reset the buffer
  156. events = append(events, PasteEvent(paste))
  157. case nil:
  158. i++
  159. continue
  160. }
  161. if mevs, ok := ev.(MultiEvent); ok {
  162. events = append(events, []Event(mevs)...)
  163. } else {
  164. events = append(events, ev)
  165. }
  166. i += nb
  167. }
  168. return events, nil
  169. }