To: vim_dev@googlegroups.com Subject: Patch 9.0.0889 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0889 Problem: Keycode check script has a few flaws. Solution: Sort on terminal name. Ignore XTGETTCAP responses. Check for version and status response. Update entries. Files: src/testdir/keycode_check.vim, src/testdir/keycode_check.json *** ../vim-9.0.0888/src/testdir/keycode_check.vim 2022-11-15 22:58:41.225439836 +0000 --- src/testdir/keycode_check.vim 2022-11-16 16:05:15.804719729 +0000 *************** *** 2,8 **** # Script to get various codes that keys send, depending on the protocol used. # ! # Usage: vim -u keycode_check.vim # # Author: Bram Moolenaar # Last Update: 2022 Nov 15 --- 2,8 ---- # Script to get various codes that keys send, depending on the protocol used. # ! # Usage: vim -u NONE -S keycode_check.vim # # Author: Bram Moolenaar # Last Update: 2022 Nov 15 *************** *** 76,81 **** --- 76,129 ---- ['Alt-Space', 'A-Space'], ] + # Given a terminal name and a item name, return the text to display. + def GetItemDisplay(term: string, item: string): string + var val = get(keycodes[term], item, '') + + # see if we can pretty-print this one + var pretty = val + if val[0 : 1] == '1b' + pretty = 'ESC' + var idx = 2 + + if val[0 : 3] == '1b5b' + pretty = 'CSI' + idx = 4 + endif + + var digits = false + while idx < len(val) + var cc = val[idx : idx + 1] + var nr = str2nr('0x' .. cc, 16) + idx += 2 + if nr >= char2nr('0') && nr <= char2nr('9') + if !digits + pretty ..= ' ' + endif + digits = true + pretty ..= cc[1] + else + if nr == char2nr(';') && digits + # don't use space between semicolon and digits to keep it short + pretty ..= ';' + else + digits = false + if nr >= char2nr(' ') && nr <= char2nr('~') + # printable character + pretty ..= ' ' .. printf('%c', nr) + else + # non-printable, use hex code + pretty = val + break + endif + endif + endif + endwhile + endif + + return pretty + enddef + # Action: list the information in "keycodes" in a more or less nice way. def ActionList() *************** *** 84,149 **** echo 'No terminal results yet' return endif ! # Use one column of width 10 for the item name, then columns of 20 ! # characters to fit most codes. You will need to increase the terminal ! # width to avoid wrapping. ! echon printf(' ') ! for term in terms ! echon printf('%-20s', term) ! endfor ! echo "\n" ! var items = ['protocol'] + key_entries->copy()->map((_, v) => v[1]) for item in items ! echon printf('%8s ', item) ! for term in terms ! var val = get(keycodes[term], item, '') ! ! # see if we can pretty-print this one ! var pretty = val ! if val[0 : 1] == '1b' ! pretty = 'ESC' ! var idx = 2 ! ! if val[0 : 3] == '1b5b' ! pretty = 'CSI' ! idx = 4 ! endif ! ! var digits = false ! while idx < len(val) ! var cc = val[idx : idx + 1] ! var nr = str2nr('0x' .. cc, 16) ! idx += 2 ! if nr >= char2nr('0') && nr <= char2nr('9') ! if !digits ! pretty ..= ' ' ! endif ! digits = true ! pretty ..= cc[1] ! else ! digits = false ! if nr >= char2nr(' ') && nr <= char2nr('~') ! # printable character ! pretty ..= ' ' .. printf('%c', nr) ! else ! # non-printable, use hex code ! pretty = val ! break ! endif ! endif ! endwhile endif ! echon printf('%-20s', pretty) endfor echo '' endfor echo "\n" enddef def GetTermName(): string var name = input('Enter the name of the terminal: ') return name --- 132,185 ---- echo 'No terminal results yet' return endif + sort(terms) ! var items = ['protocol', 'version', 'status'] ! + key_entries->copy()->map((_, v) => v[1]) ! # For each terminal compute the needed width, add two. ! # You may need to increase the terminal width to avoid wrapping. ! var widths = [] ! for [idx, term] in items(terms) ! widths[idx] = len(term) + 2 ! endfor for item in items ! for [idx, term] in items(terms) ! var l = len(GetItemDisplay(term, item)) ! if widths[idx] < l + 2 ! widths[idx] = l + 2 endif + endfor + endfor ! # Use one column of width 10 for the item name. ! echo "\n" ! echon ' ' ! for [idx, term] in items(terms) ! echon printf('%-' .. widths[idx] .. 's', term) ! endfor ! echo "\n" ! ! for item in items ! echon printf('%8s ', item) ! for [idx, term] in items(terms) ! echon printf('%-' .. widths[idx] .. 's', GetItemDisplay(term, item)) endfor echo '' endfor echo "\n" enddef + # Convert the literal string after "raw key input" into hex form. + def Literal2hex(code: string): string + var hex = '' + for i in range(len(code)) + hex ..= printf('%02x', char2nr(code[i])) + endfor + return hex + enddef + def GetTermName(): string var name = input('Enter the name of the terminal: ') return name *************** *** 162,188 **** if proto == 1 &t_TI = "" elseif proto == 2 &t_TI = "\[>4;2m" proto_name = 'mok2' elseif proto == 3 ! &t_TI = "\[>1u" proto_name = 'kitty' else echoerr 'invalid protocol choice' return endif # executing a dummy shell command will output t_TI !echo >/dev/null if !has_key(keycodes, name) keycodes[name] = {} endif keycodes[name]['protocol'] = proto_name ! echo "When a key press doesn't get to Vim (e.g. when using Alt) press Space" for entry in key_entries ch_logfile('keylog', 'w') echo $'Press the {entry[0]} key (q to quit):' var r = getcharstr() --- 198,295 ---- if proto == 1 &t_TI = "" elseif proto == 2 + # Enable modifyOtherKeys level 2 - no status is reported &t_TI = "\[>4;2m" proto_name = 'mok2' elseif proto == 3 ! # Enable Kitty keyboard protocol and request the status ! &t_TI = "\[>1u" .. "\[?u" proto_name = 'kitty' else echoerr 'invalid protocol choice' return endif + # Append the request for the version response, this is used to check we have + # the results. + &t_TI ..= "\[>c" + + # Pattern that matches the line with the version response. + const version_pattern = "\\\[>\\d\\+;\\d\\+;\\d*c" + + # Pattern that matches the line with the status. Currently what terminals + # return for the Kitty keyboard protocol. + const status_pattern = "\\\[?\\d\\+u" + + ch_logfile('keylog', 'w') + # executing a dummy shell command will output t_TI !echo >/dev/null + # Wait until the log file has the version response. + var startTime = reltime() + var seenVersion = false + while !seenVersion + var log = readfile('keylog') + if len(log) > 2 + for line in log + if line =~ 'raw key input' + var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '') + if code =~ version_pattern + seenVersion = true + echo 'Found the version response' + break + endif + endif + endfor + endif + if reltime(startTime)->reltimefloat() > 3 + break + endif + endwhile + + echo 'seenVersion: ' seenVersion + + # Prepare the terminal entry, set protocol and clear status and version. if !has_key(keycodes, name) keycodes[name] = {} endif keycodes[name]['protocol'] = proto_name + keycodes[name]['version'] = '' + keycodes[name]['status'] = '' + + # Check the log file for a status and the version response + ch_logfile('', '') + var log = readfile('keylog') + delete('keylog') + for line in log + if line =~ 'raw key input' + var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '') + # Check for kitty keyboard protocol status + if code =~ status_pattern + var status = substitute(code, '.*\(' .. status_pattern .. '\).*', '\1', '') + keycodes[name]['status'] = Literal2hex(status) + endif + + if code =~ version_pattern + var version = substitute(code, '.*\(' .. version_pattern .. '\).*', '\1', '') + keycodes[name]['version'] = Literal2hex(version) + break + endif + endif + endfor ! echo "For Alt to work you may need to press the Windows/Super key as well" ! echo "When a key press doesn't get to Vim (e.g. when using Alt) press x" for entry in key_entries + # Consume any typeahead. Wait a bit for any responses to arrive. + sleep 100m + while getchar(1) + getchar() + sleep 100m + endwhile + ch_logfile('keylog', 'w') echo $'Press the {entry[0]} key (q to quit):' var r = getcharstr() *************** *** 190,197 **** if r == 'q' break endif ! var log = readfile('keylog') ! delete('keylog') if len(log) < 2 echoerr 'failed to read result' return --- 297,309 ---- if r == 'q' break endif ! log = readfile('keylog') ! if entry[1] == 'Tab' ! # keep a copy ! rename('keylog', 'keylog-tab') ! else ! delete('keylog') ! endif if len(log) < 2 echoerr 'failed to read result' return *************** *** 201,211 **** if line =~ 'raw key input' var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '') ! # convert the literal bytes into hex var hex = '' ! for i in range(len(code)) ! hex ..= printf('%02x', char2nr(code[i])) ! endfor keycodes[name][entry[1]] = hex done = true break --- 313,338 ---- if line =~ 'raw key input' var code = substitute(line, '.*raw key input: "\([^"]*\).*', '\1', '') ! # Remove any version termresponse ! code = substitute(code, version_pattern, '', 'g') ! ! # Remove any XTGETTCAP replies. ! const cappat = "\P[01]+\\k\\+=\\x*\\\\\" ! code = substitute(code, cappat, '', 'g') ! ! # Remove any kitty status reply ! code = substitute(code, status_pattern, '', 'g') ! if code == '' ! continue ! endif ! ! # Convert the literal bytes into hex. If 'x' was pressed then clear ! # the entry. var hex = '' ! if code != 'x' ! hex = Literal2hex(code) ! endif ! keycodes[name][entry[1]] = hex done = true break *************** *** 241,248 **** echo "\n" if choice > 0 && choice <= len(terms) DoTerm(terms[choice - 1]) endif - echo 'invalid index' enddef # Action: Quit, possibly after saving the results first. --- 368,393 ---- echo "\n" if choice > 0 && choice <= len(terms) DoTerm(terms[choice - 1]) + else + echo 'invalid index' + endif + enddef + + # Action: Clear key codes for an already known terminal. + def ActionClear() + var terms = keys(keycodes) + if len(terms) == 0 + echo 'No terminal results yet' + return + endif + + var choice = inputlist(['Select:'] + terms->copy()->map((idx, arg) => (idx + 1) .. ': ' .. arg)) + echo "\n" + if choice > 0 && choice <= len(terms) + remove(keycodes, terms[choice - 1]) + else + echo 'invalid index' endif enddef # Action: Quit, possibly after saving the results first. *************** *** 271,277 **** '1. List results', '2. Add results for a new terminal', '3. Replace results', ! '4. Quit', ]) echo "\n" if action == 1 --- 416,423 ---- '1. List results', '2. Add results for a new terminal', '3. Replace results', ! '4. Clear results', ! '5. Quit', ]) echo "\n" if action == 1 *************** *** 281,286 **** --- 427,434 ---- elseif action == 3 ActionReplace() elseif action == 4 + ActionClear() + elseif action == 5 ActionQuit() endif endwhile *** ../vim-9.0.0888/src/testdir/keycode_check.json 2022-11-15 22:58:41.229439838 +0000 --- src/testdir/keycode_check.json 2022-11-16 16:01:09.535340089 +0000 *************** *** 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"}} *** ../vim-9.0.0888/src/version.c 2022-11-16 12:02:24.861138121 +0000 --- src/version.c 2022-11-16 16:08:01.579688284 +0000 *************** *** 697,698 **** --- 697,700 ---- { /* Add new patch number below this line */ + /**/ + 889, /**/ -- hundred-and-one symptoms of being an internet addict: 84. Books in your bookcase bear the names Bongo, WinSock and Inside OLE /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///