Skip to content

Commit 8303035

Browse files
committed
patch 9.0.0889: keycode check script has a few flaws
Problem: Keycode check script has a few flaws. Solution: Sort on terminal name. Ignore XTGETTCAP responses. Check for version and status response. Update entries.
1 parent f10952e commit 8303035

3 files changed

Lines changed: 210 additions & 60 deletions

File tree

src/testdir/keycode_check.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"xterm":{"Space":"20","C-Tab":"09","A-Esc":"20","C-Space":"","S-C-I":"09","C-I":"09","S-Tab":"1b5b5a","Tab":"09","S-Space":"20","A-Tab":"20","C-Esc":"1b","protocol":"none","A-Space":"20","S-Esc":"1b","Esc":"1b"},"kitty":{"Space":"20","C-Tab":"20","A-Esc":"1b5b4f","C-Space":"1b5b33323b3575","S-C-I":"1b5b3130353b3675","C-I":"1b5b3130353b3575","S-Tab":"1b5b393b3275","Tab":"09","S-Space":"20","A-Tab":"1b5b4f","C-Esc":"1b5b32373b3575","protocol":"kitty","A-Space":"20","S-Esc":"1b5b32373b3275","Esc":"1b5b323775"},"xterm2":{"Space":"20","C-Tab":"1b5b32373b353b397e","A-Esc":"20","C-Space":"1b5b32373b353b33327e","S-C-I":"1b5b32373b363b37337e","C-I":"1b5b32373b353b3130357e","S-Tab":"1b5b5a","Tab":"09","S-Space":"1b5b32373b323b33327e","A-Tab":"20","C-Esc":"1b5b32373b353b32377e","protocol":"mok2","A-Space":"20","S-Esc":"1b","Esc":"1b"}}
1+
{"12xterm":{"Space":"20","version":"1b5b3e34313b3335363b3063","C-Tab":"1b5b32373b353b397e","A-Esc":"1b5b32373b333b32377e","C-Space":"1b5b32373b353b33327e","status":"","S-C-I":"1b5b32373b363b37337e","C-I":"1b5b32373b353b3130357e","S-Tab":"1b5b5a","Tab":"09","S-Space":"1b5b32373b323b33327e","A-Tab":"1b5b32373b333b397e","C-Esc":"1b5b32373b353b32377e","protocol":"mok2","A-Space":"1b5b32373b333b33327e","S-Esc":"1b","Esc":"1b"},"2kitty":{"Space":"20","version":"1b5b3e313b343030303b323163","C-Tab":"","A-Esc":"1b5b32373b313175","C-Space":"1b5b33323b3575","status":"1b5b3f3175","S-C-I":"1b5b3130353b3675","C-I":"1b5b3130353b3575","S-Tab":"1b5b393b3275","Tab":"09","S-Space":"20","A-Tab":"1b5b393b313175","C-Esc":"1b5b32373b3575","protocol":"kitty","A-Space":"1b5b33323b313175","S-Esc":"1b5b32373b3275","Esc":"1b5b323775"},"11xterm":{"Space":"20","version":"1b5b3e34313b3335363b3063","C-Tab":"09","A-Esc":"9b00","status":"","S-C-I":"09","C-I":"09","S-Tab":"1b5b5a","Tab":"09","S-Space":"20","A-Tab":"8900","C-Esc":"1b","protocol":"none","A-Space":"a000","S-Esc":"1b","Esc":"1b"}}

src/testdir/keycode_check.vim

Lines changed: 207 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ vim9script
22

33
# Script to get various codes that keys send, depending on the protocol used.
44
#
5-
# Usage: vim -u keycode_check.vim
5+
# Usage: vim -u NONE -S keycode_check.vim
66
#
77
# Author: Bram Moolenaar
88
# Last Update: 2022 Nov 15
@@ -76,6 +76,54 @@ var key_entries = [
7676
['Alt-Space', 'A-Space'],
7777
]
7878

79+
# Given a terminal name and a item name, return the text to display.
80+
def GetItemDisplay(term: string, item: string): string
81+
var val = get(keycodes[term], item, '')
82+
83+
# see if we can pretty-print this one
84+
var pretty = val
85+
if val[0 : 1] == '1b'
86+
pretty = 'ESC'
87+
var idx = 2
88+
89+
if val[0 : 3] == '1b5b'
90+
pretty = 'CSI'
91+
idx = 4
92+
endif
93+
94+
var digits = false
95+
while idx < len(val)
96+
var cc = val[idx : idx + 1]
97+
var nr = str2nr('0x' .. cc, 16)
98+
idx += 2
99+
if nr >= char2nr('0') && nr <= char2nr('9')
100+
if !digits
101+
pretty ..= ' '
102+
endif
103+
digits = true
104+
pretty ..= cc[1]
105+
else
106+
if nr == char2nr(';') && digits
107+
# don't use space between semicolon and digits to keep it short
108+
pretty ..= ';'
109+
else
110+
digits = false
111+
if nr >= char2nr(' ') && nr <= char2nr('~')
112+
# printable character
113+
pretty ..= ' ' .. printf('%c', nr)
114+
else
115+
# non-printable, use hex code
116+
pretty = val
117+
break
118+
endif
119+
endif
120+
endif
121+
endwhile
122+
endif
123+
124+
return pretty
125+
enddef
126+
79127

80128
# Action: list the information in "keycodes" in a more or less nice way.
81129
def ActionList()
@@ -84,66 +132,54 @@ def ActionList()
84132
echo 'No terminal results yet'
85133
return
86134
endif
135+
sort(terms)
87136

88-
# Use one column of width 10 for the item name, then columns of 20
89-
# characters to fit most codes. You will need to increase the terminal
90-
# width to avoid wrapping.
91-
echon printf(' ')
92-
for term in terms
93-
echon printf('%-20s', term)
94-
endfor
95-
echo "\n"
137+
var items = ['protocol', 'version', 'status']
138+
+ key_entries->copy()->map((_, v) => v[1])
96139

97-
var items = ['protocol'] + key_entries->copy()->map((_, v) => v[1])
140+
# For each terminal compute the needed width, add two.
141+
# You may need to increase the terminal width to avoid wrapping.
142+
var widths = []
143+
for [idx, term] in items(terms)
144+
widths[idx] = len(term) + 2
145+
endfor
98146

99147
for item in items
100-
echon printf('%8s ', item)
101-
for term in terms
102-
var val = get(keycodes[term], item, '')
103-
104-
# see if we can pretty-print this one
105-
var pretty = val
106-
if val[0 : 1] == '1b'
107-
pretty = 'ESC'
108-
var idx = 2
109-
110-
if val[0 : 3] == '1b5b'
111-
pretty = 'CSI'
112-
idx = 4
113-
endif
114-
115-
var digits = false
116-
while idx < len(val)
117-
var cc = val[idx : idx + 1]
118-
var nr = str2nr('0x' .. cc, 16)
119-
idx += 2
120-
if nr >= char2nr('0') && nr <= char2nr('9')
121-
if !digits
122-
pretty ..= ' '
123-
endif
124-
digits = true
125-
pretty ..= cc[1]
126-
else
127-
digits = false
128-
if nr >= char2nr(' ') && nr <= char2nr('~')
129-
# printable character
130-
pretty ..= ' ' .. printf('%c', nr)
131-
else
132-
# non-printable, use hex code
133-
pretty = val
134-
break
135-
endif
136-
endif
137-
endwhile
148+
for [idx, term] in items(terms)
149+
var l = len(GetItemDisplay(term, item))
150+
if widths[idx] < l + 2
151+
widths[idx] = l + 2
138152
endif
153+
endfor
154+
endfor
155+
156+
# Use one column of width 10 for the item name.
157+
echo "\n"
158+
echon ' '
159+
for [idx, term] in items(terms)
160+
echon printf('%-' .. widths[idx] .. 's', term)
161+
endfor
162+
echo "\n"
139163

140-
echon printf('%-20s', pretty)
164+
for item in items
165+
echon printf('%8s ', item)
166+
for [idx, term] in items(terms)
167+
echon printf('%-' .. widths[idx] .. 's', GetItemDisplay(term, item))
141168
endfor
142169
echo ''
143170
endfor
144171
echo "\n"
145172
enddef
146173

174+
# Convert the literal string after "raw key input" into hex form.
175+
def Literal2hex(code: string): string
176+
var hex = ''
177+
for i in range(len(code))
178+
hex ..= printf('%02x', char2nr(code[i]))
179+
endfor
180+
return hex
181+
enddef
182+
147183
def GetTermName(): string
148184
var name = input('Enter the name of the terminal: ')
149185
return name
@@ -162,36 +198,112 @@ def DoTerm(name: string)
162198
if proto == 1
163199
&t_TI = ""
164200
elseif proto == 2
201+
# Enable modifyOtherKeys level 2 - no status is reported
165202
&t_TI = "\<Esc>[>4;2m"
166203
proto_name = 'mok2'
167204
elseif proto == 3
168-
&t_TI = "\<Esc>[>1u"
205+
# Enable Kitty keyboard protocol and request the status
206+
&t_TI = "\<Esc>[>1u" .. "\<Esc>[?u"
169207
proto_name = 'kitty'
170208
else
171209
echoerr 'invalid protocol choice'
172210
return
173211
endif
174212

213+
# Append the request for the version response, this is used to check we have
214+
# the results.
215+
&t_TI ..= "\<Esc>[>c"
216+
217+
# Pattern that matches the line with the version response.
218+
const version_pattern = "\<Esc>\\[>\\d\\+;\\d\\+;\\d*c"
219+
220+
# Pattern that matches the line with the status. Currently what terminals
221+
# return for the Kitty keyboard protocol.
222+
const status_pattern = "\<Esc>\\[?\\d\\+u"
223+
224+
ch_logfile('keylog', 'w')
225+
175226
# executing a dummy shell command will output t_TI
176227
!echo >/dev/null
177228

229+
# Wait until the log file has the version response.
230+
var startTime = reltime()
231+
var seenVersion = false
232+
while !seenVersion
233+
var log = readfile('keylog')
234+
if len(log) > 2
235+
for line in log
236+
if line =~ 'raw key input'
237+
var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '')
238+
if code =~ version_pattern
239+
seenVersion = true
240+
echo 'Found the version response'
241+
break
242+
endif
243+
endif
244+
endfor
245+
endif
246+
if reltime(startTime)->reltimefloat() > 3
247+
break
248+
endif
249+
endwhile
250+
251+
echo 'seenVersion: ' seenVersion
252+
253+
# Prepare the terminal entry, set protocol and clear status and version.
178254
if !has_key(keycodes, name)
179255
keycodes[name] = {}
180256
endif
181257
keycodes[name]['protocol'] = proto_name
258+
keycodes[name]['version'] = ''
259+
keycodes[name]['status'] = ''
182260

183-
echo "When a key press doesn't get to Vim (e.g. when using Alt) press Space"
261+
# Check the log file for a status and the version response
262+
ch_logfile('', '')
263+
var log = readfile('keylog')
264+
delete('keylog')
265+
for line in log
266+
if line =~ 'raw key input'
267+
var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '')
268+
# Check for kitty keyboard protocol status
269+
if code =~ status_pattern
270+
var status = substitute(code, '.*\(' .. status_pattern .. '\).*', '\1', '')
271+
keycodes[name]['status'] = Literal2hex(status)
272+
endif
273+
274+
if code =~ version_pattern
275+
var version = substitute(code, '.*\(' .. version_pattern .. '\).*', '\1', '')
276+
keycodes[name]['version'] = Literal2hex(version)
277+
break
278+
endif
279+
endif
280+
endfor
281+
282+
echo "For Alt to work you may need to press the Windows/Super key as well"
283+
echo "When a key press doesn't get to Vim (e.g. when using Alt) press x"
184284

185285
for entry in key_entries
286+
# Consume any typeahead. Wait a bit for any responses to arrive.
287+
sleep 100m
288+
while getchar(1)
289+
getchar()
290+
sleep 100m
291+
endwhile
292+
186293
ch_logfile('keylog', 'w')
187294
echo $'Press the {entry[0]} key (q to quit):'
188295
var r = getcharstr()
189296
ch_logfile('', '')
190297
if r == 'q'
191298
break
192299
endif
193-
var log = readfile('keylog')
194-
delete('keylog')
300+
log = readfile('keylog')
301+
if entry[1] == 'Tab'
302+
# keep a copy
303+
rename('keylog', 'keylog-tab')
304+
else
305+
delete('keylog')
306+
endif
195307
if len(log) < 2
196308
echoerr 'failed to read result'
197309
return
@@ -201,11 +313,26 @@ def DoTerm(name: string)
201313
if line =~ 'raw key input'
202314
var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '')
203315

204-
# convert the literal bytes into hex
316+
# Remove any version termresponse
317+
code = substitute(code, version_pattern, '', 'g')
318+
319+
# Remove any XTGETTCAP replies.
320+
const cappat = "\<Esc>P[01]+\\k\\+=\\x*\<Esc>\\\\"
321+
code = substitute(code, cappat, '', 'g')
322+
323+
# Remove any kitty status reply
324+
code = substitute(code, status_pattern, '', 'g')
325+
if code == ''
326+
continue
327+
endif
328+
329+
# Convert the literal bytes into hex. If 'x' was pressed then clear
330+
# the entry.
205331
var hex = ''
206-
for i in range(len(code))
207-
hex ..= printf('%02x', char2nr(code[i]))
208-
endfor
332+
if code != 'x'
333+
hex = Literal2hex(code)
334+
endif
335+
209336
keycodes[name][entry[1]] = hex
210337
done = true
211338
break
@@ -241,8 +368,26 @@ def ActionReplace()
241368
echo "\n"
242369
if choice > 0 && choice <= len(terms)
243370
DoTerm(terms[choice - 1])
371+
else
372+
echo 'invalid index'
373+
endif
374+
enddef
375+
376+
# Action: Clear key codes for an already known terminal.
377+
def ActionClear()
378+
var terms = keys(keycodes)
379+
if len(terms) == 0
380+
echo 'No terminal results yet'
381+
return
382+
endif
383+
384+
var choice = inputlist(['Select:'] + terms->copy()->map((idx, arg) => (idx + 1) .. ': ' .. arg))
385+
echo "\n"
386+
if choice > 0 && choice <= len(terms)
387+
remove(keycodes, terms[choice - 1])
388+
else
389+
echo 'invalid index'
244390
endif
245-
echo 'invalid index'
246391
enddef
247392

248393
# Action: Quit, possibly after saving the results first.
@@ -271,7 +416,8 @@ while true
271416
'1. List results',
272417
'2. Add results for a new terminal',
273418
'3. Replace results',
274-
'4. Quit',
419+
'4. Clear results',
420+
'5. Quit',
275421
])
276422
echo "\n"
277423
if action == 1
@@ -281,6 +427,8 @@ while true
281427
elseif action == 3
282428
ActionReplace()
283429
elseif action == 4
430+
ActionClear()
431+
elseif action == 5
284432
ActionQuit()
285433
endif
286434
endwhile

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ static char *(features[]) =
695695

696696
static int included_patches[] =
697697
{ /* Add new patch number below this line */
698+
/**/
699+
889,
698700
/**/
699701
888,
700702
/**/

0 commit comments

Comments
 (0)