main
Raw Download raw file
  1package tea
  2
  3import (
  4	"context"
  5	"fmt"
  6	"io"
  7	"regexp"
  8	"strings"
  9	"unicode/utf8"
 10)
 11
 12// KeyMsg contains information about a keypress. KeyMsgs are always sent to
 13// the program's update function. There are a couple general patterns you could
 14// use to check for keypresses:
 15//
 16//	// Switch on the string representation of the key (shorter)
 17//	switch msg := msg.(type) {
 18//	case KeyMsg:
 19//	    switch msg.String() {
 20//	    case "enter":
 21//	        fmt.Println("you pressed enter!")
 22//	    case "a":
 23//	        fmt.Println("you pressed a!")
 24//	    }
 25//	}
 26//
 27//	// Switch on the key type (more foolproof)
 28//	switch msg := msg.(type) {
 29//	case KeyMsg:
 30//	    switch msg.Type {
 31//	    case KeyEnter:
 32//	        fmt.Println("you pressed enter!")
 33//	    case KeyRunes:
 34//	        switch string(msg.Runes) {
 35//	        case "a":
 36//	            fmt.Println("you pressed a!")
 37//	        }
 38//	    }
 39//	}
 40//
 41// Note that Key.Runes will always contain at least one character, so you can
 42// always safely call Key.Runes[0]. In most cases Key.Runes will only contain
 43// one character, though certain input method editors (most notably Chinese
 44// IMEs) can input multiple runes at once.
 45type KeyMsg Key
 46
 47// String returns a string representation for a key message. It's safe (and
 48// encouraged) for use in key comparison.
 49func (k KeyMsg) String() (str string) {
 50	return Key(k).String()
 51}
 52
 53// Key contains information about a keypress.
 54type Key struct {
 55	Type  KeyType
 56	Runes []rune
 57	Alt   bool
 58	Paste bool
 59}
 60
 61// String returns a friendly string representation for a key. It's safe (and
 62// encouraged) for use in key comparison.
 63//
 64//	k := Key{Type: KeyEnter}
 65//	fmt.Println(k)
 66//	// Output: enter
 67func (k Key) String() (str string) {
 68	var buf strings.Builder
 69	if k.Alt {
 70		buf.WriteString("alt+")
 71	}
 72	if k.Type == KeyRunes {
 73		if k.Paste {
 74			// Note: bubbles/keys bindings currently do string compares to
 75			// recognize shortcuts. Since pasted text should never activate
 76			// shortcuts, we need to ensure that the binding code doesn't
 77			// match Key events that result from pastes. We achieve this
 78			// here by enclosing pastes in '[...]' so that the string
 79			// comparison in Matches() fails in that case.
 80			buf.WriteByte('[')
 81		}
 82		buf.WriteString(string(k.Runes))
 83		if k.Paste {
 84			buf.WriteByte(']')
 85		}
 86		return buf.String()
 87	} else if s, ok := keyNames[k.Type]; ok {
 88		buf.WriteString(s)
 89		return buf.String()
 90	}
 91	return ""
 92}
 93
 94// KeyType indicates the key pressed, such as KeyEnter or KeyBreak or KeyCtrlC.
 95// All other keys will be type KeyRunes. To get the rune value, check the Rune
 96// method on a Key struct, or use the Key.String() method:
 97//
 98//	k := Key{Type: KeyRunes, Runes: []rune{'a'}, Alt: true}
 99//	if k.Type == KeyRunes {
100//
101//	    fmt.Println(k.Runes)
102//	    // Output: a
103//
104//	    fmt.Println(k.String())
105//	    // Output: alt+a
106//
107//	}
108type KeyType int
109
110func (k KeyType) String() (str string) {
111	if s, ok := keyNames[k]; ok {
112		return s
113	}
114	return ""
115}
116
117// Control keys. We could do this with an iota, but the values are very
118// specific, so we set the values explicitly to avoid any confusion.
119//
120// See also:
121// https://en.wikipedia.org/wiki/C0_and_C1_control_codes
122const (
123	keyNUL KeyType = 0   // null, \0
124	keySOH KeyType = 1   // start of heading
125	keySTX KeyType = 2   // start of text
126	keyETX KeyType = 3   // break, ctrl+c
127	keyEOT KeyType = 4   // end of transmission
128	keyENQ KeyType = 5   // enquiry
129	keyACK KeyType = 6   // acknowledge
130	keyBEL KeyType = 7   // bell, \a
131	keyBS  KeyType = 8   // backspace
132	keyHT  KeyType = 9   // horizontal tabulation, \t
133	keyLF  KeyType = 10  // line feed, \n
134	keyVT  KeyType = 11  // vertical tabulation \v
135	keyFF  KeyType = 12  // form feed \f
136	keyCR  KeyType = 13  // carriage return, \r
137	keySO  KeyType = 14  // shift out
138	keySI  KeyType = 15  // shift in
139	keyDLE KeyType = 16  // data link escape
140	keyDC1 KeyType = 17  // device control one
141	keyDC2 KeyType = 18  // device control two
142	keyDC3 KeyType = 19  // device control three
143	keyDC4 KeyType = 20  // device control four
144	keyNAK KeyType = 21  // negative acknowledge
145	keySYN KeyType = 22  // synchronous idle
146	keyETB KeyType = 23  // end of transmission block
147	keyCAN KeyType = 24  // cancel
148	keyEM  KeyType = 25  // end of medium
149	keySUB KeyType = 26  // substitution
150	keyESC KeyType = 27  // escape, \e
151	keyFS  KeyType = 28  // file separator
152	keyGS  KeyType = 29  // group separator
153	keyRS  KeyType = 30  // record separator
154	keyUS  KeyType = 31  // unit separator
155	keyDEL KeyType = 127 // delete. on most systems this is mapped to backspace, I hear
156)
157
158// Control key aliases.
159const (
160	KeyNull      KeyType = keyNUL
161	KeyBreak     KeyType = keyETX
162	KeyEnter     KeyType = keyCR
163	KeyBackspace KeyType = keyDEL
164	KeyTab       KeyType = keyHT
165	KeyEsc       KeyType = keyESC
166	KeyEscape    KeyType = keyESC
167
168	KeyCtrlAt           KeyType = keyNUL // ctrl+@
169	KeyCtrlA            KeyType = keySOH
170	KeyCtrlB            KeyType = keySTX
171	KeyCtrlC            KeyType = keyETX
172	KeyCtrlD            KeyType = keyEOT
173	KeyCtrlE            KeyType = keyENQ
174	KeyCtrlF            KeyType = keyACK
175	KeyCtrlG            KeyType = keyBEL
176	KeyCtrlH            KeyType = keyBS
177	KeyCtrlI            KeyType = keyHT
178	KeyCtrlJ            KeyType = keyLF
179	KeyCtrlK            KeyType = keyVT
180	KeyCtrlL            KeyType = keyFF
181	KeyCtrlM            KeyType = keyCR
182	KeyCtrlN            KeyType = keySO
183	KeyCtrlO            KeyType = keySI
184	KeyCtrlP            KeyType = keyDLE
185	KeyCtrlQ            KeyType = keyDC1
186	KeyCtrlR            KeyType = keyDC2
187	KeyCtrlS            KeyType = keyDC3
188	KeyCtrlT            KeyType = keyDC4
189	KeyCtrlU            KeyType = keyNAK
190	KeyCtrlV            KeyType = keySYN
191	KeyCtrlW            KeyType = keyETB
192	KeyCtrlX            KeyType = keyCAN
193	KeyCtrlY            KeyType = keyEM
194	KeyCtrlZ            KeyType = keySUB
195	KeyCtrlOpenBracket  KeyType = keyESC // ctrl+[
196	KeyCtrlBackslash    KeyType = keyFS  // ctrl+\
197	KeyCtrlCloseBracket KeyType = keyGS  // ctrl+]
198	KeyCtrlCaret        KeyType = keyRS  // ctrl+^
199	KeyCtrlUnderscore   KeyType = keyUS  // ctrl+_
200	KeyCtrlQuestionMark KeyType = keyDEL // ctrl+?
201)
202
203// Other keys.
204const (
205	KeyRunes KeyType = -(iota + 1)
206	KeyUp
207	KeyDown
208	KeyRight
209	KeyLeft
210	KeyShiftTab
211	KeyHome
212	KeyEnd
213	KeyPgUp
214	KeyPgDown
215	KeyCtrlPgUp
216	KeyCtrlPgDown
217	KeyDelete
218	KeyInsert
219	KeySpace
220	KeyCtrlUp
221	KeyCtrlDown
222	KeyCtrlRight
223	KeyCtrlLeft
224	KeyCtrlHome
225	KeyCtrlEnd
226	KeyShiftUp
227	KeyShiftDown
228	KeyShiftRight
229	KeyShiftLeft
230	KeyShiftHome
231	KeyShiftEnd
232	KeyCtrlShiftUp
233	KeyCtrlShiftDown
234	KeyCtrlShiftLeft
235	KeyCtrlShiftRight
236	KeyCtrlShiftHome
237	KeyCtrlShiftEnd
238	KeyF1
239	KeyF2
240	KeyF3
241	KeyF4
242	KeyF5
243	KeyF6
244	KeyF7
245	KeyF8
246	KeyF9
247	KeyF10
248	KeyF11
249	KeyF12
250	KeyF13
251	KeyF14
252	KeyF15
253	KeyF16
254	KeyF17
255	KeyF18
256	KeyF19
257	KeyF20
258)
259
260// Mappings for control keys and other special keys to friendly consts.
261var keyNames = map[KeyType]string{
262	// Control keys.
263	keyNUL: "ctrl+@", // also ctrl+` (that's ctrl+backtick)
264	keySOH: "ctrl+a",
265	keySTX: "ctrl+b",
266	keyETX: "ctrl+c",
267	keyEOT: "ctrl+d",
268	keyENQ: "ctrl+e",
269	keyACK: "ctrl+f",
270	keyBEL: "ctrl+g",
271	keyBS:  "ctrl+h",
272	keyHT:  "tab", // also ctrl+i
273	keyLF:  "ctrl+j",
274	keyVT:  "ctrl+k",
275	keyFF:  "ctrl+l",
276	keyCR:  "enter",
277	keySO:  "ctrl+n",
278	keySI:  "ctrl+o",
279	keyDLE: "ctrl+p",
280	keyDC1: "ctrl+q",
281	keyDC2: "ctrl+r",
282	keyDC3: "ctrl+s",
283	keyDC4: "ctrl+t",
284	keyNAK: "ctrl+u",
285	keySYN: "ctrl+v",
286	keyETB: "ctrl+w",
287	keyCAN: "ctrl+x",
288	keyEM:  "ctrl+y",
289	keySUB: "ctrl+z",
290	keyESC: "esc",
291	keyFS:  "ctrl+\\",
292	keyGS:  "ctrl+]",
293	keyRS:  "ctrl+^",
294	keyUS:  "ctrl+_",
295	keyDEL: "backspace",
296
297	// Other keys.
298	KeyRunes:          "runes",
299	KeyUp:             "up",
300	KeyDown:           "down",
301	KeyRight:          "right",
302	KeySpace:          " ", // for backwards compatibility
303	KeyLeft:           "left",
304	KeyShiftTab:       "shift+tab",
305	KeyHome:           "home",
306	KeyEnd:            "end",
307	KeyCtrlHome:       "ctrl+home",
308	KeyCtrlEnd:        "ctrl+end",
309	KeyShiftHome:      "shift+home",
310	KeyShiftEnd:       "shift+end",
311	KeyCtrlShiftHome:  "ctrl+shift+home",
312	KeyCtrlShiftEnd:   "ctrl+shift+end",
313	KeyPgUp:           "pgup",
314	KeyPgDown:         "pgdown",
315	KeyCtrlPgUp:       "ctrl+pgup",
316	KeyCtrlPgDown:     "ctrl+pgdown",
317	KeyDelete:         "delete",
318	KeyInsert:         "insert",
319	KeyCtrlUp:         "ctrl+up",
320	KeyCtrlDown:       "ctrl+down",
321	KeyCtrlRight:      "ctrl+right",
322	KeyCtrlLeft:       "ctrl+left",
323	KeyShiftUp:        "shift+up",
324	KeyShiftDown:      "shift+down",
325	KeyShiftRight:     "shift+right",
326	KeyShiftLeft:      "shift+left",
327	KeyCtrlShiftUp:    "ctrl+shift+up",
328	KeyCtrlShiftDown:  "ctrl+shift+down",
329	KeyCtrlShiftLeft:  "ctrl+shift+left",
330	KeyCtrlShiftRight: "ctrl+shift+right",
331	KeyF1:             "f1",
332	KeyF2:             "f2",
333	KeyF3:             "f3",
334	KeyF4:             "f4",
335	KeyF5:             "f5",
336	KeyF6:             "f6",
337	KeyF7:             "f7",
338	KeyF8:             "f8",
339	KeyF9:             "f9",
340	KeyF10:            "f10",
341	KeyF11:            "f11",
342	KeyF12:            "f12",
343	KeyF13:            "f13",
344	KeyF14:            "f14",
345	KeyF15:            "f15",
346	KeyF16:            "f16",
347	KeyF17:            "f17",
348	KeyF18:            "f18",
349	KeyF19:            "f19",
350	KeyF20:            "f20",
351}
352
353// Sequence mappings.
354var sequences = map[string]Key{
355	// Arrow keys
356	"\x1b[A":    {Type: KeyUp},
357	"\x1b[B":    {Type: KeyDown},
358	"\x1b[C":    {Type: KeyRight},
359	"\x1b[D":    {Type: KeyLeft},
360	"\x1b[1;2A": {Type: KeyShiftUp},
361	"\x1b[1;2B": {Type: KeyShiftDown},
362	"\x1b[1;2C": {Type: KeyShiftRight},
363	"\x1b[1;2D": {Type: KeyShiftLeft},
364	"\x1b[OA":   {Type: KeyShiftUp},    // DECCKM
365	"\x1b[OB":   {Type: KeyShiftDown},  // DECCKM
366	"\x1b[OC":   {Type: KeyShiftRight}, // DECCKM
367	"\x1b[OD":   {Type: KeyShiftLeft},  // DECCKM
368	"\x1b[a":    {Type: KeyShiftUp},    // urxvt
369	"\x1b[b":    {Type: KeyShiftDown},  // urxvt
370	"\x1b[c":    {Type: KeyShiftRight}, // urxvt
371	"\x1b[d":    {Type: KeyShiftLeft},  // urxvt
372	"\x1b[1;3A": {Type: KeyUp, Alt: true},
373	"\x1b[1;3B": {Type: KeyDown, Alt: true},
374	"\x1b[1;3C": {Type: KeyRight, Alt: true},
375	"\x1b[1;3D": {Type: KeyLeft, Alt: true},
376
377	"\x1b[1;4A": {Type: KeyShiftUp, Alt: true},
378	"\x1b[1;4B": {Type: KeyShiftDown, Alt: true},
379	"\x1b[1;4C": {Type: KeyShiftRight, Alt: true},
380	"\x1b[1;4D": {Type: KeyShiftLeft, Alt: true},
381
382	"\x1b[1;5A": {Type: KeyCtrlUp},
383	"\x1b[1;5B": {Type: KeyCtrlDown},
384	"\x1b[1;5C": {Type: KeyCtrlRight},
385	"\x1b[1;5D": {Type: KeyCtrlLeft},
386	"\x1b[Oa":   {Type: KeyCtrlUp, Alt: true},    // urxvt
387	"\x1b[Ob":   {Type: KeyCtrlDown, Alt: true},  // urxvt
388	"\x1b[Oc":   {Type: KeyCtrlRight, Alt: true}, // urxvt
389	"\x1b[Od":   {Type: KeyCtrlLeft, Alt: true},  // urxvt
390	"\x1b[1;6A": {Type: KeyCtrlShiftUp},
391	"\x1b[1;6B": {Type: KeyCtrlShiftDown},
392	"\x1b[1;6C": {Type: KeyCtrlShiftRight},
393	"\x1b[1;6D": {Type: KeyCtrlShiftLeft},
394	"\x1b[1;7A": {Type: KeyCtrlUp, Alt: true},
395	"\x1b[1;7B": {Type: KeyCtrlDown, Alt: true},
396	"\x1b[1;7C": {Type: KeyCtrlRight, Alt: true},
397	"\x1b[1;7D": {Type: KeyCtrlLeft, Alt: true},
398	"\x1b[1;8A": {Type: KeyCtrlShiftUp, Alt: true},
399	"\x1b[1;8B": {Type: KeyCtrlShiftDown, Alt: true},
400	"\x1b[1;8C": {Type: KeyCtrlShiftRight, Alt: true},
401	"\x1b[1;8D": {Type: KeyCtrlShiftLeft, Alt: true},
402
403	// Miscellaneous keys
404	"\x1b[Z": {Type: KeyShiftTab},
405
406	"\x1b[2~":   {Type: KeyInsert},
407	"\x1b[3;2~": {Type: KeyInsert, Alt: true},
408
409	"\x1b[3~":   {Type: KeyDelete},
410	"\x1b[3;3~": {Type: KeyDelete, Alt: true},
411
412	"\x1b[5~":   {Type: KeyPgUp},
413	"\x1b[5;3~": {Type: KeyPgUp, Alt: true},
414	"\x1b[5;5~": {Type: KeyCtrlPgUp},
415	"\x1b[5^":   {Type: KeyCtrlPgUp}, // urxvt
416	"\x1b[5;7~": {Type: KeyCtrlPgUp, Alt: true},
417
418	"\x1b[6~":   {Type: KeyPgDown},
419	"\x1b[6;3~": {Type: KeyPgDown, Alt: true},
420	"\x1b[6;5~": {Type: KeyCtrlPgDown},
421	"\x1b[6^":   {Type: KeyCtrlPgDown}, // urxvt
422	"\x1b[6;7~": {Type: KeyCtrlPgDown, Alt: true},
423
424	"\x1b[1~":   {Type: KeyHome},
425	"\x1b[H":    {Type: KeyHome},                     // xterm, lxterm
426	"\x1b[1;3H": {Type: KeyHome, Alt: true},          // xterm, lxterm
427	"\x1b[1;5H": {Type: KeyCtrlHome},                 // xterm, lxterm
428	"\x1b[1;7H": {Type: KeyCtrlHome, Alt: true},      // xterm, lxterm
429	"\x1b[1;2H": {Type: KeyShiftHome},                // xterm, lxterm
430	"\x1b[1;4H": {Type: KeyShiftHome, Alt: true},     // xterm, lxterm
431	"\x1b[1;6H": {Type: KeyCtrlShiftHome},            // xterm, lxterm
432	"\x1b[1;8H": {Type: KeyCtrlShiftHome, Alt: true}, // xterm, lxterm
433
434	"\x1b[4~":   {Type: KeyEnd},
435	"\x1b[F":    {Type: KeyEnd},                     // xterm, lxterm
436	"\x1b[1;3F": {Type: KeyEnd, Alt: true},          // xterm, lxterm
437	"\x1b[1;5F": {Type: KeyCtrlEnd},                 // xterm, lxterm
438	"\x1b[1;7F": {Type: KeyCtrlEnd, Alt: true},      // xterm, lxterm
439	"\x1b[1;2F": {Type: KeyShiftEnd},                // xterm, lxterm
440	"\x1b[1;4F": {Type: KeyShiftEnd, Alt: true},     // xterm, lxterm
441	"\x1b[1;6F": {Type: KeyCtrlShiftEnd},            // xterm, lxterm
442	"\x1b[1;8F": {Type: KeyCtrlShiftEnd, Alt: true}, // xterm, lxterm
443
444	"\x1b[7~": {Type: KeyHome},          // urxvt
445	"\x1b[7^": {Type: KeyCtrlHome},      // urxvt
446	"\x1b[7$": {Type: KeyShiftHome},     // urxvt
447	"\x1b[7@": {Type: KeyCtrlShiftHome}, // urxvt
448
449	"\x1b[8~": {Type: KeyEnd},          // urxvt
450	"\x1b[8^": {Type: KeyCtrlEnd},      // urxvt
451	"\x1b[8$": {Type: KeyShiftEnd},     // urxvt
452	"\x1b[8@": {Type: KeyCtrlShiftEnd}, // urxvt
453
454	// Function keys, Linux console
455	"\x1b[[A": {Type: KeyF1}, // linux console
456	"\x1b[[B": {Type: KeyF2}, // linux console
457	"\x1b[[C": {Type: KeyF3}, // linux console
458	"\x1b[[D": {Type: KeyF4}, // linux console
459	"\x1b[[E": {Type: KeyF5}, // linux console
460
461	// Function keys, X11
462	"\x1bOP": {Type: KeyF1}, // vt100, xterm
463	"\x1bOQ": {Type: KeyF2}, // vt100, xterm
464	"\x1bOR": {Type: KeyF3}, // vt100, xterm
465	"\x1bOS": {Type: KeyF4}, // vt100, xterm
466
467	"\x1b[1;3P": {Type: KeyF1, Alt: true}, // vt100, xterm
468	"\x1b[1;3Q": {Type: KeyF2, Alt: true}, // vt100, xterm
469	"\x1b[1;3R": {Type: KeyF3, Alt: true}, // vt100, xterm
470	"\x1b[1;3S": {Type: KeyF4, Alt: true}, // vt100, xterm
471
472	"\x1b[11~": {Type: KeyF1}, // urxvt
473	"\x1b[12~": {Type: KeyF2}, // urxvt
474	"\x1b[13~": {Type: KeyF3}, // urxvt
475	"\x1b[14~": {Type: KeyF4}, // urxvt
476
477	"\x1b[15~": {Type: KeyF5}, // vt100, xterm, also urxvt
478
479	"\x1b[15;3~": {Type: KeyF5, Alt: true}, // vt100, xterm, also urxvt
480
481	"\x1b[17~": {Type: KeyF6},  // vt100, xterm, also urxvt
482	"\x1b[18~": {Type: KeyF7},  // vt100, xterm, also urxvt
483	"\x1b[19~": {Type: KeyF8},  // vt100, xterm, also urxvt
484	"\x1b[20~": {Type: KeyF9},  // vt100, xterm, also urxvt
485	"\x1b[21~": {Type: KeyF10}, // vt100, xterm, also urxvt
486
487	"\x1b[17;3~": {Type: KeyF6, Alt: true},  // vt100, xterm
488	"\x1b[18;3~": {Type: KeyF7, Alt: true},  // vt100, xterm
489	"\x1b[19;3~": {Type: KeyF8, Alt: true},  // vt100, xterm
490	"\x1b[20;3~": {Type: KeyF9, Alt: true},  // vt100, xterm
491	"\x1b[21;3~": {Type: KeyF10, Alt: true}, // vt100, xterm
492
493	"\x1b[23~": {Type: KeyF11}, // vt100, xterm, also urxvt
494	"\x1b[24~": {Type: KeyF12}, // vt100, xterm, also urxvt
495
496	"\x1b[23;3~": {Type: KeyF11, Alt: true}, // vt100, xterm
497	"\x1b[24;3~": {Type: KeyF12, Alt: true}, // vt100, xterm
498
499	"\x1b[1;2P": {Type: KeyF13},
500	"\x1b[1;2Q": {Type: KeyF14},
501
502	"\x1b[25~": {Type: KeyF13}, // vt100, xterm, also urxvt
503	"\x1b[26~": {Type: KeyF14}, // vt100, xterm, also urxvt
504
505	"\x1b[25;3~": {Type: KeyF13, Alt: true}, // vt100, xterm
506	"\x1b[26;3~": {Type: KeyF14, Alt: true}, // vt100, xterm
507
508	"\x1b[1;2R": {Type: KeyF15},
509	"\x1b[1;2S": {Type: KeyF16},
510
511	"\x1b[28~": {Type: KeyF15}, // vt100, xterm, also urxvt
512	"\x1b[29~": {Type: KeyF16}, // vt100, xterm, also urxvt
513
514	"\x1b[28;3~": {Type: KeyF15, Alt: true}, // vt100, xterm
515	"\x1b[29;3~": {Type: KeyF16, Alt: true}, // vt100, xterm
516
517	"\x1b[15;2~": {Type: KeyF17},
518	"\x1b[17;2~": {Type: KeyF18},
519	"\x1b[18;2~": {Type: KeyF19},
520	"\x1b[19;2~": {Type: KeyF20},
521
522	"\x1b[31~": {Type: KeyF17},
523	"\x1b[32~": {Type: KeyF18},
524	"\x1b[33~": {Type: KeyF19},
525	"\x1b[34~": {Type: KeyF20},
526
527	// Powershell sequences.
528	"\x1bOA": {Type: KeyUp, Alt: false},
529	"\x1bOB": {Type: KeyDown, Alt: false},
530	"\x1bOC": {Type: KeyRight, Alt: false},
531	"\x1bOD": {Type: KeyLeft, Alt: false},
532}
533
534// unknownInputByteMsg is reported by the input reader when an invalid
535// utf-8 byte is detected on the input. Currently, it is not handled
536// further by bubbletea. However, having this event makes it possible
537// to troubleshoot invalid inputs.
538type unknownInputByteMsg byte
539
540func (u unknownInputByteMsg) String() string {
541	return fmt.Sprintf("?%#02x?", int(u))
542}
543
544// unknownCSISequenceMsg is reported by the input reader when an
545// unrecognized CSI sequence is detected on the input. Currently, it
546// is not handled further by bubbletea. However, having this event
547// makes it possible to troubleshoot invalid inputs.
548type unknownCSISequenceMsg []byte
549
550func (u unknownCSISequenceMsg) String() string {
551	return fmt.Sprintf("?CSI%+v?", []byte(u)[2:])
552}
553
554var spaceRunes = []rune{' '}
555
556// readAnsiInputs reads keypress and mouse inputs from a TTY and produces messages
557// containing information about the key or mouse events accordingly.
558func readAnsiInputs(ctx context.Context, msgs chan<- Msg, input io.Reader) error {
559	var buf [256]byte
560
561	var leftOverFromPrevIteration []byte
562loop:
563	for {
564		// Read and block.
565		numBytes, err := input.Read(buf[:])
566		if err != nil {
567			return fmt.Errorf("error reading input: %w", err)
568		}
569		b := buf[:numBytes]
570		if leftOverFromPrevIteration != nil {
571			b = append(leftOverFromPrevIteration, b...)
572		}
573
574		// If we had a short read (numBytes < len(buf)), we're sure that
575		// the end of this read is an event boundary, so there is no doubt
576		// if we are encountering the end of the buffer while parsing a message.
577		// However, if we've succeeded in filling up the buffer, there may
578		// be more data in the OS buffer ready to be read in, to complete
579		// the last message in the input. In that case, we will retry with
580		// the left over data in the next iteration.
581		canHaveMoreData := numBytes == len(buf)
582
583		var i, w int
584		for i, w = 0, 0; i < len(b); i += w {
585			var msg Msg
586			w, msg = detectOneMsg(b[i:], canHaveMoreData)
587			if w == 0 {
588				// Expecting more bytes beyond the current buffer. Try waiting
589				// for more input.
590				leftOverFromPrevIteration = make([]byte, 0, len(b[i:])+len(buf))
591				leftOverFromPrevIteration = append(leftOverFromPrevIteration, b[i:]...)
592				continue loop
593			}
594
595			select {
596			case msgs <- msg:
597			case <-ctx.Done():
598				err := ctx.Err()
599				if err != nil {
600					err = fmt.Errorf("found context error while reading input: %w", err)
601				}
602				return err
603			}
604		}
605		leftOverFromPrevIteration = nil
606	}
607}
608
609var (
610	unknownCSIRe  = regexp.MustCompile(`^\x1b\[[\x30-\x3f]*[\x20-\x2f]*[\x40-\x7e]`)
611	mouseSGRRegex = regexp.MustCompile(`(\d+);(\d+);(\d+)([Mm])`)
612)
613
614func detectOneMsg(b []byte, canHaveMoreData bool) (w int, msg Msg) {
615	// Detect mouse events.
616	// X10 mouse events have a length of 6 bytes
617	const mouseEventX10Len = 6
618	if len(b) >= mouseEventX10Len && b[0] == '\x1b' && b[1] == '[' {
619		switch b[2] {
620		case 'M':
621			return mouseEventX10Len, MouseMsg(parseX10MouseEvent(b))
622		case '<':
623			if matchIndices := mouseSGRRegex.FindSubmatchIndex(b[3:]); matchIndices != nil {
624				// SGR mouse events length is the length of the match plus the length of the escape sequence
625				mouseEventSGRLen := matchIndices[1] + 3 //nolint:gomnd
626				return mouseEventSGRLen, MouseMsg(parseSGRMouseEvent(b))
627			}
628		}
629	}
630
631	// Detect focus events.
632	var foundRF bool
633	foundRF, w, msg = detectReportFocus(b)
634	if foundRF {
635		return w, msg
636	}
637
638	// Detect bracketed paste.
639	var foundbp bool
640	foundbp, w, msg = detectBracketedPaste(b)
641	if foundbp {
642		return w, msg
643	}
644
645	// Detect escape sequence and control characters other than NUL,
646	// possibly with an escape character in front to mark the Alt
647	// modifier.
648	var foundSeq bool
649	foundSeq, w, msg = detectSequence(b)
650	if foundSeq {
651		return w, msg
652	}
653
654	// No non-NUL control character or escape sequence.
655	// If we are seeing at least an escape character, remember it for later below.
656	alt := false
657	i := 0
658	if b[0] == '\x1b' {
659		alt = true
660		i++
661	}
662
663	// Are we seeing a standalone NUL? This is not handled by detectSequence().
664	if i < len(b) && b[i] == 0 {
665		return i + 1, KeyMsg{Type: keyNUL, Alt: alt}
666	}
667
668	// Find the longest sequence of runes that are not control
669	// characters from this point.
670	var runes []rune
671	for rw := 0; i < len(b); i += rw {
672		var r rune
673		r, rw = utf8.DecodeRune(b[i:])
674		if r == utf8.RuneError || r <= rune(keyUS) || r == rune(keyDEL) || r == ' ' {
675			// Rune errors are handled below; control characters and spaces will
676			// be handled by detectSequence in the next call to detectOneMsg.
677			break
678		}
679		runes = append(runes, r)
680		if alt {
681			// We only support a single rune after an escape alt modifier.
682			i += rw
683			break
684		}
685	}
686	if i >= len(b) && canHaveMoreData {
687		// We have encountered the end of the input buffer. Alas, we can't
688		// be sure whether the data in the remainder of the buffer is
689		// complete (maybe there was a short read). Instead of sending anything
690		// dumb to the message channel, do a short read. The outer loop will
691		// handle this case by extending the buffer as necessary.
692		return 0, nil
693	}
694
695	// If we found at least one rune, we report the bunch of them as
696	// a single KeyRunes or KeySpace event.
697	if len(runes) > 0 {
698		k := Key{Type: KeyRunes, Runes: runes, Alt: alt}
699		if len(runes) == 1 && runes[0] == ' ' {
700			k.Type = KeySpace
701		}
702		return i, KeyMsg(k)
703	}
704
705	// We didn't find an escape sequence, nor a valid rune. Was this a
706	// lone escape character at the end of the input?
707	if alt && len(b) == 1 {
708		return 1, KeyMsg(Key{Type: KeyEscape})
709	}
710
711	// The character at the current position is neither an escape
712	// sequence, a valid rune start or a sole escape character. Report
713	// it as an invalid byte.
714	return 1, unknownInputByteMsg(b[0])
715}