PuTTY wish portable-keyboard

Home | FAQ | Feedback | Licence | Updates | Mirrors | Keys | Links | Team
Download: Stable · Snapshot | Docs | Changes | Wishlist

summary: Shared keyboard handler across platforms
class: wish: This is a request for an enhancement.
difficulty: tricky: Needs many tuits.
blocks: key-mapping
priority: medium: This should be fixed one day.

At present, each port of PuTTY has a separate keyboard handler, which takes
keyboard events and converts them into bytes to be fed to the line discipline.
This is clearly silly, since much of the code is shared, but a sensible
abstraction is trickier than you might think.

I (BJH) can think of the following kinds of keypress that PuTTY has to be able
to handle.  Further suggestions welcome.

1a: Typewriter keys, possibly affected by Caps Lock, Shift, Alt Gr, or Option.
  These emit graphic characters in the current character set.  The graphic
  character in question should be whatever the user expects, which is usually
  determined by the OS.

1b: Typewriter keys with Control held down.  For keys which would usually
  generate ASCII characters without Control, it's usually clear which
  control character they should generate.  What about non-ASCII characters
  (or non-ASCII keyboards)?  In the Mac OS, Command-key shortcuts are
  always based on a Roman keyboard layout.  Should we do the same with
  Control?

1c: Typewriter keys handled through the "compose" mechanism.  These have to be
  converted to characters as if Compose were not held down, and then composed
  through a fixed table.

2: Function keys, including Tab, Esc, Backspace, F1-F12 and editing keys, but
  not the numeric keypad.  These emit escape sequences (sequences of _bytes_,
  not characters), with the precise sequence depending on terminal modes,
  configuration, keys held down etc.  While complex, I think this is all
  entirely platform- and keyboard-layout independent, and hence not scary.

3a: The numeric keypad in application mode.  In this mode, the keypad, including
  Num Lock, behaves as a set of function keys.

3b: The numeric keypad in normal mode, with Num Lock off.  In this mode, those
  keypad keys which can also be editing keys generate the same sequences as
  the editing keys themselves.  Other keys are, I think, processed as with
  Num Lock on below.

3c: The numeric keypad in normal mode, with Num Lock on.  In this mode, the
  keypad behaves as typewriter keys.

3d: The numeric keypad with Alt held down.  This accumulates a numeric character
  code (line charset) in decimal which is sent when Alt goes up.

* All the above, with Meta held down.  This should send the same sequence as
  without Meta down, but preceded by ESC.

* Keys which cause PuTTY to do things but which aren't sent to the host. 
  Some of these (e.g. Shift+Page Up) are platform-independent, and can
  be treated as function keys.  Others (e.g. Alt+Space) are better handled
  in platform-dependent code.

* Keys which should be handled by the OS.  I don't think the platform-
  independent keyboard handler should see these at all.

Now for some proposals:

We define a list of modifiers, provisionally including:
PKM_SHIFT
PKM_CONTROL
PKM_META
PKM_ALT
PKM_CAPSLOCK
PKM_NUMLOCK

Note that the Alt key (used for Alt+keypad) and the Meta key (used for
Meta+typewriter) may or may not have distinct physical keys.  The PI code
should ignore Meta on the keypad and Alt everywhere else.

[ But what if I want to type Meta+Alt+123 on a system with separate Alt and
  Meta keys?  Is that so wrong? ]

We define a list of keysyms for function keys, with a null keysym:
PK_NULL
PK_F1
PK_RETURN
PK_UP
PK_PF1
...

We define a function to be called by the platform keyboard handler when
something happens:

process_key(keysym, chars, modifiers)

keysym can be PK_NULL if there's no keysym for the current key.
chars (a UCS-2 string) can be empty if the platform doesn't have a translation
for the current key.
If both keysym is PK_NULL and chars is empty, the platform is just reporting
a change of modifier state (for Alt+keypad).

In the examples that follow, assume that what look like C strings are really
UCS-2.

Now for the specifics:
Case 1a is easy:
    process_key(PK_NULL, "A", PKM_SHIFT);
  NB that all modifiers are reported, but SHIFT and CAPSLOCK are assumed to
  have been dealt with already.
Case 1b is interesting.  On some platforms, the native keyboard handler
  understands Control, so we can do:
    process_key(PK_NULL, "\001", PKM_CONTROL);
  On the other hand, we might find that we need some extra ones, so
  process_key would have to handle:
    process_key(PK_NULL, "`", PKM_CONTROL);
  I can't see any obvious problem with allowing both.
Case 1c is a combination of 2 and 1a:
    process_key(PK_COMPOSE, "", 0);
    process_key(PK_NULL, "e", 0);
    process_key(PK_NULL, "'", 0);
  Composition can then be handled in the PI code.
Case 2 is trivial:
    process_key(PK_F1, "", 0);
    process_key(PK_TAB, "", PK_SHIFT);
Case 3a-3d are mostly identical in the platform code:
    process_key(PK_PF2, "/", 0);
    process_key(PK_KPDECIMAL, ",", PKM_NUMLOCK); /* German kbd */
But Num Lock is a pain -- I think I'd habe the platform code check the
  application-keypad state and damn the layering violation:
    process_key(PK_NULL, "", PKM_NUMLOCK);
    process_key(PK_PF1, "", 0);
If the Meta key is down, the platform code is expected to subtract it out of
  the characters sent if it did anything:
    process_key(PK_NULL, "a", PKM_META);

(Update: this idea appeared in the code in the form of term_key() in
terminal.c in r2728; however it was never adopted in any of the
mainstream ports, so was finally removed again in r9579.)
Audit trail for this wish.


If you want to comment on this web site, see the Feedback page.
(last revision of this bug record was at 2013-08-06 22:56:44 +0000)