Vim Tips Wiki
No edit summary
 
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{review}}
 
{{review}}
  +
{{TipImported
{{Tip
 
 
|id=1272
 
|id=1272
  +
|previous=1269
|title=Mapping fast keycodes in terminal Vim
 
  +
|next=1274
|created=June 25, 2006 0:10
 
  +
|created=2006
 
|complexity=intermediate
 
|complexity=intermediate
 
|author=Gerald Lai
 
|author=Gerald Lai
 
|version=6.0
 
|version=6.0
 
|rating=66/21
 
|rating=66/21
  +
|category1=
|text=
 
  +
|category2=
In the GUI version of Vim (known as GVim), the mapping of keys seem to work for
 
  +
}}
  +
In the GUI version of Vim (gvim), the mapping of keys seem to work for the most part. For instance, it is easy to map Ctrl-Shift-F2 to a keystroke:
   
  +
<pre>
the most part. For instance, it is easy to map Ctrl-Shift-F2 to a keystroke:
 
  +
"delete all lines in the current buffer
  +
:nmap <C-S-F2> ggdG
  +
</pre>
   
  +
For terminal versions of Vim (such as xterm, rxvt, win32, etc), mapping something like Ctrl-Shift-F2 needs some extra work. It may seem daunting to deal with archaic terminal keycodes at first, but once you understand what is going on in the right context, it is quite simple.
   
  +
===1a. Keycodes===
  +
There are two types of keycodes: terminal keycodes and Vim keycodes. Terminal keycodes look something like
   
  +
<pre>
"delete all lines in the current buffer
 
  +
^[[1;2A
  +
</pre>
   
  +
These are actual bytes that are sent to Vim by the terminal when we type Shift-Up, for example (on an xterm).
:nmap &lt;C-S-F2&gt; ggdG
 
   
  +
Vim keycodes look like
   
  +
<pre>
  +
&lt;S-Up>
  +
</pre>
   
  +
Vim needs its own representation of keycodes because it runs on a variety of platforms. Vim can act upon its own keycodes, and leave the assignment of terminal keycodes to autodetection (or to manual setup by the user, which is what this guide is for).
For terminal versions of Vim (such as xterm, rxvt, win32, etc.), mapping
 
   
  +
===1b. List of usable keycodes===
something like Ctrl-Shift-F2 needs some extra work. It may seem daunting to
 
  +
To obtain a list of terminal keycodes, look it up in the manual for that terminal.
   
  +
For a list of Vim's internal keycodes, see {{help|t_ku}}. Enter <code>:set termcap</code> to list the terminal keycodes (see {{help|terminal-options}}).
deal with archaic terminal keycodes at first, but once you understand what is
 
   
  +
In addition to the Vim keycodes listed in the help section above, the keycodes for the function keys actually go up to F37. This means, we have
going on in the right context, it is quite simple.
 
   
  +
<pre>
  +
<F1> to <F37>
  +
&lt;S-F1> to &lt;S-F37>
  +
</pre>
   
  +
We can use this to our advantage to create more "responsive" mappings. More on this later in section 2b.
   
  +
We can also set these Vim keycodes:
References:
 
   
  +
<pre>
  +
<C-Home>, <C-End>
  +
&lt;S-Home>, &lt;S-End>
  +
&lt;S-a> to &lt;S-z>
  +
<C-a> to <C-z>
  +
<A-a> to <A-z>
  +
</pre>
   
  +
Be careful when setting these keycodes. See section 3a.
   
  +
===1c. Setting Vim keycodes===
http://groups.yahoo.com/group/vim/message/66414
 
  +
Vim keycodes look a lot like the keystrokes we would define in a mapping. They are easy to read, quite intuitive, and are almost treated the same by Vim. The only difference is that we can <code>:set</code> internal keycodes. For example, to manually set the keycode for Shift-Down_arrow:
   
  +
<pre>
http://groups.yahoo.com/group/vim/message/66451
 
  +
:set &lt;S-Down>=^[[1;2B
  +
</pre>
   
  +
where ^[ is a literal ESC special character.
http://groups.yahoo.com/group/vim/message/69148
 
   
  +
The following is ''not'' allowed because the keycode is not a listed Vim keycode:
   
  +
<pre>
  +
:set <C-S-Down>=^[[1;6B
  +
</pre>
   
  +
Once the correct terminal keycode is assigned to the appropriate Vim keycode, the keystroke should work in terminal Vim. Shift-Down_arrow should now work, but the Ctrl-Shift-Down_arrow keycode can not be set in the same way. For this we need mappings (see section 2b).
   
  +
===1d. Entering literal characters & terminal codes===
  +
Either in the :command line, or in insert mode:
   
  +
To enter a literal character in Vim, first type Ctrl-v, followed by a single keystroke. Hence, typing Ctrl-v then Esc will produce "^[".
1a. Keycodes
 
   
  +
To enter a terminal keycode in Vim, first type Ctrl-v, followed by the keystroke we want to obtain the term keycode from. Hence, typing Ctrl-v + Shift-Down_arrow will produce "^[[1;2B".
============
 
   
  +
This means that there are 2 ways to set the Vim keycode as shown in section 1c:
   
  +
<pre>
  +
"literally enter the keycode
  +
:set &lt;S-Down>={C-v}{Esc}[1;2B
  +
</pre>
   
  +
or
There are two types of keycodes: terminal keycodes and Vim keycodes. Terminal
 
  +
<pre>
  +
"let the terminal send its keycode to Vim
  +
:set &lt;S-Down>={C-v}{S-Down}
  +
</pre>
   
  +
where curly brackets {..} denote the action of typing the keystroke. For instance, when you see {C-v}, hold down Ctrl and hit "v". Do not type it literally as "{C-v}".
keycodes look something like
 
   
  +
We shall use the curly brackets as nomenclature from now on.
   
  +
Also make use of the Normal mode command 'ga' to inspect the resulting keycode. Place the cursor over a special character, and type 'ga'. This will provide you with ascii information of the character under the cursor.
   
  +
See {{help|i_ctrl-v}}, {{help|ga}}.
^[[1;2A
 
   
  +
===2a. Mappings===
  +
The function of mappings in Vim is to map a set of keystrokes to another set of keystrokes. For more information, see {{help|key-mapping}}, {{help|map-modes}}.
   
  +
===2b. Mapping "fast" keycodes===
  +
As mentioned in section 1c, the Ctrl-Shift-Down_arrow keycode cannot be set in the same way as the Shift-Down_arrow keycode because it is not a listed Vim keycode. One way to get around that is to do the following:
   
  +
<pre>
These are actual bytes that are sent by the terminal to Vim when we type
 
  +
:map <Esc>[1;6B <C-S-Down>
  +
</pre>
   
  +
This maps the literal terminal keycode to a Vim keystroke (remember, not a Vim keycode).
Shift-Up, for (an xterm) example.
 
   
  +
The disadvantage of this is that Vim will "wait" everytime after the Esc key pressed for a potential "[" + "1" + ";" + "6" + "B" keystroke combination, just in case you meant to do <C-S-Down> instead of a simple <Esc> to Normal mode.
   
  +
If you typed "{Esc}[1;6B" fast enough, you would do a Ctrl-Shift-Down_arrow. After all, you are mapping a keystroke, not a keycode.
   
  +
A better way of mapping keycodes is to first assign the terminal keycode to an unused Vim keycode, and then map the newly used Vim keycode. This way, we can set 'ttimeoutlen' to a small value to ensure that the terminal keycode can only be entered into Vim as fast as the terminal can, but will be humanly-impossible to do it manually.
Vim keycodes look like
 
   
  +
This is how it is done:
   
  +
<pre>
  +
:set timeout timeoutlen=1000 ttimeoutlen=100
  +
:set <F13>=^[[1;6B
  +
:map <F13> <C-S-Down>
  +
:map! <F13> <C-S-Down>
  +
</pre>
   
  +
Now, Ctrl-Shift-Down_arrow will work, and Esc will not pause.
&lt;S-Up&gt;
 
   
  +
Potentially unused Vim keycodes that can be used include:
   
  +
<pre>
  +
<F13> to <F37>
  +
&lt;S-F13> to &lt;S-F37>
  +
<xF1> to <xF4>
  +
&lt;S-xF1> to &lt;S-xF4>
  +
</pre>
   
  +
When setting any Vim keycode, exercise caution. Do some checks to see if the terminal code you're setting the Vim keycode to is set elsewhere. There must be no conflicts.
The reason why Vim needs its own representation of keycodes is because it runs
 
   
  +
For instance, in a Win32 terminal, <F1> to <F4> will always be set the same as <xF1> to <xF4>, respectively. Therefore, you cannot use those keycodes.
on a variety of platforms. By assigning the terminal keycodes to its own
 
   
  +
See {{help|'timeout'}}, {{help|'timeoutlen'}}, {{help|'ttimeoutlen'}}.
internal representation, it can then act upon its own keycodes, and leave the
 
   
  +
===2c. Laying it out in vimrc===
assignment of terminal-&gt;Vim keycodes up to autodetection (or at the very least,
 
  +
Here is an example of how to set up the keycodes in a vimrc file. It is highly recommended that you start Vim without any startup scripts that may interfere with keycode detection:
   
  +
<pre>
manual setup by the user - which is what this guide is for).
 
  +
$ vim -Nu NONE .vimrc
  +
</pre>
   
  +
<pre>
  +
set timeout timeoutlen=1000 ttimeoutlen=100
  +
if !has("gui_running")
  +
if &term == "xterm"
  +
set <Home>=^[[H <End>=^[[F <BS>=^?
  +
set &lt;S-Up>=^[[1;2A &lt;S-Down>=^[[1;2B &lt;S-Right>=^[[1;2C &lt;S-Left>=^[[1;2D
  +
set <xF1>={C-v}{C-S-Up}^[[1;6A <xF2>=^[[1;6B <xF3>=^[[1;6C <xF4>=^[[1;6D
  +
map <xF1> <C-S-Up>
  +
map <xF2> <C-S-Down>
  +
map <xF3> <C-S-Right>
  +
map <xF4> <C-S-Left>
  +
map! <xF1> <C-S-Up>
  +
map! <xF2> <C-S-Down>
  +
map! <xF3> <C-S-Right>
  +
map! <xF4> <C-S-Left>
  +
elseif &term == "win32"
  +
...
  +
else
  +
...
  +
endif
  +
endif
  +
</pre>
   
  +
where ^[ is a literal ESC special character and ^? is a literal ascii 0x7f character.
   
  +
See {{help|'term'}}, {{help|has-patch}}.
   
  +
You can also use a function like the following to automatically assign fast keycodes:
   
  +
<pre>
1b. List of usable keycodes
 
  +
" MapFastKeycode: helper for fast keycode mappings
  +
" makes use of unused vim keycodes <[S-]F15> to <[S-]F37>
  +
function! <SID>MapFastKeycode(key, keycode)
  +
if s:fast_i == 46
  +
echohl WarningMsg
  +
echomsg "Unable to map ".a:key.": out of spare keycodes"
  +
echohl None
  +
return
  +
endif
  +
let vkeycode = '<'.(s:fast_i/23==0 ? '' : 'S-').'F'.(15+s:fast_i%23).'>'
  +
exec 'set '.vkeycode.'='.a:keycode
  +
exec 'map '.vkeycode.' '.a:key
  +
let s:fast_i += 1
  +
endfunction
  +
let s:fast_i = 0
  +
</pre>
   
  +
It uses Vim keycodes <code><F15></code> and above. If you don't have keys for <code><F13></code> and <code><F14></code> on your keyboard, you can also make use of those, for a total of 50 keys you can map this way.
===========================
 
   
  +
Once defined, you can use the function to map keys like so: (example for rxvt)
   
  +
<pre>
  +
call <SID>MapFastKeycode('<C-F3>', "\e[13^")
  +
call <SID>MapFastKeycode('<C-F4>', "\e[14^")
  +
call <SID>MapFastKeycode('<M-j>', "\ej")
  +
call <SID>MapFastKeycode('<M-k>', "\ek")
  +
" ...
  +
</pre>
   
  +
===3a. Troubleshooting I===
To obtain a list of terminal keycodes, look it up in the manual for that
 
  +
You only need to employ unused Vim keycodes either when<br>
  +
(a) there are no available Vim keycodes that match the terminal keycode, and<br>
  +
(b) the terminal keycode is longer than a single keystroke<br>
  +
or<br>
  +
(c) setting the Vim keycode that matches the terminal keycode causes weird behavior.
   
  +
'''Example where (a) is not true:'''
terminal.
 
  +
<pre>
  +
:set <F13>=^[[1;2B
  +
:map <F13> &lt;S-Down>
  +
</pre>
   
  +
Setting the unused <F13> is redundant, because &lt;S-Down> is already available as a Vim keycode. Do this instead:
  +
<pre>
  +
:set &lt;S-Down>=^[[1;2B
  +
</pre>
   
  +
'''Example where (b) is not true:'''
   
  +
For a Win32 terminal, mapping Ctrl-Backspace is done by
For a list of Vim's internal keycodes, see
 
  +
<pre>
  +
:map <C-{C-v}{BS}> <C-BS>
  +
</pre>
   
  +
Since the terminal keycode can be represented by <C-^?>, which is a single keystroke, there is no need to employ an unused Vim keycode.
   
  +
'''Example where (c) is true:'''
   
  +
For an rxvt terminal, merely doing
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:t_ku}} :help t_ku]
 
  +
<pre>
  +
:set <A-j>=^[j <A-u>=^[u <A-6>=^[6
  +
</pre>
   
  +
will not make Alt-j, Alt-u and Alt-6 work. Reason unknown. Need to assign to unused Vim keycodes.
   
  +
===3b. Troubleshooting II===
  +
Sometimes, performing
  +
<pre>
  +
:set <xF1>={C-v}{A-S-F1}
  +
</pre>
   
  +
produces
In addition to the Vim keycodes listed in the help section above, the keycodes
 
  +
<pre>
 
  +
:set <xF1>=^[&lt;S-F1>
for the function keys actually go up to F37. This means, we have
 
  +
</pre>
 
 
 
&lt;F1&gt; to &lt;F37&gt;
 
 
&lt;S-F1&gt; to &lt;S-F37&gt;
 
 
 
 
We can use this to our advantage to create more "responsive" mappings. More on
 
 
this later in section 2b.
 
 
 
 
We can also set these Vim keycodes:
 
 
 
 
&lt;C-Home&gt;, &lt;C-End&gt;
 
 
&lt;S-Home&gt;, &lt;S-End&gt;
 
 
&lt;S-a&gt; to &lt;S-z&gt;
 
 
&lt;C-a&gt; to &lt;C-z&gt;
 
 
&lt;A-a&gt; to &lt;A-z&gt;
 
 
 
 
Be careful when setting these keycodes. See section 3a.
 
 
 
 
 
 
1c. Setting Vim keycodes
 
 
========================
 
 
 
 
The internal keycodes look a lot like the keystrokes we would define in a
 
 
mapping. They are both easy to read, are quite intuitive, and are virtually
 
 
treated the same by Vim. The only difference is that we can :set internal
 
 
keycodes. For example, to manually set the keycode for Shift-Down_arrow, do
 
 
 
 
:set &lt;S-Down&gt;=^[[1;2B
 
 
 
 
where ^[ is a literal ESC special character.
 
 
 
 
This is NOT allowed because the keycode is not a listed Vim keycode:
 
 
 
 
:set &lt;C-S-Down&gt;=^[[1;6B
 
 
 
 
Once the correct terminal keycode is assigned to the appropriate Vim keycode,
 
 
the keystroke should work in terminal Vim.
 
 
 
 
For instance, Shift-Down_arrow should now work, but Ctrl-Shift-Down_arrow
 
 
keycode cannot be set in the same way. We need mappings for this. See section
 
 
2b.
 
 
 
 
 
 
1d. Entering literal characters &amp; terminal codes
 
 
================================================
 
 
 
 
Either in the :command line, or in Insert mode:
 
 
 
 
To enter a literal character in Vim, first type Ctrl-v, followed by a single
 
 
keystroke. Hence, typing Ctrl-v + Esc will produce "^[".
 
 
 
 
To enter a terminal keycode in Vim, first type Ctrl-v, followed by the
 
 
keystroke we want to obtain the term keycode from. Hence, typing Ctrl-v +
 
 
Shift-Down_arrow will produce "^[[1;2B".
 
 
 
 
This means that there are 2 ways to set the Vim keycode as shown in section 1c:
 
 
 
 
"literally enter the keycode
 
 
:set &lt;S-Down&gt;={C-v}{Esc}[1;2B
 
 
 
 
or
 
 
 
 
"let the terminal send its keycode to Vim
 
 
:set &lt;S-Down&gt;={C-v}{S-Down}
 
 
 
 
where curly brackets {..} denote the action of typing the keystroke. For
 
 
instance, when you see {C-v}, hold down Ctrl and hit "v". DO NOT type it
 
 
literally as "{C-v}".
 
 
 
 
We shall use the curly brackets as nomenclature from now on.
 
 
 
 
Also make use of the Normal mode command 'ga' to inspect the resulting keycode.
 
 
Place the cursor over a special character, and type 'ga'. This will provide you
 
 
with ascii information of the character under the cursor.
 
 
 
 
See
 
 
 
 
:help i_ctrl-v
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:ga}} :help ga]
 
 
 
 
 
 
2a. Mappings
 
 
============
 
 
 
 
The function of mappings in Vim is to map a set of keystrokes to another set of
 
 
keystrokes. For more information, see
 
 
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:key-mapping}} :help key-mapping]
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:map-modes}} :help map-modes]
 
 
[http://groups.yahoo.com/group/vim/message/69366   http://groups.yahoo.com/group/vim/message/69366 ];
 
 
 
 
 
 
2b. Mapping "fast" keycodes
 
 
===========================
 
 
 
 
As mentioned in section 1c, the Ctrl-Shift-Down_arrow keycode cannot be set in
 
 
the same way as the Shift-Down_arrow keycode because it is not a listed Vim
 
 
keycode. One way to get around that is to do the following:
 
 
 
 
:map &lt;Esc&gt;[1;6B &lt;C-S-Down&gt;
 
 
 
 
This maps the literal terminal keycode to a Vim keystroke (remember, not a Vim
 
 
keycode).
 
 
 
 
The disadvantage of this is that Vim will "wait" everytime after the Esc key
 
 
pressed for a potential "[" + "1" + ";" + "6" + "B" keystroke combination, just
 
 
in case you meant to do &lt;C-S-Down&gt; instead of a simple &lt;Esc&gt; to Normal mode.
 
 
 
 
If you typed "{Esc}[1;6B" fast enough, you would do a Ctrl-Shift-Down_arrow.
 
 
After all, you are mapping a keystroke, not a keycode.
 
 
 
 
A better way of mapping keycodes is to first assign the terminal keycode to an
 
 
unused Vim keycode, and then map the newly used Vim keycode. This way, we can
 
 
set 'ttimeoutlen' to a small value to ensure that the terminal keycode can only
 
 
be entered into Vim as fast as the terminal can, but will be humanly-impossible
 
 
to do it manually.
 
 
 
 
This is how it is done:
 
 
 
 
:set timeout timeoutlen=1000 ttimeoutlen=100
 
 
:set &lt;F13&gt;=^[[1;6B
 
 
:map &lt;F13&gt; &lt;C-S-Down&gt;
 
 
:map! &lt;F13&gt; &lt;C-S-Down&gt;
 
 
 
 
Now, Ctrl-Shift-Down_arrow will work, and Esc will not pause.
 
 
 
 
Potentially unused Vim keycodes that can be used include:
 
 
 
 
&lt;F13&gt; to &lt;F37&gt;
 
 
&lt;S-F13&gt; to &lt;S-F37&gt;
 
 
&lt;xF1&gt; to &lt;xF4&gt;
 
 
&lt;S-xF1&gt; to &lt;S-xF4&gt;
 
 
 
 
When setting any Vim keycode, exercise caution. Do some checks to see if the
 
 
terminal code you're setting the Vim keycode to is set elsewhere. There must be
 
 
no conflicts.
 
 
 
 
For instance, in a win32 terminal, &lt;F1&gt; to &lt;F4&gt; will always be set the same as
 
 
&lt;xF1&gt; to &lt;xF4&gt;, respectively. Therefore, you cannot use those keycodes.
 
 
 
 
See
 
 
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:'timeout'}} :help 'timeout']
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:'timeoutlen'}} :help 'timeoutlen']
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:'ttimeoutlen'}} :help 'ttimeoutlen']
 
 
 
 
 
 
2c. Laying it out in VIMRC
 
 
==========================
 
 
 
 
Here is an example of how to set up the keycodes in a VIMRC file. It is highly
 
 
recommended that you start Vim without any startup scripts that may interfere
 
 
with keycode detection:
 
 
 
 
$ vim -Nu NONE .vimrc
 
 
 
 
===
 
 
set timeout timeoutlen=1000 ttimeoutlen=100
 
 
 
 
if !has("gui_running")
 
 
if &amp;term == "xterm"
 
 
set &lt;Home&gt;=^[[H &lt;End&gt;=^[[F &lt;BS&gt;=^?
 
 
set &lt;S-Up&gt;=^[[1;2A &lt;S-Down&gt;=^[[1;2B &lt;S-Right&gt;=^[[1;2C &lt;S-Left&gt;=^[[1;2D
 
 
 
 
set &lt;xF1&gt;={C-v}{C-S-Up}^[[1;6A &lt;xF2&gt;=^[[1;6B &lt;xF3&gt;=^[[1;6C &lt;xF4&gt;=^[[1;6D
 
 
map &lt;xF1&gt; &lt;C-S-Up&gt;
 
 
map &lt;xF2&gt; &lt;C-S-Down&gt;
 
 
map &lt;xF3&gt; &lt;C-S-Right&gt;
 
 
map &lt;xF4&gt; &lt;C-S-Left&gt;
 
 
map! &lt;xF1&gt; &lt;C-S-Up&gt;
 
 
map! &lt;xF2&gt; &lt;C-S-Down&gt;
 
 
map! &lt;xF3&gt; &lt;C-S-Right&gt;
 
 
map! &lt;xF4&gt; &lt;C-S-Left&gt;
 
 
 
 
elseif &amp;term == "win32"
 
 
...
 
 
else
 
 
...
 
 
endif
 
 
endif
 
 
===
 
 
 
 
where ^[ is a literal ESC special character and ^? is a literal ascii 0x7f
 
 
character.
 
 
 
 
See
 
 
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:'term'}} :help 'term']
 
 
[http://vimplugin.sf.net/cgi-bin/help?tag={{urlencode:has-patch}} :help has-patch]
 
 
 
 
 
 
3a. Troubleshooting I
 
 
=====================
 
 
 
 
You only need to employ unused Vim keycodes either when
 
 
 
 
(a) there are no available Vim keycodes that match the terminal keycode, and
 
 
(b) the terminal keycode is longer than a single keystroke
 
 
 
 
or
 
 
 
 
(c) setting the Vim keycode that matches the terminal keycode causes weird
 
 
behavior
 
 
 
 
Example where (a) is not true:
 
 
------------------------------
 
 
:set &lt;F13&gt;=^[[1;2B
 
 
:map &lt;F13&gt; &lt;S-Down&gt;
 
 
 
 
Setting the unused &lt;F13&gt; is redundant, because &lt;S-Down&gt; is already available as
 
 
a Vim keycode. Do this instead:
 
 
 
 
:set &lt;S-Down&gt;=^[[1;2B
 
 
 
 
 
 
Example where (b) is not true:
 
 
------------------------------
 
 
For a win32 terminal, mapping Ctrl-Backspace is done by
 
 
 
 
:map &lt;C-{C-v}{BS}&gt; &lt;C-BS&gt;
 
 
 
 
Since the terminal keycode can be represented by &lt;C-^?&gt;, which is a single
 
 
keystroke, there is no need to employ an unused Vim keycode.
 
 
 
 
 
 
Example where (c) is true:
 
 
--------------------------
 
 
For an rxvt terminal, merely doing
 
 
 
 
:set &lt;A-j&gt;=^[j &lt;A-u&gt;=^[u &lt;A-6&gt;=^[6
 
 
 
 
will not make Alt-j, Alt-u and Alt-6 work. Reason unknown. Need to assign to
 
 
unused Vim keycodes.
 
 
 
 
 
 
3b. Troubleshooting II
 
 
======================
 
 
 
 
Sometimes, performing
 
 
 
 
:set &lt;xF1&gt;={C-v}{A-S-F1}
 
 
 
 
produces
 
 
 
 
:set &lt;xF1&gt;=^[&lt;S-F1&gt;
 
 
 
 
where ^[ is a literal ESC special character and "&lt;S-F1&gt;" is literal text.
 
 
 
 
This means that you may have already set Vim's keycode &lt;S-F1&gt;, and that it was
 
 
part of the Alt-Shift-F1 terminal keycode that was sent to Vim. Vim processes
 
 
the entire terminal keycode and noticed that it could replace part of it with
 
 
its own internal representation.
 
 
 
 
To fix this and enter the full terminal keycode, backspace up to "&lt;" and do
 
 
{C-v}{S-F1}. The full action would be:
 
 
 
 
:set &lt;xF1&gt;={C-v}{A-S-F1}{BS 6 times}{C-v}{S-F1}
 
 
 
 
to produce
 
 
 
 
:set &lt;xF1&gt;=^[^[[23~
 
 
 
 
To give some perspective, here are the actual terminal keycodes for rxvt:
 
 
 
 
&lt;S-F1&gt; = ^[[23~
 
 
&lt;A-S-F1&gt; = ^[^[[23~
 
 
 
}}
 
 
== Comments ==
 
nice tip.
 
   
  +
where ^[ is a literal ESC special character and "&lt;S-F1>" is literal text.
One question: Emacs map all keycodes on windows and X, like:
 
   
  +
This means that you may have already set Vim's keycode &lt;S-F1>, and that it was part of the Alt-Shift-F1 terminal keycode that was sent to Vim. Vim processes the entire terminal keycode and noticed that it could replace part of it with its own internal representation.
Alt-Num-5,
 
M-H-S-s-&lt;SPACE&gt;
 
   
  +
To fix this and enter the full terminal keycode, backspace up to "<" and do {C-v}{S-F1}. The full action would be:
How do I do the same in gvim?
 
  +
<pre>
  +
:set <xF1>={C-v}{A-S-F1}{BS 6 times}{C-v}{S-F1}
  +
</pre>
   
  +
to produce
For example:
 
  +
<pre>
:map &lt;C-v&gt;&lt;Alt-Num-5&gt; .. gvim doesn't read the second key, emacs does and echoes the name.
 
  +
:set <xF1>=^[^[[23~
  +
</pre>
   
  +
To give some perspective, here are the actual terminal keycodes for rxvt:
Ajit
 
  +
<pre>
, June 25, 2006 20:37
 
  +
&lt;S-F1> = ^[[23~
----
 
  +
<A-S-F1> = ^[^[[23~
very good tip! suggest to add into vim's online help :)
 
  +
</pre>
   
  +
==Comments==
linsong dot qizi AT gmail dot com
 
, June 26, 2006 22:18
 
----
 
<!-- parsed by vimtips.py in 0.907716 seconds-->
 

Revision as of 06:23, 18 May 2014

Tip 1272 Printable Monobook Previous Next

created 2006 · complexity intermediate · author Gerald Lai · version 6.0


In the GUI version of Vim (gvim), the mapping of keys seem to work for the most part. For instance, it is easy to map Ctrl-Shift-F2 to a keystroke:

"delete all lines in the current buffer
:nmap <C-S-F2> ggdG

For terminal versions of Vim (such as xterm, rxvt, win32, etc), mapping something like Ctrl-Shift-F2 needs some extra work. It may seem daunting to deal with archaic terminal keycodes at first, but once you understand what is going on in the right context, it is quite simple.

1a. Keycodes

There are two types of keycodes: terminal keycodes and Vim keycodes. Terminal keycodes look something like

^[[1;2A

These are actual bytes that are sent to Vim by the terminal when we type Shift-Up, for example (on an xterm).

Vim keycodes look like

<S-Up>

Vim needs its own representation of keycodes because it runs on a variety of platforms. Vim can act upon its own keycodes, and leave the assignment of terminal keycodes to autodetection (or to manual setup by the user, which is what this guide is for).

1b. List of usable keycodes

To obtain a list of terminal keycodes, look it up in the manual for that terminal.

For a list of Vim's internal keycodes, see :help t_ku. Enter :set termcap to list the terminal keycodes (see :help terminal-options).

In addition to the Vim keycodes listed in the help section above, the keycodes for the function keys actually go up to F37. This means, we have

<F1> to <F37>
<S-F1> to <S-F37>

We can use this to our advantage to create more "responsive" mappings. More on this later in section 2b.

We can also set these Vim keycodes:

<C-Home>, <C-End>
<S-Home>, <S-End>
<S-a> to <S-z>
<C-a> to <C-z>
<A-a> to <A-z>

Be careful when setting these keycodes. See section 3a.

1c. Setting Vim keycodes

Vim keycodes look a lot like the keystrokes we would define in a mapping. They are easy to read, quite intuitive, and are almost treated the same by Vim. The only difference is that we can :set internal keycodes. For example, to manually set the keycode for Shift-Down_arrow:

:set <S-Down>=^[[1;2B

where ^[ is a literal ESC special character.

The following is not allowed because the keycode is not a listed Vim keycode:

:set <C-S-Down>=^[[1;6B

Once the correct terminal keycode is assigned to the appropriate Vim keycode, the keystroke should work in terminal Vim. Shift-Down_arrow should now work, but the Ctrl-Shift-Down_arrow keycode can not be set in the same way. For this we need mappings (see section 2b).

1d. Entering literal characters & terminal codes

Either in the :command line, or in insert mode:

To enter a literal character in Vim, first type Ctrl-v, followed by a single keystroke. Hence, typing Ctrl-v then Esc will produce "^[".

To enter a terminal keycode in Vim, first type Ctrl-v, followed by the keystroke we want to obtain the term keycode from. Hence, typing Ctrl-v + Shift-Down_arrow will produce "^[[1;2B".

This means that there are 2 ways to set the Vim keycode as shown in section 1c:

"literally enter the keycode
:set <S-Down>={C-v}{Esc}[1;2B

or

"let the terminal send its keycode to Vim
:set <S-Down>={C-v}{S-Down}

where curly brackets {..} denote the action of typing the keystroke. For instance, when you see {C-v}, hold down Ctrl and hit "v". Do not type it literally as "{C-v}".

We shall use the curly brackets as nomenclature from now on.

Also make use of the Normal mode command 'ga' to inspect the resulting keycode. Place the cursor over a special character, and type 'ga'. This will provide you with ascii information of the character under the cursor.

See :help i_ctrl-v, :help ga.

2a. Mappings

The function of mappings in Vim is to map a set of keystrokes to another set of keystrokes. For more information, see :help key-mapping, :help map-modes.

2b. Mapping "fast" keycodes

As mentioned in section 1c, the Ctrl-Shift-Down_arrow keycode cannot be set in the same way as the Shift-Down_arrow keycode because it is not a listed Vim keycode. One way to get around that is to do the following:

:map <Esc>[1;6B <C-S-Down>

This maps the literal terminal keycode to a Vim keystroke (remember, not a Vim keycode).

The disadvantage of this is that Vim will "wait" everytime after the Esc key pressed for a potential "[" + "1" + ";" + "6" + "B" keystroke combination, just in case you meant to do <C-S-Down> instead of a simple <Esc> to Normal mode.

If you typed "{Esc}[1;6B" fast enough, you would do a Ctrl-Shift-Down_arrow. After all, you are mapping a keystroke, not a keycode.

A better way of mapping keycodes is to first assign the terminal keycode to an unused Vim keycode, and then map the newly used Vim keycode. This way, we can set 'ttimeoutlen' to a small value to ensure that the terminal keycode can only be entered into Vim as fast as the terminal can, but will be humanly-impossible to do it manually.

This is how it is done:

:set timeout timeoutlen=1000 ttimeoutlen=100
:set <F13>=^[[1;6B
:map <F13> <C-S-Down>
:map! <F13> <C-S-Down>

Now, Ctrl-Shift-Down_arrow will work, and Esc will not pause.

Potentially unused Vim keycodes that can be used include:

<F13> to <F37>
<S-F13> to <S-F37>
<xF1> to <xF4>
<S-xF1> to <S-xF4>

When setting any Vim keycode, exercise caution. Do some checks to see if the terminal code you're setting the Vim keycode to is set elsewhere. There must be no conflicts.

For instance, in a Win32 terminal, <F1> to <F4> will always be set the same as <xF1> to <xF4>, respectively. Therefore, you cannot use those keycodes.

See :help 'timeout', :help 'timeoutlen', :help 'ttimeoutlen'.

2c. Laying it out in vimrc

Here is an example of how to set up the keycodes in a vimrc file. It is highly recommended that you start Vim without any startup scripts that may interfere with keycode detection:

$ vim -Nu NONE .vimrc
set timeout timeoutlen=1000 ttimeoutlen=100
if !has("gui_running")
  if &term == "xterm"
    set <Home>=^[[H <End>=^[[F <BS>=^?
    set <S-Up>=^[[1;2A <S-Down>=^[[1;2B <S-Right>=^[[1;2C <S-Left>=^[[1;2D
    set <xF1>={C-v}{C-S-Up}^[[1;6A <xF2>=^[[1;6B <xF3>=^[[1;6C <xF4>=^[[1;6D
    map <xF1> <C-S-Up>
    map <xF2> <C-S-Down>
    map <xF3> <C-S-Right>
    map <xF4> <C-S-Left>
    map! <xF1> <C-S-Up>
    map! <xF2> <C-S-Down>
    map! <xF3> <C-S-Right>
    map! <xF4> <C-S-Left>
  elseif &term == "win32"
    ...
  else
    ...
  endif
endif

where ^[ is a literal ESC special character and ^? is a literal ascii 0x7f character.

See :help 'term', :help has-patch.

You can also use a function like the following to automatically assign fast keycodes:

" MapFastKeycode: helper for fast keycode mappings
" makes use of unused vim keycodes <[S-]F15> to <[S-]F37>
function! <SID>MapFastKeycode(key, keycode)
    if s:fast_i == 46
        echohl WarningMsg
        echomsg "Unable to map ".a:key.": out of spare keycodes"
        echohl None
        return
    endif
    let vkeycode = '<'.(s:fast_i/23==0 ? '' : 'S-').'F'.(15+s:fast_i%23).'>'
    exec 'set '.vkeycode.'='.a:keycode
    exec 'map '.vkeycode.' '.a:key
    let s:fast_i += 1
endfunction
let s:fast_i = 0

It uses Vim keycodes <F15> and above. If you don't have keys for <F13> and <F14> on your keyboard, you can also make use of those, for a total of 50 keys you can map this way.

Once defined, you can use the function to map keys like so: (example for rxvt)

call <SID>MapFastKeycode('<C-F3>', "\e[13^")
call <SID>MapFastKeycode('<C-F4>', "\e[14^")
call <SID>MapFastKeycode('<M-j>', "\ej")
call <SID>MapFastKeycode('<M-k>', "\ek")
" ...

3a. Troubleshooting I

You only need to employ unused Vim keycodes either when
(a) there are no available Vim keycodes that match the terminal keycode, and
(b) the terminal keycode is longer than a single keystroke
or
(c) setting the Vim keycode that matches the terminal keycode causes weird behavior.

Example where (a) is not true:

:set <F13>=^[[1;2B
:map <F13> <S-Down>

Setting the unused <F13> is redundant, because <S-Down> is already available as a Vim keycode. Do this instead:

:set <S-Down>=^[[1;2B

Example where (b) is not true:

For a Win32 terminal, mapping Ctrl-Backspace is done by

:map <C-{C-v}{BS}> <C-BS>

Since the terminal keycode can be represented by <C-^?>, which is a single keystroke, there is no need to employ an unused Vim keycode.

Example where (c) is true:

For an rxvt terminal, merely doing

:set <A-j>=^[j <A-u>=^[u <A-6>=^[6

will not make Alt-j, Alt-u and Alt-6 work. Reason unknown. Need to assign to unused Vim keycodes.

3b. Troubleshooting II

Sometimes, performing

:set <xF1>={C-v}{A-S-F1}

produces

:set <xF1>=^[<S-F1>

where ^[ is a literal ESC special character and "<S-F1>" is literal text.

This means that you may have already set Vim's keycode <S-F1>, and that it was part of the Alt-Shift-F1 terminal keycode that was sent to Vim. Vim processes the entire terminal keycode and noticed that it could replace part of it with its own internal representation.

To fix this and enter the full terminal keycode, backspace up to "<" and do {C-v}{S-F1}. The full action would be:

:set <xF1>={C-v}{A-S-F1}{BS 6 times}{C-v}{S-F1}

to produce

:set <xF1>=^[^[[23~

To give some perspective, here are the actual terminal keycodes for rxvt:

<S-F1> = ^[[23~
<A-S-F1> = ^[^[[23~

Comments