Vim copes poorly with a variety of different keyboard inputs.

All the time, we get new users in #vim asking how they can map
Ctrl-Shift-L, or Alt-letters, or various other problems, and we're
forever explaining it Can't Be Done. Sometimes even in gvim, as I
understand, because of the way gvim implements a terminal-like wrapper
which presents terminal sequences at the vim core.

This presents three key problems, which I shall call Cases A, B and C:

  Case A: Ctrl-L and Ctrl-Shift-L generate the same single byte in the
    terminal; namely 0x0c. They are indistinct

  Case B: Ctrl-I and Tab generate the same single byte in the terminal;
    namely 0x09. They are indistinct

  Case C: UTF-8, Alt+letter, Esc-letter all generate the same bytes in
    the terminal. E.g. é vs. Alt+C Alt+) vs. Esc C Esc )

Cases A and B cannot be solved without fixing the terminal itself. Vim
currently uses timing information to distinguish some of Case C.

Furthermore, until very recently, Vim did not understand any of Xterm
et.al.'s modified function key sequences; e.g. Ctrl-Left. It now has some
understanding of them, but not in a way I find very satisfactory. (See
later).

I have a fix for all of this mess, which involves a combination of fixes
in the terminal, and in vim. Some of these fixes are already in progress
in xterm or other places. The fixes I suggest here for vim are either
recognition of new things that previously didn't happen, or changes to
internals that would be of greater benefit anyway.

It is my understanding that the primary input queue is a sequence of
bytes from the terminal, that gets interpreted late (if at all) into
keys. This needs to become a queue of key events. Each key event would be
one of:

  struct { int modifiers; int codepoint };   /* for Unicode input */
  struct { int modifiers; int functionkey }; /* for non-printing keys */
  (in both cases, "modifers" is a bitfield of CTRL, SHIFT, ALT, etc..)

This becomes trivial to fill from the GTK, Win32, MacOSX or other cases.
It also becomes easy to fill from the terminal, if for example, my own
"libtermkey" library is used to parse the terminal's input. This already
provides structs of that form.

The advantages here in the non-terminal cases easily present themselves -
we can now easily tell apart all of cases A, B, and C above.

The fix in the terminals themselves involves changes to the sequences
used to express various concepts. Maintaining as much backward compat. as
possible, function keys in xterm et.al. already use the form

  CSI function;modifiers ~

For example, CSI 12;5~ as Ctrl-F2.

This scheme can extend into trivially to the "private use area" of CSIs,
where we define 'u' to mean a modified Unicode point:

  CSI codepoint;modifiers u

This now stands for any modified keystroke that isn't a function key
(i.e. sends normal Unicode data when unmodified). To reuse the examples
above:

  Ctrl-Shift-L  =>  CSI 76;5u    (Codepoint 76 being Capital L, and the
      Ctrl modifier. The fact that Shift is used to obtain the capital L
      is unimportant. Compare to e.g. Ctrl-$ or other symbols that need
      to be shifted on most keyboard layouts)

We could, if we wanted to break everything, define that:

  Ctrl-L        =>  CSI 108;5u

but it's likely no program yet would understand that. Plus, most kernel's
tty input layers like only one byte for things like EOF (Ctrl-D), so it's
probably best to leave those as they were

  Ctrl-L        => 0x0c

Now we can distinguish all three cases of B:

  é             => 0xc3 0xa9
  Alt+C Alt+)   => CSI 67;3u CSI 41;3u
  Esc C Esc )   => ESC C ESC )

We have to stick to the 8bit encoding of CSI in order that this be
unambiguous, but if we do that, we find that all three cases have unique
byte sequences, and any case can be determined only by looking at the
bytes themselves, and not the timing that they arrived at.

We can aim at a partial solution - simply adding recognition into vim for
these new CSIs doesn't prevent older schemes from working. But it does
mean that given a new terminal using the right scheme, that suddenly vim
can recognise any keyboard input. Also, the upshot gained by having
proper representation in structs internally gives instant gains for the
GTK and other GUI cases, independent of any terminal work.

I would like to suggest that a full CSI parser be implemented (or just
use the one from my "libtermkey" library), as this is most
forward-compatible. Over the last 5 years or so I've witnessed much
breakage in any terminal program that doesn't do this (i.e. all of them)
when I press Ctrl-Left in my xterm; because the program didn't have a
full CSI parser, so gave up after CSI 1; rather than read the whole
sequence. It then was left with a raw 5D which it printed as normal
input. If a program had a full CSI parser, then it wouldn't have broken
here. It wouldn't understand the second 5 parameter, it would have just
seen a normal <Left> key press. I think that's a much more graceful
failure case than currently. 

It's also future-proof. If, in 10 years time when we all have
pressure-sensitive keys, I type enter or ENTER by hitting the keys
harder, and xterm sends

  CSI 13;1;1u   or   CSI 13;1;5u

then a program written today with a real CSI parser still notices those
both as Enter key presses, it just doesn't pick up on the extra pressure
information. But that's OK, because today we didn't know what to do with
that. Graceful failure.

I think Vim is a good place to start this fix from. Clearly someone has
to start - either the terminals sending, or the applications receiving.
Adding recogintion of new codes is easy and safe, as long as it doesn't
affect existing things, which I believe the above does, so it suggests
fixing applications first. Vim specifically is a nice place because of
its nice orthogonal :map command to bind keypresses to other things - it
can easily take full advantage of the keys now representable.

I've mentioned this problem on #vim on many occasions, and I've decided
now is the time to bring it to the attention of the mailing list, and see
if we can find a solution. As I mentioned on the channel, I would like to
offer a total of £300 by way of a "bug bounty" for a complete fix, or
parts thereof for stages that get us there.

Six conditions for a "fixed" solution are:
  1: With proper terminal input, can distinguish <C-L> from <C-S-L>
  2: With proper terminal input, can distinguish <C-I> from <Tab>
  3: With proper terminal input, can distinguish UTF-8 from Alt+letter
     from Esc letter
  4: Does not use timing information, can work solely from one atomic
     read() call
  5: Improvements also visible from GTK or other frontends
  6: Improvements work in :map and similar commands

Does this sound like something we can achieve?

-- 
Paul "LeoNerd" Evans

[EMAIL PROTECTED]
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/

Attachment: signature.asc
Description: PGP signature

Raspunde prin e-mail lui