Closed boulderob closed 4 years ago
Vim support for key codes can be spotty. In :help terminal-key-codes
there is a (partial) list of key codes that can be configured using the set
command. Function keys that are completely unmodified are supported (<F12>
, for example), as are shifted function keys (<S-F12>
); but function keys with the control modifier aren't supported. As shown in :help xterm-modifier-keys
, Vim tries to avoid defining all combinations of modifiers for all keys, and instead uses a special sequence (;*X
) at the end of the corresponding unmodified key.
For Xterm on my Linux system, the default key code for <F12>
is shown as follows:
set <F12>
This displays as:
^[[24;*~
The first two characters (^[
) are shown in a different color, indicating that they represent pressing control with [
; this is another name for the Escape character. Note the extra ;*~
at the end of the sequence. This means that Xterm uses <Escape>[24~
for the unmodified key, and that modifiers will extend this sequence based on the particular modifier. For the shift modifier, the result is <Escape>[24;2~
(there is an extra ;2
inserted before the final character of the key code).
For key codes that Vim supports directly using the :set
command, teaching Vim how to recognize a key code is mostly straightforward. As an example, make the following two mappings to make it easy to see when <F5>
and <F6>
are pressed:
:map <F5> :echo '<F5>'<CR>
:map <F6> :echo '<F6>'<CR>
Now pressing <F5>
or <F6>
should echo the key name.
Typing :set <F5>
yields ^[[15;*~
, and :set <F6>
yields ^[[17;*~
. For demonstration purposes, these codes may be swapped as follows:
:execute "set <F5>=\e[17;*~"
:execute "set <F6>=\e[15;*~"
Note the use of execute
above. This is just for the convenience of using double-quoted strings that expand the two characters \e
into the Escape code, rather than having to enter the actual key code directly (by pressing CTRL-v Escape
, for example).
You should be able to do the same thing on your Mac, adjusting for whatever key codes these keys produce.
Things get harder for keys whose key codes aren't directly supported with :set
. Function keys using the control modifier fall in this category, so it's not possible to do :set <C-F12>
. This is despite the fact that the syntax <C-F12>
is valid within mappings, because mappings and key codes are two different things to Vim.
The hack I use in Fixkey is to find a key that isn't used on typical keyboards, change the key code for that key, and then map that key to the unsupported key. For historical reasons, Vim supports numbered function keys beyond <F12>
. The keys <F13>
through <F-37>
known to Vim, along with their shifted counterparts. Modern keyboards lack these keys, so Fixkey uses them as described above.
For your case, you might be able to make <C-F12>
work by setting the key code for <F13>
to be your sequence ^[[24^
, and then map <F13>
to <C-F12>
:
:execute "set <F13>=\e[24^"
:map <F13> <C-F12>
:map! <F13> <C-F12>
As before, execute
allows the use of \e
for Escape. The :map
and :map!
combination ensures mapping in all of Vim's modes. Within Fixkey itself, the function Fixkey_setNewKey()
allocates a spare key from the range of unused function keys, sets the desired key code using :set
, then performs the two mappings as shown above.
@drmikehenry much appreciate your very detailed followup! while i was waiting for your reply, i actually dug a bit deeper on my own and actually came to the same conclusion and wound up doing exactly what you suggested above except that i instead mapped SF12 which i wasn't actually using in vim but vim supported to a terminal key code that was assigned to C-F12. that was the glue that tied it together and made it work.
the example i just described was just a test to see if i could do it but it actually winds up eating up a valid S-F12. the fact that i can use the F13 and greater keys as you describe is a great way to trick vim into doing what i want though without burning up S-F<#> keys that i might use for other purposes.
two final questions:
to see which terminal-key-codes my vim8 supported, i used :h terminal-key-codes
and though it shows me S-F<1-12> as valid, it doesn't show F13 - 37 like you suggest. i'm sure what you're saying is correct, but how did you figure out that vim supported those F13-37 keys? just curious if it's in the :h or you had to look at vim source code to determine that and if so where / which file in the project?
to do what i want, i'm having to fiddle around with my mac terminal profile to make sure it's sending certain keys and then configure vim with set to "rig up" the key codes with keys vim accepts like we're doing above. however, when i start switching to other linux systems with potentially different terminal apps and profiles, i can forsee a situation where i'm going to have to modify my dotfiles so that i can quickly get terminal keys setup quickly so that i can keep my vimrc stable and make it work in different environments!
i had to change a lot of keys in my mac terminal profile b/c unlike vim, tmux expects certain chars to already be mapped to what i would call certain "logical key combos".. so you can't set the key codes in tmux, you have to remap what the terminal app sends to match what tmux wants.
i haven't crossed this bridge yet but my question is, do you have any suggestions on how to best configure or handle the platform specific terminal key settings for different console / terminal apps? i can create different profiles for mac terminal.. but i'm not sure where it even saves them or if i can manually edit them in a text file?.. instead i had to click on a each set of keys i wanted to change in the terminal app individually and manually set each one. it's slow and prone to error.
like i said i'm envisioning having to do this for multiple terminal apps on multiple platforms and want a way to just have a single text file i can edit by hand for each terminal / platform configuration? i'm mostly a grand consumer of terminals and consoles for two decades and i've never had to screw with any of this key stuff until now so i'm not sure what configuration actually exists for what i want to do. since it's linux my guess is it's available though.
any thoughts welcome if you've crossed this bridge already. regardless thanks for the information above.
@boulderob I replied a few days ago but it looks like I did something wrong and the comment didn't take. The quick summary of my lost comment is that I think I probably first heard about function keys beyond F12
from the Vim mailing list, but I expect I confirmed the range from the Vim source, e.g.:
https://github.com/vim/vim/blob/c6d539b67181ad573452e919e58ecbfa362f4c49/src/keymap.h#L313-L352
For my own needs, KDE Konsole works well enough without configuration, so I've just stuck with that terminal emulator. I don't blame you for wanting a command-line interface for configuring your terminal(s) of choice, but the best I've got is to suggest searching on the terminal name and keywords like configuration
, command line
, and perhaps plist
on OS X.
thx @drmikehenry once again for the followup. have a great year!
@boulderob You're welcome, and good luck in your quest for terminal happiness :-)
hello. i came here via a stack post. i'm using vim8 on mac sierra. i'm trying to get it to recognize but it doesn't recognize that combo with the modifier key Ctl.
i can see that this combo produces
^[[24^
in my stock terminal and in insert mode in vim. i can also see that the mac terminal is generating that key sequence in it's own profile config.instead of installing and using your plugin which is overkill for the one key seq i want to configure for vim, i want to borrow from it and just use the one line i need which is this (btw i believe you documented this in your stack post as well)
the problem is when i try to use this incantation, vim doesn't recognize the line as a valid line because it thinks it's an invalid option no matter how many different ways i've tried to enter it.
it obviously is tripping up on the fact that
<C-F12>
doesn't look like a known vim option and i would agree but your entire plugin is based on it working! :) i'm probably missing something really simple.any and all thoughts greatly appreciated thx