driver.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package input
  2. import (
  3. "bytes"
  4. "io"
  5. "unicode/utf8"
  6. "github.com/erikgeiser/coninput"
  7. "github.com/muesli/cancelreader"
  8. )
  9. // Driver represents an ANSI terminal input Driver.
  10. // It reads input events and parses ANSI sequences from the terminal input
  11. // buffer.
  12. type Driver struct {
  13. rd cancelreader.CancelReader
  14. table map[string]Key // table is a lookup table for key sequences.
  15. term string // term is the terminal name $TERM.
  16. // paste is the bracketed paste mode buffer.
  17. // When nil, bracketed paste mode is disabled.
  18. paste []byte
  19. buf [256]byte // do we need a larger buffer?
  20. // prevMouseState keeps track of the previous mouse state to determine mouse
  21. // up button events.
  22. prevMouseState coninput.ButtonState // nolint: unused
  23. // lastWinsizeEvent keeps track of the last window size event to prevent
  24. // multiple size events from firing.
  25. lastWinsizeEvent coninput.WindowBufferSizeEventRecord // nolint: unused
  26. flags int // control the behavior of the driver.
  27. }
  28. // NewDriver returns a new ANSI input driver.
  29. // This driver uses ANSI control codes compatible with VT100/VT200 terminals,
  30. // and XTerm. It supports reading Terminfo databases to overwrite the default
  31. // key sequences.
  32. func NewDriver(r io.Reader, term string, flags int) (*Driver, error) {
  33. d := new(Driver)
  34. cr, err := newCancelreader(r)
  35. if err != nil {
  36. return nil, err
  37. }
  38. d.rd = cr
  39. d.table = buildKeysTable(flags, term)
  40. d.term = term
  41. d.flags = flags
  42. return d, nil
  43. }
  44. // Cancel cancels the underlying reader.
  45. func (d *Driver) Cancel() bool {
  46. return d.rd.Cancel()
  47. }
  48. // Close closes the underlying reader.
  49. func (d *Driver) Close() error {
  50. return d.rd.Close()
  51. }
  52. func (d *Driver) readEvents() (e []Event, err error) {
  53. nb, err := d.rd.Read(d.buf[:])
  54. if err != nil {
  55. return nil, err
  56. }
  57. buf := d.buf[:nb]
  58. // Lookup table first
  59. if bytes.HasPrefix(buf, []byte{'\x1b'}) {
  60. if k, ok := d.table[string(buf)]; ok {
  61. e = append(e, KeyPressEvent(k))
  62. return
  63. }
  64. }
  65. var i int
  66. for i < len(buf) {
  67. nb, ev := ParseSequence(buf[i:])
  68. // Handle bracketed-paste
  69. if d.paste != nil {
  70. if _, ok := ev.(PasteEndEvent); !ok {
  71. d.paste = append(d.paste, buf[i])
  72. i++
  73. continue
  74. }
  75. }
  76. switch ev.(type) {
  77. case UnknownCsiEvent, UnknownSs3Event, UnknownEvent:
  78. // If the sequence is not recognized by the parser, try looking it up.
  79. if k, ok := d.table[string(buf[i:i+nb])]; ok {
  80. ev = KeyPressEvent(k)
  81. }
  82. case PasteStartEvent:
  83. d.paste = []byte{}
  84. case PasteEndEvent:
  85. // Decode the captured data into runes.
  86. var paste []rune
  87. for len(d.paste) > 0 {
  88. r, w := utf8.DecodeRune(d.paste)
  89. if r != utf8.RuneError {
  90. paste = append(paste, r)
  91. }
  92. d.paste = d.paste[w:]
  93. }
  94. d.paste = nil // reset the buffer
  95. e = append(e, PasteEvent(paste))
  96. case nil:
  97. i++
  98. continue
  99. }
  100. if mevs, ok := ev.(MultiEvent); ok {
  101. e = append(e, []Event(mevs)...)
  102. } else {
  103. e = append(e, ev)
  104. }
  105. i += nb
  106. }
  107. return
  108. }