1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
package terminal
import "github.com/gdamore/tcell/v2"
// Encode turns a key press into the bytes a terminal program expects to read.
//
// applicationCursor is the screen's DECCKM setting: a program that has asked
// for application cursor keys expects ESC O A for the up arrow rather than
// ESC [ A, and gets the arrow keys wrong if it is given the other form.
//
// A key with no terminal meaning encodes to nothing at all, which the caller
// should treat as "nothing to send" rather than as an empty line.
//
// terminal.Encode(tcell.NewEventKey(tcell.KeyEnter, 0, tcell.ModNone), false)
// // []byte{'\r'}
func Encode(ev *tcell.EventKey, applicationCursor bool) []byte {
if sequence, ok := encodeCursor(ev.Key(), applicationCursor); ok {
return sequence
}
if sequence, ok := namedKeys[ev.Key()]; ok {
return []byte(sequence)
}
if ev.Key() == tcell.KeyRune {
return encodeRune(ev)
}
return encodeControl(ev)
}
// cursorKeys are the four arrows and the two keys that travel with them, whose
// encoding depends on the mode the program asked for.
var cursorKeys = map[tcell.Key]byte{
tcell.KeyUp: 'A',
tcell.KeyDown: 'B',
tcell.KeyRight: 'C',
tcell.KeyLeft: 'D',
tcell.KeyHome: 'H',
tcell.KeyEnd: 'F',
}
// encodeCursor encodes an arrow, Home or End in whichever form the program is
// expecting.
func encodeCursor(key tcell.Key, applicationCursor bool) ([]byte, bool) {
final, ok := cursorKeys[key]
if !ok {
return nil, false
}
introducer := byte('[')
if applicationCursor {
introducer = 'O'
}
return []byte{escape, introducer, final}, true
}
// namedKeys are the keys with a fixed sequence of their own.
var namedKeys = map[tcell.Key]string{
tcell.KeyEnter: "\r",
tcell.KeyTab: "\t",
tcell.KeyEscape: "\x1b",
tcell.KeyBackspace: "\x7f",
tcell.KeyBackspace2: "\x7f",
tcell.KeyBacktab: "\x1b[Z",
tcell.KeyInsert: "\x1b[2~",
tcell.KeyDelete: "\x1b[3~",
tcell.KeyPgUp: "\x1b[5~",
tcell.KeyPgDn: "\x1b[6~",
tcell.KeyF1: "\x1bOP",
tcell.KeyF2: "\x1bOQ",
tcell.KeyF3: "\x1bOR",
tcell.KeyF4: "\x1bOS",
tcell.KeyF5: "\x1b[15~",
tcell.KeyF6: "\x1b[17~",
tcell.KeyF7: "\x1b[18~",
tcell.KeyF8: "\x1b[19~",
tcell.KeyF9: "\x1b[20~",
tcell.KeyF10: "\x1b[21~",
tcell.KeyF11: "\x1b[23~",
tcell.KeyF12: "\x1b[24~",
}
// encodeRune encodes a printable character, with the escape prefix that stands
// for Alt.
func encodeRune(ev *tcell.EventKey) []byte {
text := []byte(string(ev.Rune()))
if ev.Modifiers()&tcell.ModAlt != 0 {
return append([]byte{escape}, text...)
}
return text
}
// encodeControl encodes a Ctrl-key press.
//
// tcell does not report the control byte itself: reading 0x03 from the
// terminal, it posts KeyCtrlSpace+3, and KeyCtrlSpace is 64. So the whole
// range 64…95 stands for the control bytes 0…31, and turning a key back into
// what a terminal expects means subtracting that offset again.
//
// Getting this wrong is silent: every Ctrl-key would simply send nothing.
func encodeControl(ev *tcell.EventKey) []byte {
key := ev.Key()
if key < tcell.KeyCtrlSpace || key > tcell.KeyCtrlUnderscore {
return nil
}
control := byte(key - tcell.KeyCtrlSpace)
if ev.Modifiers()&tcell.ModAlt != 0 {
return []byte{escape, control}
}
return []byte{control}
}
|