Keyboard input handling

4,465 views
Skip to first unread message

Paul LeoNerd Evans

unread,
May 4, 2010, 7:14:06 PM5/4/10
to vim...@googlegroups.com
Vim's keyboard input system revolves centrally around a queue of bytes.
This worked well when all the world was serial terminals. In this new
world of GUIs this model doesn't work so well. I advocate changing it to
a queue of keypress events.

Over the past 7 years, I have been a member of the #vim channel on
Freenode. Almost every week we get somebody in the channel who wonders
such things as how to map Ctrl-Shift-T differently from Ctrl-T. We
explain that isn't possible. Even in Gvim. Because of vim's input queue
system. People often don't realise that Tab is Ctrl-I, or Enter is
Ctrl-M. We have to explain why it's not possible to map one of these
pairs without breaking the other. It's become apparent to me that the
byte-based model is no longer appropriate if Vim is to remain relevant
and current on newer platforms. It's time we changed the core.

I would like to propose that the base of the input queue be turned into
a queue of structures something like the following form:

struct keypress {
enum {
UNICODE,
SPECIAL,
} type;
int keycode;
int modifiers;
};

In this scheme we can represent any of the keypresses vim can handle:

A = { .type = UNICODE, keycode = 'A', .modifiers = 0 }
<Ctrl-T> = { .type = UNICODE, keycode = 'T', .modifiers = CTRL }
<Enter> = { .type = SPECIAL, keycode = ENTER, .modifiers = 0 }

In this scheme, it is simple to write the code that :map etc.. will use
to recognise the keys and turn them into basic operations. It's also
simple to generate these events from GUI events (such as from GTK or
Win32).

This scheme is also relatively simple to generate from terminal input
bytes, since vim already has this functionality.

Once using this scheme, gvim would now fully support mapping Tab, Ctrl-I
and Ctrl-Shift-I as three separate independent keys. Newer terminals
like xterm already posess ways to encode these three keystrokes
differently at the byte level, and with e.g. libtermkey[*]'s help, vim
could be taught how to recognise all these three too.

In recognition of the non-trivial amount of work required here, and as a
token of my commitment to this issue, I would be happy to donate a
further EUR100 to the vim development sponsorship on top of the EUR20 I
have just sent, if we could come to a mutual agreement on how to proceed
on this front. It would be great if we would be able to make this
feature a reality; I would be happy to consider a further donation at
that point.

I know this isn't the way terminals have worked for the past 20 years.
However, it is the way "terminals", being the units of end-user
interaction, will work for the next 20 years. It would be nice if vim
were able to cope as well with the next 20 as it has with the last.

-----
*: I have also been developing a library, libtermkey, which aims to be
a better way to read key press events from terminals than existing
solutions that are curses or terminfo-based. While it reads the
terminfo database, it also fully understands the extended ways that
xterm et.al. encode modified keypresses, in a way that would be
fully compatible with vim's core, and existing behaviours.

http://www.leonerd.org.uk/code/libtermkey/
-----

--
Paul "LeoNerd" Evans

leo...@leonerd.org.uk
ICQ# 4135350 | Registered Linux# 179460
http://www.leonerd.org.uk/

signature.asc

Tom Sorensen

unread,
May 4, 2010, 8:14:13 PM5/4/10
to vim...@googlegroups.com
On Tue, May 4, 2010 at 7:14 PM, Paul LeoNerd Evans
<leo...@leonerd.org.uk> wrote:
> Over the past 7 years, I have been a member of the #vim channel on
> Freenode. Almost every week we get somebody in the channel who wonders
> such things as how to map Ctrl-Shift-T differently from Ctrl-T. We
> explain that isn't possible. Even in Gvim.

Actually, he's understating it. We usually get at least two people a
week. Several people a day isn't too uncommon. A lot of this is
because vim has already used pretty much every non-shifted key on the
keyboard -- you're left with either replacing default functionality
(which I don't like suggesting) or using <Leader> based combinations
(which I'm fine with, to a certain extent, but many others are not).

> *: I have also been developing a library, libtermkey, which aims to be
>   a better way to read key press events from terminals than existing
>   solutions that are curses or terminfo-based. While it reads the
>   terminfo database, it also fully understands the extended ways that
>   xterm et.al. encode modified keypresses, in a way that would be
>   fully compatible with vim's core, and existing behaviours.

Paul knows his stuff when it comes to terminal encoding. He's one of
the only people who *really* understands termcap/terminfo that I know,
as well as xterm and EMCA standards. And he's stated on #vim that
libtermkey is backwards compatible in that it will read terminfo files
and handle anything in the terminfo database correctly. The API is
different, but that's because it has to be -- it's exposing far more
functionality than termcap/terminfo could ever dream of.

Historically, termcap and terminfo date back to code that was
originally in vi. I think it would be appropriate if the next
improvement in terminal key handling came, in large part, from the vim
community. It would be a great feature for v8. And I'm quite sure
there would be plenty of beta testers on numerous platforms (I'll
personally volunteer for XP, AIX 5.3, Solaris 9, RHEL5, and RHEL6).

Tom

--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

Matt Wozniski

unread,
May 5, 2010, 3:23:59 AM5/5/10
to vim...@googlegroups.com
On Tue, May 4, 2010 at 8:14 PM, Tom Sorensen wrote:
> On Tue, May 4, 2010 at 7:14 PM, Paul LeoNerd Evans
> <leo...@leonerd.org.uk> wrote:
>> Over the past 7 years, I have been a member of the #vim channel on
>> Freenode. Almost every week we get somebody in the channel who wonders
>> such things as how to map Ctrl-Shift-T differently from Ctrl-T. We
>> explain that isn't possible. Even in Gvim.
>
> Actually, he's understating it. We usually get at least two people a
> week. Several people a day isn't too uncommon. A lot of this is
> because vim has already used pretty much every non-shifted key on the
> keyboard -- you're left with either replacing default functionality
> (which I don't like suggesting) or using <Leader> based combinations
> (which I'm fine with, to a certain extent, but many others are not).

I'd be certain that the average is at least 2 or 3 people a day - many
of the IRC regulars have seen this question get asked multiple times
in one day, and we're not on for 24 hours - usually more like 2 or 3.
And let's not forget how often it comes up on the mailing list - A
quick search over the last ~1 year shows the below list of threads
that all amount to "you can't map that in vim". I emphatically agree
that vim's keyboard handling is one of the ugliest parts of the
editor; something definitely needs to be done to bring vim back up on
par with other GUI tools.

~Matt

Mapping Shift-space: how to tell if its possible?
How to imap <C-=> ?
CTRL+W under MS Windows
map <a-h> on win32 (Win XP) gvim 7.2 in french layout work incorrectly
accent grave in french(France) keyboard layout is not printing. win32
(Win XP) Platform
why nmap<A-0> not work?
map <a-h> on win32 (Win XP) gvim 7.2 in french layout work incorrectly
What is Alt-T supposed to do by default?
Mapping ctrl-; (ctrl semicolon)
mapping problems
How to map Ctrl+/ ?
mapping alt-keys
add mapping to auto-fill
Binding Ctrl+Tab and Ctrl+Shift+Tab difficulties with Vim and PuTTY.
Bugging me for a long time
Can't :imap <S-space>
How to map Alt+key when using vim in putty
How to get Alt-[ in putty terminal
How to map ctrl-del to delete word?
how to map <tab> and <c-i> independently
How to map key shift+ctrl+N?
I can't "remap" <Shift-F4> key
Insert Mode Mappings on a Mac
map! <C-=> <C-o>gt and map! <C--> <C-o>gT Don't work
map command, ctrl-v and .vimrc
"map <C-J> <C-W>j" not operate...help..
mapping control+0-1 or backtick
Maping Ctrl-Shift-s problems
Mapping shift-space
Mappings to shift-keys within terminal mode
Mappings for tab navigation don't work
<Tab> and <C-i> will clash in mappings
unable to map ctrl-1
Unable to map Ctrl+Shift+Z
Strange behavior with Key Maps

Henrik Öhman

unread,
May 5, 2010, 10:21:45 AM5/5/10
to vim_dev
On May 5, 1:14 am, Paul LeoNerd Evans <leon...@leonerd.org.uk> wrote:
> Vim's keyboard input system revolves centrally around a queue of bytes.
> This worked well when all the world was serial terminals. In this new
> world of GUIs this model doesn't work so well. I advocate changing it to
> a queue of keypress events.
[...]

FWIW: I wholeheartedly support this feature, and would make myself
available for implementation and testing, if someone with the ability
to see it through takes the lead.

Henrik

Ben Fritz

unread,
May 5, 2010, 11:20:25 AM5/5/10
to vim_dev


On May 4, 6:14 pm, Paul LeoNerd Evans <leon...@leonerd.org.uk> wrote:
> Vim's keyboard input system revolves centrally around a queue of bytes.
> This worked well when all the world was serial terminals. In this new
> world of GUIs this model doesn't work so well. I advocate changing it to
> a queue of keypress events.
>

I know next to nothing about the termcap/terminfo/etc. code or what is
involved in such a change, and do not have the time currently to start
delving into Vim's C code (sometime soon, I keep telling myself) but I
would certainly be willing to test on Windows XP and Vista, even to
the point of learning how to compile my own Vim on these systems so
that I can try out the patches.

I have a Ubuntu system at home but don't get many chances to use it; I
image we'll have a plethora of testers on such systems though.

Dennis Benzinger

unread,
May 5, 2010, 11:27:14 AM5/5/10
to vim...@googlegroups.com
-------- Original-Nachricht --------
> Datum: Wed, 5 May 2010 00:14:06 +0100
> Von: Paul LeoNerd Evans <leo...@leonerd.org.uk>
> An: vim...@googlegroups.com
> Betreff: Keyboard input handling

> Vim's keyboard input system revolves centrally around a queue of bytes.
> This worked well when all the world was serial terminals. In this new
> world of GUIs this model doesn't work so well. I advocate changing it to
> a queue of keypress events.
> [...]

I could test it on Ubuntu 10.04 and Mac OS X 10.6.
Would this change also handle special keys found on some keyboards?
I could test with some different keyboards.


HTH,
Dennis Benzinger

Matt Wozniski

unread,
May 5, 2010, 3:05:25 PM5/5/10
to vim...@googlegroups.com
On Wed, May 5, 2010 at 11:20 AM, Ben Fritz wrote:
>
>
> On May 4, 6:14 pm, Paul LeoNerd Evans <leon...@leonerd.org.uk> wrote:
>> Vim's keyboard input system revolves centrally around a queue of bytes.
>> This worked well when all the world was serial terminals. In this new
>> world of GUIs this model doesn't work so well. I advocate changing it to
>> a queue of keypress events.
>>
>
> I know next to nothing about the termcap/terminfo/etc. code or what is
> involved in such a change, and do not have the time currently to start
> delving into Vim's C code (sometime soon, I keep telling myself) but I
> would certainly be willing to test on Windows XP and Vista, even to
> the point of learning how to compile my own Vim on these systems so
> that I can try out the patches.
>
> I have a Ubuntu system at home but don't get many chances to use it; I
> image we'll have a plethora of testers on such systems though.

I've got access to xterm on HP-UX, AIX, and Solaris 9 and 10 - nothing
too exotic, but I can help test there - and in Linux with fbiterm,
which is pretty exotic as far as terminal emulators go these days.

~Matt

Bram Moolenaar

unread,
May 5, 2010, 4:40:39 PM5/5/10
to Paul LeoNerd Evans, vim...@googlegroups.com

Paul LeoNerd Evans wrote:

> Vim's keyboard input system revolves centrally around a queue of bytes.
> This worked well when all the world was serial terminals. In this new
> world of GUIs this model doesn't work so well. I advocate changing it to
> a queue of keypress events.
>
> Over the past 7 years, I have been a member of the #vim channel on
> Freenode. Almost every week we get somebody in the channel who wonders
> such things as how to map Ctrl-Shift-T differently from Ctrl-T. We
> explain that isn't possible. Even in Gvim. Because of vim's input queue
> system. People often don't realise that Tab is Ctrl-I, or Enter is
> Ctrl-M. We have to explain why it's not possible to map one of these
> pairs without breaking the other. It's become apparent to me that the
> byte-based model is no longer appropriate if Vim is to remain relevant
> and current on newer platforms. It's time we changed the core.

That's not completely correct. Vim can have a key modifier in the
queue, it can have CTRL and SHIFT before a T. It's a design choice to
have CTRL-SHIFT-T and CTRL-T result in the same code. See the global
variable "mod_mask".

It's possible to make a difference between the two when there is a
mapping for CTRL-SHIFT-T. I actually thought that was working, but it
doesn't. Perhaps this only works in combination with Alt, don't have
time right now to check the details.

> I would like to propose that the base of the input queue be turned into
> a queue of structures something like the following form:
>
> struct keypress {
> enum {
> UNICODE,
> SPECIAL,
> } type;
> int keycode;
> int modifiers;
> };
>
> In this scheme we can represent any of the keypresses vim can handle:
>
> A = { .type = UNICODE, keycode = 'A', .modifiers = 0 }
> <Ctrl-T> = { .type = UNICODE, keycode = 'T', .modifiers = CTRL }
> <Enter> = { .type = SPECIAL, keycode = ENTER, .modifiers = 0 }
>
> In this scheme, it is simple to write the code that :map etc.. will use
> to recognise the keys and turn them into basic operations. It's also
> simple to generate these events from GUI events (such as from GTK or
> Win32).
>
> This scheme is also relatively simple to generate from terminal input
> bytes, since vim already has this functionality.
>
> Once using this scheme, gvim would now fully support mapping Tab, Ctrl-I
> and Ctrl-Shift-I as three separate independent keys. Newer terminals
> like xterm already posess ways to encode these three keystrokes
> differently at the byte level, and with e.g. libtermkey[*]'s help, vim
> could be taught how to recognise all these three too.

I think this is possible without changing the input queue.

> In recognition of the non-trivial amount of work required here, and as a
> token of my commitment to this issue, I would be happy to donate a
> further EUR100 to the vim development sponsorship on top of the EUR20 I
> have just sent, if we could come to a mutual agreement on how to proceed
> on this front. It would be great if we would be able to make this
> feature a reality; I would be happy to consider a further donation at
> that point.
>
> I know this isn't the way terminals have worked for the past 20 years.
> However, it is the way "terminals", being the units of end-user
> interaction, will work for the next 20 years. It would be nice if vim
> were able to cope as well with the next 20 as it has with the last.
>
> -----
> *: I have also been developing a library, libtermkey, which aims to be
> a better way to read key press events from terminals than existing
> solutions that are curses or terminfo-based. While it reads the
> terminfo database, it also fully understands the extended ways that
> xterm et.al. encode modified keypresses, in a way that would be
> fully compatible with vim's core, and existing behaviours.
>
> http://www.leonerd.org.uk/code/libtermkey/

Now that sounds like a long awaited improvement. The termcap/terminfo
system is completely inadequate. Vim must have xterm special key
support built-in, since there is no way to define these keys with the
old libraries.

It would be great if someone can make a patch for Vim that uses this
library and is fully backwards compatible for the special xterm keys
codes. That would be a good test for the library as well.

--
hundred-and-one symptoms of being an internet addict:
23. You can't call your mother...she doesn't have a modem.

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ download, build and distribute -- http://www.A-A-P.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Paul LeoNerd Evans

unread,
May 7, 2010, 7:15:08 AM5/7/10
to vim...@googlegroups.com
On Wed, May 05, 2010 at 10:40:39PM +0200, Bram Moolenaar wrote:
> It's possible to make a difference between the two when there is a
> mapping for CTRL-SHIFT-T. I actually thought that was working, but it
> doesn't. Perhaps this only works in combination with Alt, don't have
> time right now to check the details.
...

> > http://www.leonerd.org.uk/code/libtermkey/
>
> Now that sounds like a long awaited improvement. The termcap/terminfo
> system is completely inadequate. Vim must have xterm special key
> support built-in, since there is no way to define these keys with the
> old libraries.
>
> It would be great if someone can make a patch for Vim that uses this
> library and is fully backwards compatible for the special xterm keys
> codes. That would be a good test for the library as well.

Hi Bram,

Thanks for the response on this. It looks like then there's three separate
issues here:

1. Making sure that the input queue really can distinguish Ctrl-T from
Ctrl-Shift-T, and also between e.g. Tab and Ctrl-I

2. Getting GUI-based frontends to correctly insert input queue
keypresses

3. Using libtermkey or similar, to recognise keypresses on terminals

I'm actually away until Tuesday now, but when I get back I'll take a
further look into things, mostly in this order. Though, I forsee there's
probably scope for some parallelising between other developers, if
someone else manages to make some headway into one of the bits in the
meantime.

signature.asc

Paul LeoNerd Evans

unread,
May 12, 2010, 1:44:02 PM5/12/10
to vim...@googlegroups.com
On Wed, May 05, 2010 at 10:40:39PM +0200, Bram Moolenaar wrote:

Actually, I've now just remembered why I wanted to change this, why I
thought a byte queue is a really bad idea.

To quote #vim/Freenode just now:

(18:31) <qbit_> can the esc key be compeletly disabled ?
(18:31) <qbit_> I am trying to force myself to use ctrl+c
(18:32) <qbit_> i tried noremap <Esc> <NOP>
(18:32) <LeoNerd> I really would suggest not
(18:32) <LeoNerd> eeeeeverything will break, if you do that
...
(18:34) <LeoNerd> If you map <Esc> away you'll break all the
arrow/function/cursor keys
(18:35) <qbit_> how will that break them ?
(18:35) <LeoNerd> Because of the way terminals work
(18:35) <LeoNerd> E.g. the <Up> arrow key is <Esc>[A
(18:35) <LeoNerd> So if you map <Esc> to something else, the Up arrow
key no longer does that.. and breakage happens

We -really- need to be able to distinguish Escape, the ASCII sequence of
0x1e, from <Esc>, the human-level idea of pressing that piece of
plastic. This would enable us to

:map <Esc> foobarsplot

without affecting any of the other keypress events that start with an
Escape byte, such as all the CSI and SS3s in 7bit legacy mode.

libtermkey already contains all the logic for this; it will only output
a KEYSYM_ESCAPE on a real Escape (by usual prefix and timing analysis),
meaning vim could map that away with confidence of knowing it hadn't
broken CSI/SS3-based keys.

If it will further sway the argument, libtermkey even supports a "render
this struct into a human-readable string" sprintf()-alike operation,
allowing it to produce strings looking like

<Escape>
<Ctrl-Up>
etc...

A little further effort could create a sscanf()-alike to parse these,
giving really easy integration with all of vim's mapping layer.


What thoughts here - can we further consider a keypress-event-structure
queue instead of raw terminal bytes?

signature.asc

Milan Vancura

unread,
May 13, 2010, 5:18:05 AM5/13/10
to vim...@googlegroups.com
Hello.

This is very interesting thread.

> We -really- need to be able to distinguish Escape, the ASCII sequence of
> 0x1e, from <Esc>, the human-level idea of pressing that piece of
> plastic. This would enable us to
>
> :map <Esc> foobarsplot

And also get rid of the waiting loop for distinguishing between manual Esc key
press and a terminal generated sequence of bytes...

BTW, slightly different topic: how can one remap some internal function from
its default hotkey to the different one? As far as I know there is nothing like
"leave insert mode" function which can be mapped to the different key in case
Esc is already mapped to something else. Am I wrong?

Typical example:

" make 'Q' working as original 'D', that part works:
:map Q D

" now remap 'D' to something else as we have 'Q' for original 'D' action already
:map D $

now both 'Q' and 'D' work as '$' instead of having 'Q' working like original
'D' and 'D' working like original '$'.

Milan

Lech Lorens

unread,
May 13, 2010, 7:19:10 AM5/13/10
to vim...@googlegroups.com
On 13 May 2010 11:18, Milan Vancura <mi...@ucw.cz> wrote:
> BTW, slightly different topic: how can one remap some internal function from
> its default hotkey to the different one? As far as I know there is nothing like
> "leave insert mode" function which can be mapped to the different key in case
> Esc is already mapped to something else. Am I wrong?
>
> Typical example:
>
> " make 'Q' working as original 'D', that part works:
> :map Q D
>
> " now remap 'D' to something else as we have 'Q' for original 'D' action already
> :map D $
>
> now both 'Q' and 'D' work as '$' instead of having 'Q' working like original
> 'D' and 'D' working like original '$'.
>
> Milan

I'm not sure I get your point, but it seems that the problem you are
describing is solved by using nnoremap, vnoremap, onoremap instead of
map.

--
Regards,
Lech Lorens

Milan Vancura

unread,
May 13, 2010, 9:08:00 AM5/13/10
to vim...@googlegroups.com
> On 13 May 2010 11:18, Milan Vancura <mi...@ucw.cz> wrote:
> > BTW, slightly different topic: how can one remap some internal function from
> > its default hotkey to the different one? As far as I know there is nothing like
> > "leave insert mode" function which can be mapped to the different key in case
> > Esc is already mapped to something else. Am I wrong?
> >
> > Typical example:
> >
> > " make 'Q' working as original 'D', that part works:
> > :map Q D
> >
> > " now remap 'D' to something else as we have 'Q' for original 'D' action already
> > :map D $
> >
> > now both 'Q' and 'D' work as '$' instead of having 'Q' working like original
> > 'D' and 'D' working like original '$'.
> >
> > Milan
>
> I'm not sure I get your point, but it seems that the problem you are
> describing is solved by using nnoremap, vnoremap, onoremap instead of
> map.

Ah, yes, my fault. Thank you. Very non-intuitive (esp. in reverse order of
mappring) but works.

Milan

boxofrox

unread,
Dec 29, 2010, 11:58:38 PM12/29/10
to vim...@vim.org

I'm interested in trying my hand at implementing this. I'm new to vim-dev,
so if anyone has any advice or reading material I should review, I'd
appreciate it :)
--
View this message in context: http://vim.1045645.n5.nabble.com/Keyboard-input-handling-tp1211322p3322160.html
Sent from the Vim - Dev mailing list archive at Nabble.com.
Reply all
Reply to author
Forward
0 new messages