changeset 31105:46d1a434784b v9.0.0887

patch 9.0.0887: cannot easily try out what codes various keys produce Commit: https://github.com/vim/vim/commit/a44c7811ff1c5519ac9acd6a34c58c98366f5c5f Author: Bram Moolenaar <Bram@vim.org> Date: Tue Nov 15 22:59:07 2022 +0000 patch 9.0.0887: cannot easily try out what codes various keys produce Problem: Cannot easily try out what codes various keys produce. Solution: Add a script to gather key code information, with an initial list of codes to compare with.
author Bram Moolenaar <Bram@vim.org>
date Wed, 16 Nov 2022 00:00:04 +0100
parents 86edc0b8966f
children 795f63b36d04
files Filelist src/testdir/keycode_check.json src/testdir/keycode_check.vim src/version.c
diffstat 4 files changed, 291 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/Filelist
+++ b/Filelist
@@ -177,6 +177,8 @@ SRC_ALL =	\
 		src/testdir/Make_all.mak \
 		src/testdir/*.in \
 		src/testdir/*.py \
+		src/testdir/keycode_check.vim \
+		src/testdir/keycode_check.json \
 		src/testdir/lsan-suppress.txt \
 		src/testdir/sautest/autoload/*.vim \
 		src/testdir/testluaplugin/lua/testluaplugin/*.lua \
new file mode 100644
--- /dev/null
+++ b/src/testdir/keycode_check.json
@@ -0,0 +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"}}
new file mode 100644
--- /dev/null
+++ b/src/testdir/keycode_check.vim
@@ -0,0 +1,286 @@
+vim9script
+
+# 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
+#
+# The codes are stored in the file "keycode_check.json", so that you can
+# compare the results of various terminals.
+#
+# You can select what protocol to enable:
+# - None
+# - modifyOtherKeys level 2
+# - kitty keyboard protocol
+
+# Change directory to where this script is, so that the json file is found
+# there.
+exe 'cd ' .. expand('<sfile>:h')
+echo 'working in directory: ' .. getcwd()
+
+const filename = 'keycode_check.json'
+
+# Dictionary of dictionaries with the results in the form:
+# {'xterm': {protocol: 'none', 'Tab': '09', 'S-Tab': '09'},
+#  'xterm2': {protocol: 'mok2', 'Tab': '09', 'S-Tab': '09'},
+#  'kitty': {protocol: 'kitty', 'Tab': '09', 'S-Tab': '09'},
+# }
+# The values are in hex form.
+var keycodes = {}
+
+if filereadable(filename)
+  keycodes = readfile(filename)->join()->json_decode()
+else
+  # Use some dummy entries to try out with
+  keycodes = {
+    'xterm': {protocol: 'none', 'Tab': '09', 'S-Tab': '09'},
+    'kitty': {protocol: 'kitty', 'Tab': '09', 'S-Tab': '1b5b393b3275'},
+    }
+endif
+var orig_keycodes = deepcopy(keycodes)  # used to detect something changed
+
+# Write the "keycodes" variable in JSON form to "filename".
+def WriteKeycodes()
+  # If the file already exists move it to become the backup file.
+  if filereadable(filename)
+    if rename(filename, filename .. '~')
+      echoerr $'Renaming {filename} to {filename}~ failed!'
+      return
+    endif
+  endif
+
+  if writefile([json_encode(keycodes)], filename) != 0
+    echoerr $'Writing {filename} failed!'
+  endif
+enddef
+
+# The key entries that we want to list, in this order.
+# The first item is displayed in the prompt, the second is the key in
+# the keycodes dictionary.
+var key_entries = [
+	['Tab', 'Tab'],
+	['Shift-Tab', 'S-Tab'],
+	['Ctrl-Tab', 'C-Tab'],
+	['Alt-Tab', 'A-Tab'],
+	['Ctrl-I', 'C-I'],
+	['Shift-Ctrl-I', 'S-C-I'],
+	['Esc', 'Esc'],
+	['Shift-Esc', 'S-Esc'],
+	['Ctrl-Esc', 'C-Esc'],
+	['Alt-Esc', 'A-Esc'],
+	['Space', 'Space'],
+	['Shift-Space', 'S-Space'],
+	['Ctrl-Space', 'C-Space'],
+	['Alt-Space', 'A-Space'],
+      ]
+
+
+# Action: list the information in "keycodes" in a more or less nice way.
+def ActionList()
+  var terms = keys(keycodes)
+  if len(terms) == 0
+    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
+enddef
+
+# Gather key codes for terminal "name".
+def DoTerm(name: string)
+  var proto = inputlist([$'What protocol to enable for {name}:',
+			 '1. None',
+			 '2. modifyOtherKeys level 2',
+			 '3. kitty',
+			])
+  echo "\n"
+  &t_TE = "\<Esc>[>4;m"
+  var proto_name = 'none'
+  if proto == 1
+    &t_TI = ""
+  elseif proto == 2
+    &t_TI = "\<Esc>[>4;2m"
+    proto_name = 'mok2'
+  elseif proto == 3
+    &t_TI = "\<Esc>[>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()
+    ch_logfile('', '')
+    if r == 'q'
+      break
+    endif
+    var log = readfile('keylog')
+    delete('keylog')
+    if len(log) < 2
+      echoerr 'failed to read result'
+      return
+    endif
+    var done = false
+    for line in log
+      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
+      endif
+    endfor
+    if !done
+      echo 'Code not found in log'
+    endif
+  endfor
+enddef
+
+# Action: Add key codes for a new terminal.
+def ActionAdd()
+  var name = input('Enter name of the terminal: ')
+  echo "\n"
+  if index(keys(keycodes), name) >= 0
+    echoerr $'Terminal {name} already exists'
+    return
+  endif
+
+  DoTerm(name)
+enddef
+
+# Action: Replace key codes for an already known terminal.
+def ActionReplace()
+  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)
+    DoTerm(terms[choice - 1])
+  endif
+  echo 'invalid index'
+enddef
+
+# Action: Quit, possibly after saving the results first.
+def ActionQuit()
+  # If nothing was changed just quit
+  if keycodes == orig_keycodes
+    quit
+  endif
+
+  while true
+    var res = input("Save the changed key codes (y/n)? ")
+    if res == 'n'
+      quit
+    endif
+    if res == 'y'
+      WriteKeycodes()
+      quit
+    endif
+    echo 'invalid reply'
+  endwhile
+enddef
+
+# The main loop
+while true
+  var action = inputlist(['Select operation:',
+    			'1. List results',
+			'2. Add results for a new terminal',
+			'3. Replace results',
+			'4. Quit',
+		      ])
+  echo "\n"
+  if action == 1
+    ActionList()
+  elseif action == 2
+    ActionAdd()
+  elseif action == 3
+    ActionReplace()
+  elseif action == 4
+    ActionQuit()
+  endif
+endwhile
--- a/src/version.c
+++ b/src/version.c
@@ -696,6 +696,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    887,
+/**/
     886,
 /**/
     885,