Zbigniew Jędrzejewski-Szmek 62fe94
From f8958c3495edf6d1563a5309e84bd68931a46213 Mon Sep 17 00:00:00 2001
Zbigniew Jędrzejewski-Szmek 62fe94
From: David Herrmann <dh.herrmann@gmail.com>
Zbigniew Jędrzejewski-Szmek 62fe94
Date: Fri, 3 Oct 2014 12:50:41 +0200
Zbigniew Jędrzejewski-Szmek 62fe94
Subject: [PATCH] terminal/screen: add keyboard mapping
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Implement the feed_keyboard() handling by mapping XKB keys according to
Zbigniew Jędrzejewski-Szmek 62fe94
DEC-VT behavior.
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
Public information on terminal key-mappings is pretty scarce. We only
Zbigniew Jędrzejewski-Szmek 62fe94
implement the most basic mapping for now. Further improvements welcome!
Zbigniew Jędrzejewski-Szmek 62fe94
---
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/term-screen.c | 324 +++++++++++++++++++++++++++++++++-
Zbigniew Jędrzejewski-Szmek 62fe94
 src/libsystemd-terminal/term.h        |  22 ++-
Zbigniew Jędrzejewski-Szmek 62fe94
 2 files changed, 342 insertions(+), 4 deletions(-)
Zbigniew Jędrzejewski-Szmek 62fe94
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/term-screen.c b/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
index b442b96050..5b0562e4c3 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/term-screen.c
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -47,6 +47,7 @@
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <stdbool.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <stdint.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include <stdlib.h>
Zbigniew Jędrzejewski-Szmek 62fe94
+#include <xkbcommon/xkbcommon-keysyms.h>
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "macro.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "term-internal.h"
Zbigniew Jędrzejewski-Szmek 62fe94
 #include "util.h"
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -3784,12 +3785,329 @@ int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size) {
Zbigniew Jędrzejewski-Szmek 62fe94
         return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+static char *screen_map_key(term_screen *screen,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            char *p,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            const uint32_t *keysyms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            size_t n_syms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            uint32_t ascii,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            const uint32_t *ucs4,
Zbigniew Jędrzejewski-Szmek 62fe94
+                            unsigned int mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        char ch, ch2, ch_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+        uint32_t v;
Zbigniew Jędrzejewski-Szmek 62fe94
+        size_t i;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* TODO: All these key-mappings need to be verified. Public information
Zbigniew Jędrzejewski-Szmek 62fe94
+         * on those mappings is pretty scarce and every emulator seems to do it
Zbigniew Jędrzejewski-Szmek 62fe94
+         * slightly differently.
Zbigniew Jędrzejewski-Szmek 62fe94
+         * A lot of mappings are also missing. */
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (n_syms < 1)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (n_syms == 1)
Zbigniew Jędrzejewski-Szmek 62fe94
+                v = keysyms[0];
Zbigniew Jędrzejewski-Szmek 62fe94
+        else
Zbigniew Jędrzejewski-Szmek 62fe94
+                v = XKB_KEY_NoSymbol;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* In some mappings, the modifiers are encoded as CSI parameters. The
Zbigniew Jędrzejewski-Szmek 62fe94
+         * encoding is rather arbitrary, but seems to work. */
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch_mods = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (mods & (TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT | TERM_KBDMOD_CTRL)) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_SHIFT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_ALT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '3';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '4';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_CTRL:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '5';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '6';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_CTRL | TERM_KBDMOD_ALT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '7';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case TERM_KBDMOD_CTRL | TERM_KBDMOD_SHIFT | TERM_KBDMOD_ALT:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch_mods = '8';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* A user might actually use multiple layouts for keyboard
Zbigniew Jędrzejewski-Szmek 62fe94
+         * input. @keysyms[0] contains the actual keysym that the user
Zbigniew Jędrzejewski-Szmek 62fe94
+         * used. But if this keysym is not in the ascii range, the
Zbigniew Jędrzejewski-Szmek 62fe94
+         * input handler does check all other layouts that the user
Zbigniew Jędrzejewski-Szmek 62fe94
+         * specified whether one of them maps the key to some ASCII
Zbigniew Jędrzejewski-Szmek 62fe94
+         * keysym and provides this via @ascii. We always use the real
Zbigniew Jędrzejewski-Szmek 62fe94
+         * keysym except when handling CTRL+<XY> shortcuts we use the
Zbigniew Jędrzejewski-Szmek 62fe94
+         * ascii keysym. This is for compatibility to xterm et. al. so
Zbigniew Jędrzejewski-Szmek 62fe94
+         * ctrl+c always works regardless of the currently active
Zbigniew Jędrzejewski-Szmek 62fe94
+         * keyboard layout. But if no ascii-sym is found, we still use
Zbigniew Jędrzejewski-Szmek 62fe94
+         * the real keysym. */
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ascii == XKB_KEY_NoSymbol)
Zbigniew Jędrzejewski-Szmek 62fe94
+                ascii = v;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map CTRL+<ascii> */
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (mods & TERM_KBDMOD_CTRL) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                switch (ascii) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                case 0x60 ... 0x7e:
Zbigniew Jędrzejewski-Szmek 62fe94
+                        /* Right hand side is mapped to the left and then
Zbigniew Jędrzejewski-Szmek 62fe94
+                         * treated equally. Fall through to left-hand side.. */
Zbigniew Jędrzejewski-Szmek 62fe94
+                        ascii -= 0x20;
Zbigniew Jędrzejewski-Szmek 62fe94
+                case 0x20 ... 0x5f:
Zbigniew Jędrzejewski-Szmek 62fe94
+                        /* Printable ASCII is mapped 1-1 in XKB and in
Zbigniew Jędrzejewski-Szmek 62fe94
+                         * combination with CTRL bit 7 is flipped. This
Zbigniew Jędrzejewski-Szmek 62fe94
+                         * is equivalent to the caret-notation. */
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ascii ^ 0x40;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map cursor keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (v) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Up:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'A';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Down:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'B';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Right:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'C';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Left:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'D';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Home:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'H';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_End:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'F';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ch) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (screen->flags & TERM_FLAG_CURSOR_KEYS)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = 'O';
Zbigniew Jędrzejewski-Szmek 62fe94
+                else
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = '[';
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (ch_mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ';';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = ch;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map action keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (v) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Find:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Insert:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Delete:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '3';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Select:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '4';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Page_Up:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '5';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Page_Down:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '6';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ch) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = '[';
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = ch;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (ch_mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ';';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = '~';
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map lower function keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (v) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F1:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'P';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F2:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'Q';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F3:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'R';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F4:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = 'S';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ch) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (ch_mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = '[';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ';';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch;
Zbigniew Jędrzejewski-Szmek 62fe94
+                } else {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = 'O';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map upper function keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        ch2 = 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (v) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F5:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '5';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F6:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '7';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F7:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '8';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F8:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '9';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F9:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '0';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F10:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '1';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F11:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_F12:
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch = '2';
Zbigniew Jędrzejewski-Szmek 62fe94
+                ch2 = '3';
Zbigniew Jędrzejewski-Szmek 62fe94
+                break;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (ch) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = '[';
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = ch;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (ch2)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch2;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (ch_mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ';';
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = ch_mods;
Zbigniew Jędrzejewski-Szmek 62fe94
+                }
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = '~';
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map special keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        switch (v) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff08: /* XKB_KEY_BackSpace */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff09: /* XKB_KEY_Tab */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff0a: /* XKB_KEY_Linefeed */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff0b: /* XKB_KEY_Clear */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff15: /* XKB_KEY_Sys_Req */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff1b: /* XKB_KEY_Escape */
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xffff: /* XKB_KEY_Delete */
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = v - 0xff00;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff13: /* XKB_KEY_Pause */
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* TODO: What should we do with this key?
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * Sending XOFF is awful as there is no simple
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * way on modern keyboards to send XON again.
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * If someone wants this, we can re-eanble
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * optionally. */
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case 0xff14: /* XKB_KEY_Scroll_Lock */
Zbigniew Jędrzejewski-Szmek 62fe94
+                /* TODO: What should we do on scroll-lock?
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * Sending 0x14 is what the specs say but it is
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * not used today the way most users would
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * expect so we disable it. If someone wants
Zbigniew Jędrzejewski-Szmek 62fe94
+                 * this, we can re-enable it (optionally). */
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_Return:
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = 0x0d;
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (screen->flags & TERM_FLAG_NEWLINE_MODE)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *p++ = 0x0a;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        case XKB_KEY_ISO_Left_Tab:
Zbigniew Jędrzejewski-Szmek 62fe94
+                *p++ = 0x09;
Zbigniew Jędrzejewski-Szmek 62fe94
+                return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* map unicode keys */
Zbigniew Jędrzejewski-Szmek 62fe94
+        for (i = 0; i < n_syms; ++i)
Zbigniew Jędrzejewski-Szmek 62fe94
+                p += term_utf8_encode(p, ucs4[i]);
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return p;
Zbigniew Jędrzejewski-Szmek 62fe94
+}
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+int term_screen_feed_keyboard(term_screen *screen,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              const uint32_t *keysyms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              size_t n_syms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              uint32_t ascii,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              const uint32_t *ucs4,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              unsigned int mods) {
Zbigniew Jędrzejewski-Szmek 62fe94
+        _cleanup_free_ char *dyn = NULL;
Zbigniew Jędrzejewski-Szmek 62fe94
+        static const size_t padding = 1;
Zbigniew Jędrzejewski-Szmek 62fe94
+        char buf[128], *start, *p = buf;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
         assert_return(screen, -EINVAL);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        /* TODO */
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* allocate buffer if too small */
Zbigniew Jędrzejewski-Szmek 62fe94
+        start = buf;
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (4 * n_syms + padding > sizeof(buf)) {
Zbigniew Jędrzejewski-Szmek 62fe94
+                dyn = malloc(4 * n_syms + padding);
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (!dyn)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        return -ENOMEM;
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
-        return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+                start = dyn;
Zbigniew Jędrzejewski-Szmek 62fe94
+        }
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* reserve prefix space */
Zbigniew Jędrzejewski-Szmek 62fe94
+        start += padding;
Zbigniew Jędrzejewski-Szmek 62fe94
+        p = start;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        p = screen_map_key(screen, p, keysyms, n_syms, ascii, ucs4, mods);
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!p || p - start < 1)
Zbigniew Jędrzejewski-Szmek 62fe94
+                return 0;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* The ALT modifier causes ESC to be prepended to any key-stroke. We
Zbigniew Jędrzejewski-Szmek 62fe94
+         * already accounted for that buffer space above, so simply prepend it
Zbigniew Jędrzejewski-Szmek 62fe94
+         * here.
Zbigniew Jędrzejewski-Szmek 62fe94
+         * TODO: is altSendsEscape a suitable default? What are the semantics
Zbigniew Jędrzejewski-Szmek 62fe94
+         * exactly? Is it used in C0/C1 conversion? Is it prepended if there
Zbigniew Jędrzejewski-Szmek 62fe94
+         * already is an escape character? */
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (mods & TERM_KBDMOD_ALT && *start != 0x1b)
Zbigniew Jędrzejewski-Szmek 62fe94
+                *--start = 0x1b;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        /* turn C0 into C1 */
Zbigniew Jędrzejewski-Szmek 62fe94
+        if (!(screen->flags & TERM_FLAG_7BIT_MODE) && p - start >= 2)
Zbigniew Jędrzejewski-Szmek 62fe94
+                if (start[0] == 0x1b && start[1] >= 0x40 && start[1] <= 0x5f)
Zbigniew Jędrzejewski-Szmek 62fe94
+                        *++start ^= 0x40;
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        return screen_write(screen, start, p - start);
Zbigniew Jędrzejewski-Szmek 62fe94
 }
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 int term_screen_resize(term_screen *screen, unsigned int x, unsigned int y) {
Zbigniew Jędrzejewski-Szmek 62fe94
diff --git a/src/libsystemd-terminal/term.h b/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
index a3ca252e31..5228ce0601 100644
Zbigniew Jędrzejewski-Szmek 62fe94
--- a/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
+++ b/src/libsystemd-terminal/term.h
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -128,6 +128,21 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(term_parser*, term_parser_free);
Zbigniew Jędrzejewski-Szmek 62fe94
  * Screens
Zbigniew Jędrzejewski-Szmek 62fe94
  */
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
+enum {
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_IDX_SHIFT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_IDX_CTRL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_IDX_ALT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_IDX_LINUX,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_CNT,
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_SHIFT               = 1 << TERM_KBDMOD_IDX_SHIFT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_CTRL                = 1 << TERM_KBDMOD_IDX_CTRL,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_ALT                 = 1 << TERM_KBDMOD_IDX_ALT,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_LINUX               = 1 << TERM_KBDMOD_IDX_LINUX,
Zbigniew Jędrzejewski-Szmek 62fe94
+        TERM_KBDMOD_CAPS                = 1 << TERM_KBDMOD_IDX_CAPS,
Zbigniew Jędrzejewski-Szmek 62fe94
+};
Zbigniew Jędrzejewski-Szmek 62fe94
+
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef int (*term_screen_write_fn) (term_screen *screen, void *userdata, const void *buf, size_t size);
Zbigniew Jędrzejewski-Szmek 62fe94
 typedef int (*term_screen_cmd_fn) (term_screen *screen, void *userdata, unsigned int cmd, const term_seq *seq);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
@@ -141,7 +156,12 @@ unsigned int term_screen_get_width(term_screen *screen);
Zbigniew Jędrzejewski-Szmek 62fe94
 unsigned int term_screen_get_height(term_screen *screen);
Zbigniew Jędrzejewski-Szmek 62fe94
 
Zbigniew Jędrzejewski-Szmek 62fe94
 int term_screen_feed_text(term_screen *screen, const uint8_t *in, size_t size);
Zbigniew Jędrzejewski-Szmek 62fe94
-int term_screen_feed_keyboard(term_screen *screen, uint32_t keysym, uint32_t ascii, uint32_t ucs4, unsigned int mods);
Zbigniew Jędrzejewski-Szmek 62fe94
+int term_screen_feed_keyboard(term_screen *screen,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              const uint32_t *keysyms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              size_t n_syms,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              uint32_t ascii,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              const uint32_t *ucs4,
Zbigniew Jędrzejewski-Szmek 62fe94
+                              unsigned int mods);
Zbigniew Jędrzejewski-Szmek 62fe94
 int term_screen_resize(term_screen *screen, unsigned int width, unsigned int height);
Zbigniew Jędrzejewski-Szmek 62fe94
 void term_screen_soft_reset(term_screen *screen);
Zbigniew Jędrzejewski-Szmek 62fe94
 void term_screen_hard_reset(term_screen *screen);