1package uv
2
3import (
4 "strconv"
5 "strings"
6
7 "github.com/charmbracelet/x/ansi"
8 "github.com/xo/terminfo"
9)
10
11// buildKeysTable builds a table of key sequences and their corresponding key
12// events based on the VT100/VT200, XTerm, and Urxvt terminal specs.
13func buildKeysTable(flags LegacyKeyEncoding, term string, useTerminfo bool) map[string]Key {
14 nul := Key{Code: KeySpace, Mod: ModCtrl} // ctrl+@ or ctrl+space
15 if flags&flagCtrlAt != 0 {
16 nul = Key{Code: '@', Mod: ModCtrl}
17 }
18
19 tab := Key{Code: KeyTab} // ctrl+i or tab
20 if flags&flagCtrlI != 0 {
21 tab = Key{Code: 'i', Mod: ModCtrl}
22 }
23
24 enter := Key{Code: KeyEnter} // ctrl+m or enter
25 if flags&flagCtrlM != 0 {
26 enter = Key{Code: 'm', Mod: ModCtrl}
27 }
28
29 esc := Key{Code: KeyEscape} // ctrl+[ or escape
30 if flags&flagCtrlOpenBracket != 0 {
31 esc = Key{Code: '[', Mod: ModCtrl} // ctrl+[ or escape
32 }
33
34 del := Key{Code: KeyBackspace}
35 if flags&flagBackspace != 0 {
36 del.Code = KeyDelete
37 }
38
39 find := Key{Code: KeyHome}
40 if flags&flagFind != 0 {
41 find.Code = KeyFind
42 }
43
44 sel := Key{Code: KeyEnd}
45 if flags&flagSelect != 0 {
46 sel.Code = KeySelect
47 }
48
49 // The following is a table of key sequences and their corresponding key
50 // events based on the VT100/VT200 terminal specs.
51 //
52 // See: https://vt100.net/docs/vt100-ug/chapter3.html#S3.2
53 // See: https://vt100.net/docs/vt220-rm/chapter3.html
54 //
55 // XXX: These keys may be overwritten by other options like XTerm or
56 // Terminfo.
57 table := map[string]Key{
58 // C0 control characters
59 string(byte(ansi.NUL)): nul,
60 string(byte(ansi.SOH)): {Code: 'a', Mod: ModCtrl},
61 string(byte(ansi.STX)): {Code: 'b', Mod: ModCtrl},
62 string(byte(ansi.ETX)): {Code: 'c', Mod: ModCtrl},
63 string(byte(ansi.EOT)): {Code: 'd', Mod: ModCtrl},
64 string(byte(ansi.ENQ)): {Code: 'e', Mod: ModCtrl},
65 string(byte(ansi.ACK)): {Code: 'f', Mod: ModCtrl},
66 string(byte(ansi.BEL)): {Code: 'g', Mod: ModCtrl},
67 string(byte(ansi.BS)): {Code: 'h', Mod: ModCtrl},
68 string(byte(ansi.HT)): tab,
69 string(byte(ansi.LF)): {Code: 'j', Mod: ModCtrl},
70 string(byte(ansi.VT)): {Code: 'k', Mod: ModCtrl},
71 string(byte(ansi.FF)): {Code: 'l', Mod: ModCtrl},
72 string(byte(ansi.CR)): enter,
73 string(byte(ansi.SO)): {Code: 'n', Mod: ModCtrl},
74 string(byte(ansi.SI)): {Code: 'o', Mod: ModCtrl},
75 string(byte(ansi.DLE)): {Code: 'p', Mod: ModCtrl},
76 string(byte(ansi.DC1)): {Code: 'q', Mod: ModCtrl},
77 string(byte(ansi.DC2)): {Code: 'r', Mod: ModCtrl},
78 string(byte(ansi.DC3)): {Code: 's', Mod: ModCtrl},
79 string(byte(ansi.DC4)): {Code: 't', Mod: ModCtrl},
80 string(byte(ansi.NAK)): {Code: 'u', Mod: ModCtrl},
81 string(byte(ansi.SYN)): {Code: 'v', Mod: ModCtrl},
82 string(byte(ansi.ETB)): {Code: 'w', Mod: ModCtrl},
83 string(byte(ansi.CAN)): {Code: 'x', Mod: ModCtrl},
84 string(byte(ansi.EM)): {Code: 'y', Mod: ModCtrl},
85 string(byte(ansi.SUB)): {Code: 'z', Mod: ModCtrl},
86 string(byte(ansi.ESC)): esc,
87 string(byte(ansi.FS)): {Code: '\\', Mod: ModCtrl},
88 string(byte(ansi.GS)): {Code: ']', Mod: ModCtrl},
89 string(byte(ansi.RS)): {Code: '^', Mod: ModCtrl},
90 string(byte(ansi.US)): {Code: '_', Mod: ModCtrl},
91
92 // Special keys in G0
93 string(byte(ansi.SP)): {Code: KeySpace, Text: " "},
94 string(byte(ansi.DEL)): del,
95
96 // Special keys
97
98 "\x1b[Z": {Code: KeyTab, Mod: ModShift},
99
100 "\x1b[1~": find,
101 "\x1b[2~": {Code: KeyInsert},
102 "\x1b[3~": {Code: KeyDelete},
103 "\x1b[4~": sel,
104 "\x1b[5~": {Code: KeyPgUp},
105 "\x1b[6~": {Code: KeyPgDown},
106 "\x1b[7~": {Code: KeyHome},
107 "\x1b[8~": {Code: KeyEnd},
108
109 // Normal mode
110 "\x1b[A": {Code: KeyUp},
111 "\x1b[B": {Code: KeyDown},
112 "\x1b[C": {Code: KeyRight},
113 "\x1b[D": {Code: KeyLeft},
114 "\x1b[E": {Code: KeyBegin},
115 "\x1b[F": {Code: KeyEnd},
116 "\x1b[H": {Code: KeyHome},
117 "\x1b[P": {Code: KeyF1},
118 "\x1b[Q": {Code: KeyF2},
119 "\x1b[R": {Code: KeyF3},
120 "\x1b[S": {Code: KeyF4},
121
122 // Application Cursor Key Mode (DECCKM)
123 "\x1bOA": {Code: KeyUp},
124 "\x1bOB": {Code: KeyDown},
125 "\x1bOC": {Code: KeyRight},
126 "\x1bOD": {Code: KeyLeft},
127 "\x1bOE": {Code: KeyBegin},
128 "\x1bOF": {Code: KeyEnd},
129 "\x1bOH": {Code: KeyHome},
130 "\x1bOP": {Code: KeyF1},
131 "\x1bOQ": {Code: KeyF2},
132 "\x1bOR": {Code: KeyF3},
133 "\x1bOS": {Code: KeyF4},
134
135 // Keypad Application Mode (DECKPAM)
136
137 "\x1bOM": {Code: KeyKpEnter},
138 "\x1bOX": {Code: KeyKpEqual},
139 "\x1bOj": {Code: KeyKpMultiply},
140 "\x1bOk": {Code: KeyKpPlus},
141 "\x1bOl": {Code: KeyKpComma},
142 "\x1bOm": {Code: KeyKpMinus},
143 "\x1bOn": {Code: KeyKpDecimal},
144 "\x1bOo": {Code: KeyKpDivide},
145 "\x1bOp": {Code: KeyKp0},
146 "\x1bOq": {Code: KeyKp1},
147 "\x1bOr": {Code: KeyKp2},
148 "\x1bOs": {Code: KeyKp3},
149 "\x1bOt": {Code: KeyKp4},
150 "\x1bOu": {Code: KeyKp5},
151 "\x1bOv": {Code: KeyKp6},
152 "\x1bOw": {Code: KeyKp7},
153 "\x1bOx": {Code: KeyKp8},
154 "\x1bOy": {Code: KeyKp9},
155
156 // Function keys
157
158 "\x1b[11~": {Code: KeyF1},
159 "\x1b[12~": {Code: KeyF2},
160 "\x1b[13~": {Code: KeyF3},
161 "\x1b[14~": {Code: KeyF4},
162 "\x1b[15~": {Code: KeyF5},
163 "\x1b[17~": {Code: KeyF6},
164 "\x1b[18~": {Code: KeyF7},
165 "\x1b[19~": {Code: KeyF8},
166 "\x1b[20~": {Code: KeyF9},
167 "\x1b[21~": {Code: KeyF10},
168 "\x1b[23~": {Code: KeyF11},
169 "\x1b[24~": {Code: KeyF12},
170 "\x1b[25~": {Code: KeyF13},
171 "\x1b[26~": {Code: KeyF14},
172 "\x1b[28~": {Code: KeyF15},
173 "\x1b[29~": {Code: KeyF16},
174 "\x1b[31~": {Code: KeyF17},
175 "\x1b[32~": {Code: KeyF18},
176 "\x1b[33~": {Code: KeyF19},
177 "\x1b[34~": {Code: KeyF20},
178 }
179
180 // CSI ~ sequence keys
181 csiTildeKeys := map[string]Key{
182 "1": find, "2": {Code: KeyInsert},
183 "3": {Code: KeyDelete}, "4": sel,
184 "5": {Code: KeyPgUp}, "6": {Code: KeyPgDown},
185 "7": {Code: KeyHome}, "8": {Code: KeyEnd},
186 // There are no 9 and 10 keys
187 "11": {Code: KeyF1}, "12": {Code: KeyF2},
188 "13": {Code: KeyF3}, "14": {Code: KeyF4},
189 "15": {Code: KeyF5}, "17": {Code: KeyF6},
190 "18": {Code: KeyF7}, "19": {Code: KeyF8},
191 "20": {Code: KeyF9}, "21": {Code: KeyF10},
192 "23": {Code: KeyF11}, "24": {Code: KeyF12},
193 "25": {Code: KeyF13}, "26": {Code: KeyF14},
194 "28": {Code: KeyF15}, "29": {Code: KeyF16},
195 "31": {Code: KeyF17}, "32": {Code: KeyF18},
196 "33": {Code: KeyF19}, "34": {Code: KeyF20},
197 }
198
199 // URxvt keys
200 // See https://manpages.ubuntu.com/manpages/trusty/man7/urxvt.7.html#key%20codes
201 table["\x1b[a"] = Key{Code: KeyUp, Mod: ModShift}
202 table["\x1b[b"] = Key{Code: KeyDown, Mod: ModShift}
203 table["\x1b[c"] = Key{Code: KeyRight, Mod: ModShift}
204 table["\x1b[d"] = Key{Code: KeyLeft, Mod: ModShift}
205 table["\x1bOa"] = Key{Code: KeyUp, Mod: ModCtrl}
206 table["\x1bOb"] = Key{Code: KeyDown, Mod: ModCtrl}
207 table["\x1bOc"] = Key{Code: KeyRight, Mod: ModCtrl}
208 table["\x1bOd"] = Key{Code: KeyLeft, Mod: ModCtrl}
209 //nolint:godox
210 // TODO: invistigate if shift-ctrl arrow keys collide with DECCKM keys i.e.
211 // "\x1bOA", "\x1bOB", "\x1bOC", "\x1bOD"
212
213 // URxvt modifier CSI ~ keys
214 for k, v := range csiTildeKeys {
215 key := v
216 // Normal (no modifier) already defined part of VT100/VT200
217 // Shift modifier
218 key.Mod = ModShift
219 table["\x1b["+k+"$"] = key
220 // Ctrl modifier
221 key.Mod = ModCtrl
222 table["\x1b["+k+"^"] = key
223 // Shift-Ctrl modifier
224 key.Mod = ModShift | ModCtrl
225 table["\x1b["+k+"@"] = key
226 }
227
228 // URxvt F keys
229 // Note: Shift + F1-F10 generates F11-F20.
230 // This means Shift + F1 and Shift + F2 will generate F11 and F12, the same
231 // applies to Ctrl + Shift F1 & F2.
232 //
233 // P.S. Don't like this? Blame URxvt, configure your terminal to use
234 // different escapes like XTerm, or switch to a better terminal ¯\_(ツ)_/¯
235 //
236 // See https://manpages.ubuntu.com/manpages/trusty/man7/urxvt.7.html#key%20codes
237 table["\x1b[23$"] = Key{Code: KeyF11, Mod: ModShift}
238 table["\x1b[24$"] = Key{Code: KeyF12, Mod: ModShift}
239 table["\x1b[25$"] = Key{Code: KeyF13, Mod: ModShift}
240 table["\x1b[26$"] = Key{Code: KeyF14, Mod: ModShift}
241 table["\x1b[28$"] = Key{Code: KeyF15, Mod: ModShift}
242 table["\x1b[29$"] = Key{Code: KeyF16, Mod: ModShift}
243 table["\x1b[31$"] = Key{Code: KeyF17, Mod: ModShift}
244 table["\x1b[32$"] = Key{Code: KeyF18, Mod: ModShift}
245 table["\x1b[33$"] = Key{Code: KeyF19, Mod: ModShift}
246 table["\x1b[34$"] = Key{Code: KeyF20, Mod: ModShift}
247 table["\x1b[11^"] = Key{Code: KeyF1, Mod: ModCtrl}
248 table["\x1b[12^"] = Key{Code: KeyF2, Mod: ModCtrl}
249 table["\x1b[13^"] = Key{Code: KeyF3, Mod: ModCtrl}
250 table["\x1b[14^"] = Key{Code: KeyF4, Mod: ModCtrl}
251 table["\x1b[15^"] = Key{Code: KeyF5, Mod: ModCtrl}
252 table["\x1b[17^"] = Key{Code: KeyF6, Mod: ModCtrl}
253 table["\x1b[18^"] = Key{Code: KeyF7, Mod: ModCtrl}
254 table["\x1b[19^"] = Key{Code: KeyF8, Mod: ModCtrl}
255 table["\x1b[20^"] = Key{Code: KeyF9, Mod: ModCtrl}
256 table["\x1b[21^"] = Key{Code: KeyF10, Mod: ModCtrl}
257 table["\x1b[23^"] = Key{Code: KeyF11, Mod: ModCtrl}
258 table["\x1b[24^"] = Key{Code: KeyF12, Mod: ModCtrl}
259 table["\x1b[25^"] = Key{Code: KeyF13, Mod: ModCtrl}
260 table["\x1b[26^"] = Key{Code: KeyF14, Mod: ModCtrl}
261 table["\x1b[28^"] = Key{Code: KeyF15, Mod: ModCtrl}
262 table["\x1b[29^"] = Key{Code: KeyF16, Mod: ModCtrl}
263 table["\x1b[31^"] = Key{Code: KeyF17, Mod: ModCtrl}
264 table["\x1b[32^"] = Key{Code: KeyF18, Mod: ModCtrl}
265 table["\x1b[33^"] = Key{Code: KeyF19, Mod: ModCtrl}
266 table["\x1b[34^"] = Key{Code: KeyF20, Mod: ModCtrl}
267 table["\x1b[23@"] = Key{Code: KeyF11, Mod: ModShift | ModCtrl}
268 table["\x1b[24@"] = Key{Code: KeyF12, Mod: ModShift | ModCtrl}
269 table["\x1b[25@"] = Key{Code: KeyF13, Mod: ModShift | ModCtrl}
270 table["\x1b[26@"] = Key{Code: KeyF14, Mod: ModShift | ModCtrl}
271 table["\x1b[28@"] = Key{Code: KeyF15, Mod: ModShift | ModCtrl}
272 table["\x1b[29@"] = Key{Code: KeyF16, Mod: ModShift | ModCtrl}
273 table["\x1b[31@"] = Key{Code: KeyF17, Mod: ModShift | ModCtrl}
274 table["\x1b[32@"] = Key{Code: KeyF18, Mod: ModShift | ModCtrl}
275 table["\x1b[33@"] = Key{Code: KeyF19, Mod: ModShift | ModCtrl}
276 table["\x1b[34@"] = Key{Code: KeyF20, Mod: ModShift | ModCtrl}
277
278 // Register Alt + <key> combinations
279 // XXX: this must come after URxvt but before XTerm keys to register URxvt
280 // keys with alt modifier
281 tmap := map[string]Key{}
282 for seq, key := range table {
283 key := key
284 key.Mod |= ModAlt
285 key.Text = "" // Clear runes
286 tmap["\x1b"+seq] = key
287 }
288 for seq, key := range tmap {
289 table[seq] = key
290 }
291
292 // XTerm modifiers
293 // These are offset by 1 to be compatible with our Mod type.
294 // See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-PC-Style-Function-Keys
295 modifiers := []KeyMod{
296 ModShift, // 1
297 ModAlt, // 2
298 ModShift | ModAlt, // 3
299 ModCtrl, // 4
300 ModShift | ModCtrl, // 5
301 ModAlt | ModCtrl, // 6
302 ModShift | ModAlt | ModCtrl, // 7
303 ModMeta, // 8
304 ModMeta | ModShift, // 9
305 ModMeta | ModAlt, // 10
306 ModMeta | ModShift | ModAlt, // 11
307 ModMeta | ModCtrl, // 12
308 ModMeta | ModShift | ModCtrl, // 13
309 ModMeta | ModAlt | ModCtrl, // 14
310 ModMeta | ModShift | ModAlt | ModCtrl, // 15
311 }
312
313 // SS3 keypad function keys
314 ss3FuncKeys := map[string]Key{
315 // These are defined in XTerm
316 // Taken from Foot keymap.h and XTerm modifyOtherKeys
317 // https://codeberg.org/dnkl/foot/src/branch/master/keymap.h
318 "M": {Code: KeyKpEnter}, "X": {Code: KeyKpEqual},
319 "j": {Code: KeyKpMultiply}, "k": {Code: KeyKpPlus},
320 "l": {Code: KeyKpComma}, "m": {Code: KeyKpMinus},
321 "n": {Code: KeyKpDecimal}, "o": {Code: KeyKpDivide},
322 "p": {Code: KeyKp0}, "q": {Code: KeyKp1},
323 "r": {Code: KeyKp2}, "s": {Code: KeyKp3},
324 "t": {Code: KeyKp4}, "u": {Code: KeyKp5},
325 "v": {Code: KeyKp6}, "w": {Code: KeyKp7},
326 "x": {Code: KeyKp8}, "y": {Code: KeyKp9},
327 }
328
329 // XTerm keys
330 csiFuncKeys := map[string]Key{
331 "A": {Code: KeyUp}, "B": {Code: KeyDown},
332 "C": {Code: KeyRight}, "D": {Code: KeyLeft},
333 "E": {Code: KeyBegin}, "F": {Code: KeyEnd},
334 "H": {Code: KeyHome}, "P": {Code: KeyF1},
335 "Q": {Code: KeyF2}, "R": {Code: KeyF3},
336 "S": {Code: KeyF4},
337 }
338
339 // CSI 27 ; <modifier> ; <code> ~ keys defined in XTerm modifyOtherKeys
340 modifyOtherKeys := map[int]Key{
341 ansi.BS: {Code: KeyBackspace},
342 ansi.HT: {Code: KeyTab},
343 ansi.CR: {Code: KeyEnter},
344 ansi.ESC: {Code: KeyEscape},
345 ansi.DEL: {Code: KeyBackspace},
346 }
347
348 for _, m := range modifiers {
349 // XTerm modifier offset +1
350 xtermMod := strconv.Itoa(int(m) + 1)
351
352 // CSI 1 ; <modifier> <func>
353 for k, v := range csiFuncKeys {
354 // Functions always have a leading 1 param
355 seq := "\x1b[1;" + xtermMod + k
356 key := v
357 key.Mod = m
358 table[seq] = key
359 }
360 // SS3 <modifier> <func>
361 for k, v := range ss3FuncKeys {
362 seq := "\x1bO" + xtermMod + k
363 key := v
364 key.Mod = m
365 table[seq] = key
366 }
367 // CSI <number> ; <modifier> ~
368 for k, v := range csiTildeKeys {
369 seq := "\x1b[" + k + ";" + xtermMod + "~"
370 key := v
371 key.Mod = m
372 table[seq] = key
373 }
374 // CSI 27 ; <modifier> ; <code> ~
375 for k, v := range modifyOtherKeys {
376 code := strconv.Itoa(k)
377 seq := "\x1b[27;" + xtermMod + ";" + code + "~"
378 key := v
379 key.Mod = m
380 table[seq] = key
381 }
382 }
383
384 // Register terminfo keys
385 // XXX: this might override keys already registered in table
386 if useTerminfo {
387 titable := buildTerminfoKeys(flags, term)
388 for seq, key := range titable {
389 table[seq] = key
390 }
391 }
392
393 return table
394}
395
396func buildTerminfoKeys(flags LegacyKeyEncoding, term string) map[string]Key {
397 table := make(map[string]Key)
398 ti, _ := terminfo.Load(term)
399 if ti == nil {
400 return table
401 }
402
403 tiTable := defaultTerminfoKeys(flags)
404
405 // Default keys
406 for name, seq := range ti.StringCapsShort() {
407 if !strings.HasPrefix(name, "k") || len(seq) == 0 {
408 continue
409 }
410
411 if k, ok := tiTable[name]; ok {
412 table[string(seq)] = k
413 }
414 }
415
416 // Extended keys
417 for name, seq := range ti.ExtStringCapsShort() {
418 if !strings.HasPrefix(name, "k") || len(seq) == 0 {
419 continue
420 }
421
422 if k, ok := tiTable[name]; ok {
423 table[string(seq)] = k
424 }
425 }
426
427 return table
428}
429
430// This returns a map of terminfo keys to key events. It's a mix of ncurses
431// terminfo default and user-defined key capabilities.
432// Upper-case caps that are defined in the default terminfo database are
433// - kNXT
434// - kPRV
435// - kHOM
436// - kEND
437// - kDC
438// - kIC
439// - kLFT
440// - kRIT
441//
442// See https://man7.org/linux/man-pages/man5/terminfo.5.html
443// See https://github.com/mirror/ncurses/blob/master/include/Caps-ncurses
444func defaultTerminfoKeys(flags LegacyKeyEncoding) map[string]Key {
445 keys := map[string]Key{
446 "kcuu1": {Code: KeyUp},
447 "kUP": {Code: KeyUp, Mod: ModShift},
448 "kUP3": {Code: KeyUp, Mod: ModAlt},
449 "kUP4": {Code: KeyUp, Mod: ModShift | ModAlt},
450 "kUP5": {Code: KeyUp, Mod: ModCtrl},
451 "kUP6": {Code: KeyUp, Mod: ModShift | ModCtrl},
452 "kUP7": {Code: KeyUp, Mod: ModAlt | ModCtrl},
453 "kUP8": {Code: KeyUp, Mod: ModShift | ModAlt | ModCtrl},
454 "kcud1": {Code: KeyDown},
455 "kDN": {Code: KeyDown, Mod: ModShift},
456 "kDN3": {Code: KeyDown, Mod: ModAlt},
457 "kDN4": {Code: KeyDown, Mod: ModShift | ModAlt},
458 "kDN5": {Code: KeyDown, Mod: ModCtrl},
459 "kDN7": {Code: KeyDown, Mod: ModAlt | ModCtrl},
460 "kDN6": {Code: KeyDown, Mod: ModShift | ModCtrl},
461 "kDN8": {Code: KeyDown, Mod: ModShift | ModAlt | ModCtrl},
462 "kcub1": {Code: KeyLeft},
463 "kLFT": {Code: KeyLeft, Mod: ModShift},
464 "kLFT3": {Code: KeyLeft, Mod: ModAlt},
465 "kLFT4": {Code: KeyLeft, Mod: ModShift | ModAlt},
466 "kLFT5": {Code: KeyLeft, Mod: ModCtrl},
467 "kLFT6": {Code: KeyLeft, Mod: ModShift | ModCtrl},
468 "kLFT7": {Code: KeyLeft, Mod: ModAlt | ModCtrl},
469 "kLFT8": {Code: KeyLeft, Mod: ModShift | ModAlt | ModCtrl},
470 "kcuf1": {Code: KeyRight},
471 "kRIT": {Code: KeyRight, Mod: ModShift},
472 "kRIT3": {Code: KeyRight, Mod: ModAlt},
473 "kRIT4": {Code: KeyRight, Mod: ModShift | ModAlt},
474 "kRIT5": {Code: KeyRight, Mod: ModCtrl},
475 "kRIT6": {Code: KeyRight, Mod: ModShift | ModCtrl},
476 "kRIT7": {Code: KeyRight, Mod: ModAlt | ModCtrl},
477 "kRIT8": {Code: KeyRight, Mod: ModShift | ModAlt | ModCtrl},
478 "kich1": {Code: KeyInsert},
479 "kIC": {Code: KeyInsert, Mod: ModShift},
480 "kIC3": {Code: KeyInsert, Mod: ModAlt},
481 "kIC4": {Code: KeyInsert, Mod: ModShift | ModAlt},
482 "kIC5": {Code: KeyInsert, Mod: ModCtrl},
483 "kIC6": {Code: KeyInsert, Mod: ModShift | ModCtrl},
484 "kIC7": {Code: KeyInsert, Mod: ModAlt | ModCtrl},
485 "kIC8": {Code: KeyInsert, Mod: ModShift | ModAlt | ModCtrl},
486 "kdch1": {Code: KeyDelete},
487 "kDC": {Code: KeyDelete, Mod: ModShift},
488 "kDC3": {Code: KeyDelete, Mod: ModAlt},
489 "kDC4": {Code: KeyDelete, Mod: ModShift | ModAlt},
490 "kDC5": {Code: KeyDelete, Mod: ModCtrl},
491 "kDC6": {Code: KeyDelete, Mod: ModShift | ModCtrl},
492 "kDC7": {Code: KeyDelete, Mod: ModAlt | ModCtrl},
493 "kDC8": {Code: KeyDelete, Mod: ModShift | ModAlt | ModCtrl},
494 "khome": {Code: KeyHome},
495 "kHOM": {Code: KeyHome, Mod: ModShift},
496 "kHOM3": {Code: KeyHome, Mod: ModAlt},
497 "kHOM4": {Code: KeyHome, Mod: ModShift | ModAlt},
498 "kHOM5": {Code: KeyHome, Mod: ModCtrl},
499 "kHOM6": {Code: KeyHome, Mod: ModShift | ModCtrl},
500 "kHOM7": {Code: KeyHome, Mod: ModAlt | ModCtrl},
501 "kHOM8": {Code: KeyHome, Mod: ModShift | ModAlt | ModCtrl},
502 "kend": {Code: KeyEnd},
503 "kEND": {Code: KeyEnd, Mod: ModShift},
504 "kEND3": {Code: KeyEnd, Mod: ModAlt},
505 "kEND4": {Code: KeyEnd, Mod: ModShift | ModAlt},
506 "kEND5": {Code: KeyEnd, Mod: ModCtrl},
507 "kEND6": {Code: KeyEnd, Mod: ModShift | ModCtrl},
508 "kEND7": {Code: KeyEnd, Mod: ModAlt | ModCtrl},
509 "kEND8": {Code: KeyEnd, Mod: ModShift | ModAlt | ModCtrl},
510 "kpp": {Code: KeyPgUp},
511 "kprv": {Code: KeyPgUp},
512 "kPRV": {Code: KeyPgUp, Mod: ModShift},
513 "kPRV3": {Code: KeyPgUp, Mod: ModAlt},
514 "kPRV4": {Code: KeyPgUp, Mod: ModShift | ModAlt},
515 "kPRV5": {Code: KeyPgUp, Mod: ModCtrl},
516 "kPRV6": {Code: KeyPgUp, Mod: ModShift | ModCtrl},
517 "kPRV7": {Code: KeyPgUp, Mod: ModAlt | ModCtrl},
518 "kPRV8": {Code: KeyPgUp, Mod: ModShift | ModAlt | ModCtrl},
519 "knp": {Code: KeyPgDown},
520 "knxt": {Code: KeyPgDown},
521 "kNXT": {Code: KeyPgDown, Mod: ModShift},
522 "kNXT3": {Code: KeyPgDown, Mod: ModAlt},
523 "kNXT4": {Code: KeyPgDown, Mod: ModShift | ModAlt},
524 "kNXT5": {Code: KeyPgDown, Mod: ModCtrl},
525 "kNXT6": {Code: KeyPgDown, Mod: ModShift | ModCtrl},
526 "kNXT7": {Code: KeyPgDown, Mod: ModAlt | ModCtrl},
527 "kNXT8": {Code: KeyPgDown, Mod: ModShift | ModAlt | ModCtrl},
528
529 "kbs": {Code: KeyBackspace},
530 "kcbt": {Code: KeyTab, Mod: ModShift},
531
532 // Function keys
533 // This only includes the first 12 function keys. The rest are treated
534 // as modifiers of the first 12.
535 // Take a look at XTerm modifyFunctionKeys
536 //
537 // XXX: To use unambiguous function keys, use fixterms or kitty clipboard.
538 //
539 // See https://invisible-island.net/xterm/manpage/xterm.html#VT100-Widget-Resources:modifyFunctionKeys
540 // See https://invisible-island.net/xterm/terminfo.html
541
542 "kf1": {Code: KeyF1},
543 "kf2": {Code: KeyF2},
544 "kf3": {Code: KeyF3},
545 "kf4": {Code: KeyF4},
546 "kf5": {Code: KeyF5},
547 "kf6": {Code: KeyF6},
548 "kf7": {Code: KeyF7},
549 "kf8": {Code: KeyF8},
550 "kf9": {Code: KeyF9},
551 "kf10": {Code: KeyF10},
552 "kf11": {Code: KeyF11},
553 "kf12": {Code: KeyF12},
554 "kf13": {Code: KeyF1, Mod: ModShift},
555 "kf14": {Code: KeyF2, Mod: ModShift},
556 "kf15": {Code: KeyF3, Mod: ModShift},
557 "kf16": {Code: KeyF4, Mod: ModShift},
558 "kf17": {Code: KeyF5, Mod: ModShift},
559 "kf18": {Code: KeyF6, Mod: ModShift},
560 "kf19": {Code: KeyF7, Mod: ModShift},
561 "kf20": {Code: KeyF8, Mod: ModShift},
562 "kf21": {Code: KeyF9, Mod: ModShift},
563 "kf22": {Code: KeyF10, Mod: ModShift},
564 "kf23": {Code: KeyF11, Mod: ModShift},
565 "kf24": {Code: KeyF12, Mod: ModShift},
566 "kf25": {Code: KeyF1, Mod: ModCtrl},
567 "kf26": {Code: KeyF2, Mod: ModCtrl},
568 "kf27": {Code: KeyF3, Mod: ModCtrl},
569 "kf28": {Code: KeyF4, Mod: ModCtrl},
570 "kf29": {Code: KeyF5, Mod: ModCtrl},
571 "kf30": {Code: KeyF6, Mod: ModCtrl},
572 "kf31": {Code: KeyF7, Mod: ModCtrl},
573 "kf32": {Code: KeyF8, Mod: ModCtrl},
574 "kf33": {Code: KeyF9, Mod: ModCtrl},
575 "kf34": {Code: KeyF10, Mod: ModCtrl},
576 "kf35": {Code: KeyF11, Mod: ModCtrl},
577 "kf36": {Code: KeyF12, Mod: ModCtrl},
578 "kf37": {Code: KeyF1, Mod: ModShift | ModCtrl},
579 "kf38": {Code: KeyF2, Mod: ModShift | ModCtrl},
580 "kf39": {Code: KeyF3, Mod: ModShift | ModCtrl},
581 "kf40": {Code: KeyF4, Mod: ModShift | ModCtrl},
582 "kf41": {Code: KeyF5, Mod: ModShift | ModCtrl},
583 "kf42": {Code: KeyF6, Mod: ModShift | ModCtrl},
584 "kf43": {Code: KeyF7, Mod: ModShift | ModCtrl},
585 "kf44": {Code: KeyF8, Mod: ModShift | ModCtrl},
586 "kf45": {Code: KeyF9, Mod: ModShift | ModCtrl},
587 "kf46": {Code: KeyF10, Mod: ModShift | ModCtrl},
588 "kf47": {Code: KeyF11, Mod: ModShift | ModCtrl},
589 "kf48": {Code: KeyF12, Mod: ModShift | ModCtrl},
590 "kf49": {Code: KeyF1, Mod: ModAlt},
591 "kf50": {Code: KeyF2, Mod: ModAlt},
592 "kf51": {Code: KeyF3, Mod: ModAlt},
593 "kf52": {Code: KeyF4, Mod: ModAlt},
594 "kf53": {Code: KeyF5, Mod: ModAlt},
595 "kf54": {Code: KeyF6, Mod: ModAlt},
596 "kf55": {Code: KeyF7, Mod: ModAlt},
597 "kf56": {Code: KeyF8, Mod: ModAlt},
598 "kf57": {Code: KeyF9, Mod: ModAlt},
599 "kf58": {Code: KeyF10, Mod: ModAlt},
600 "kf59": {Code: KeyF11, Mod: ModAlt},
601 "kf60": {Code: KeyF12, Mod: ModAlt},
602 "kf61": {Code: KeyF1, Mod: ModShift | ModAlt},
603 "kf62": {Code: KeyF2, Mod: ModShift | ModAlt},
604 "kf63": {Code: KeyF3, Mod: ModShift | ModAlt},
605 }
606
607 // Preserve F keys from F13 to F63 instead of using them for F-keys
608 // modifiers.
609 if flags&flagFKeys != 0 {
610 keys["kf13"] = Key{Code: KeyF13}
611 keys["kf14"] = Key{Code: KeyF14}
612 keys["kf15"] = Key{Code: KeyF15}
613 keys["kf16"] = Key{Code: KeyF16}
614 keys["kf17"] = Key{Code: KeyF17}
615 keys["kf18"] = Key{Code: KeyF18}
616 keys["kf19"] = Key{Code: KeyF19}
617 keys["kf20"] = Key{Code: KeyF20}
618 keys["kf21"] = Key{Code: KeyF21}
619 keys["kf22"] = Key{Code: KeyF22}
620 keys["kf23"] = Key{Code: KeyF23}
621 keys["kf24"] = Key{Code: KeyF24}
622 keys["kf25"] = Key{Code: KeyF25}
623 keys["kf26"] = Key{Code: KeyF26}
624 keys["kf27"] = Key{Code: KeyF27}
625 keys["kf28"] = Key{Code: KeyF28}
626 keys["kf29"] = Key{Code: KeyF29}
627 keys["kf30"] = Key{Code: KeyF30}
628 keys["kf31"] = Key{Code: KeyF31}
629 keys["kf32"] = Key{Code: KeyF32}
630 keys["kf33"] = Key{Code: KeyF33}
631 keys["kf34"] = Key{Code: KeyF34}
632 keys["kf35"] = Key{Code: KeyF35}
633 keys["kf36"] = Key{Code: KeyF36}
634 keys["kf37"] = Key{Code: KeyF37}
635 keys["kf38"] = Key{Code: KeyF38}
636 keys["kf39"] = Key{Code: KeyF39}
637 keys["kf40"] = Key{Code: KeyF40}
638 keys["kf41"] = Key{Code: KeyF41}
639 keys["kf42"] = Key{Code: KeyF42}
640 keys["kf43"] = Key{Code: KeyF43}
641 keys["kf44"] = Key{Code: KeyF44}
642 keys["kf45"] = Key{Code: KeyF45}
643 keys["kf46"] = Key{Code: KeyF46}
644 keys["kf47"] = Key{Code: KeyF47}
645 keys["kf48"] = Key{Code: KeyF48}
646 keys["kf49"] = Key{Code: KeyF49}
647 keys["kf50"] = Key{Code: KeyF50}
648 keys["kf51"] = Key{Code: KeyF51}
649 keys["kf52"] = Key{Code: KeyF52}
650 keys["kf53"] = Key{Code: KeyF53}
651 keys["kf54"] = Key{Code: KeyF54}
652 keys["kf55"] = Key{Code: KeyF55}
653 keys["kf56"] = Key{Code: KeyF56}
654 keys["kf57"] = Key{Code: KeyF57}
655 keys["kf58"] = Key{Code: KeyF58}
656 keys["kf59"] = Key{Code: KeyF59}
657 keys["kf60"] = Key{Code: KeyF60}
658 keys["kf61"] = Key{Code: KeyF61}
659 keys["kf62"] = Key{Code: KeyF62}
660 keys["kf63"] = Key{Code: KeyF63}
661 }
662
663 return keys
664}