From: Reinis Danne <rei4dan@gmail.com> To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>, Jiri Slaby <jslaby@suse.com>, linux-kernel@vger.kernel.org, linux-input@vger.kernel.org, kbd@lists.altlinux.org Subject: [kbd] [RFC] tty: kb_value with flags for better Unicode support Date: Fri, 26 Apr 2019 13:52:24 +0300 Message-ID: <20190426105224.GB11020@rd-oc> (raw) Compliment already existing kbdiacruc and kbdiacrsuc structs and KD[GS]KBDIACRUC ioctls with Unicode equivalents for kb_value, kbentry and KD[GS]KBENT ioctls. ``` struct kb_valueuc { __u32 flags; /* 15 used by KTYP */ __u32 kb_valueuc; /* Unicode range: 0x0–0x10ffff */ }; struct kbentryuc { __u32 kb_table; __u32 kb_index; struct kb_valueuc; }; extern kb_valueuc *key_maps[MAX_NR_KEYMAPS]; #define KDGKBENTUC 0x???? /* get one entry in translation table */ #define KDSKBENTUC 0x???? /* set one entry in translation table */ ``` Motivation ========== Since I learned touchtyping, I want to have the same keyboard layout in VT as I have in X. So I wrote a keymap file for Latvian (modern) keyboard layout [1] to use with the kbd package and it works, mostly. I have three issues: - Compose sequences with base above Latin-1 not working (fixed). - CapsLock not working as expected for characters above Latin-1. - Can't use Meta key with characters above Latin-1. There are three letters above 0xff on level 1 of this keyboard layout: ē — U+0113 Dec:275 LATIN SMALL LETTER E WITH MACRON ā — U+0101 Dec:257 LATIN SMALL LETTER A WITH MACRON ī — U+012B Dec:299 LATIN SMALL LETTER I WITH MACRON Compose ======= I have added some extra letters in the free places to be able to type not only Latvian and English, but also German and Finnish (e.g., there is letter ö on level 3 of ē key) for the rare occasions I need them. This keyboard layout uses a dead key (dead_acute) to access level 3 symbols (the same as AltGr): compose diacr base to result compose '\'' U+0113 to U+00F6 But it didn't work if the base in the compose sequence was above 0xff (patch [2] is in tty-next). Key value and flags =================== The other two issues could be attributed to the lack of proper flags for key values (key type is encoded in its value). According to keymaps manual: ``` Each keysym may be prefixed by a '+' (plus sign), in wich case this keysym is treated as a "letter" and therefore affected by the "CapsLock" the same way as by "Shift" (to be correct, the CapsLock inverts the Shift state). The ASCII letters ('a'-'z' and 'A'-'Z') are made CapsLock'able by default. If Shift+CapsLock should not produce a lower case symbol, put lines like keycode 30 = +a A in the map file. ``` But it doesn't work — CapsLock is ignored for codepoints above 0xff. Adding plus signs to all four maps should make them behave the same way (like in X): # 0 1 2 3 # Plain Shift AltGr AltGr+Shift keycode 16 = +U+0113 +U+0112 +U+00F6 +U+00D6 | X VT --------------------------+--------------- CapsLock ē | Ē ē CapsLock+Shift ē | ē Ē CapsLock+AltGr ē | Ö Ö CapsLock+Shift+AltGr ē | ö ö For the key to behave properly, its key type (KTYP) has to be 'letter': include/uapi/linux/keyboard.h: #define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ Thus it is necessary to set KTYP for characters beyond Latin-1; which is not possible now. Currently they are defined like this: ``` include/linux/keyboard.h: extern unsigned short *key_maps[MAX_NR_KEYMAPS]; drivers/tty/vt/defkeymap.c_shipped: ushort *key_maps[MAX_NR_KEYMAPS] = { plain_map, shift_map, altgr_map, NULL, ctrl_map, shift_ctrl_map, NULL, NULL, alt_map, NULL, NULL, NULL, ctrl_alt_map, NULL }; include/uapi/linux/kd.h: struct kbentry { unsigned char kb_table; unsigned char kb_index; unsigned short kb_value; <-- Important! }; #define KDGKBENT 0x4B46 /* gets one entry in translation table */ #define KDSKBENT 0x4B47 /* sets one entry in translation table */ include/linux/kbd_kern.h: #define U(x) ((x) ^ 0xf000) #define BRL_UC_ROW 0x2800 include/uapi/linux/keyboard.h: #define K(t,v) (((t)<<8)|(v)) #define KTYP(x) ((x) >> 8) #define KVAL(x) ((x) & 0xff) ``` The use of ``unsigned short kb_value`` in ``struct kbentry`` prevents setting KTYP for Unicode characters beyond Latin-1 since there are only two bytes in an ``unsigned short`` and KTYP needs one, not leaving enough space for code points beyond 0xff. This breaks CapsLock for keyboard layouts with characters above Latin-1 [3–6]. I think those bugs are closed by mistake, since, to this day, it doesn't work. And it can't work because of the aforementioned kernel limitations (at least as far as CapsLock issue in Unicode mode is concerned). To illustrate, keysym is 16 bits long: mmmm tttt nnnn nnnn m — mask for (non-)Unicode characters (U macro) t — KTYP n — KVAL This also limits the number of Unicode characters — from 0xf000 the mask is lost. (No Klingon input in VT [not that I want one]. I think Documentation/admin-guide/unicode.rst talks only about the output. Or am I missing something?) See vt_do_kdsk_ioctl() and kbd_keycode() in drivers/tty/vt/keyboard.c for how the mask and U macro is used. As a side note: It seems CapsShift has never worked either. It was suggested as a workaround to this issue in one of the kernel bugs, but it obviously wouldn't work. First, CapsShift needs key map 256 and up (limited by MAX_NR_KEYMAPS). Second, in struct kbentry the kb_table index is unsigned char (0–255). So, even if one increased MAX_NR_KEYMAPS and recompiled the kernel, they still wouldn't be able to set the key map, because the ioctl can't index the table. Solution ======== A possible fix could be a proper, extensible struct with flags [7] for kb_value, used in the key_map[] and a pair of new ioctls (see the top of the mail). I think the increase in memory usage here is not something to worry about. That would change key_map[] from ushort to __u64. So instead of 2 bytes per keysym, it would use 8 bytes. The memory usage of keymaps would increase 4 times. Since there are 7 keymaps by default with 256 keys each, that would increase memory usage by: (8-2)*7*256=42*256=10752 B Each additional keymap would increase memory usage by: 8*256=2048 B Increasing the size of kb_table and kb_index might be useful in the future for adding multiple keyboard layout support to VT [8]. --- The increase of memory usage could be cut in half if ``__u32 flags`` is dropped and KTYP is put at the last byte of ``__u32 kb_valueuc``: #define K(t,v) (((t)<<24)|(v)) #define KTYP(x) ((x) >> 24) #define KVAL(x) ((x) & 0xffffff) But in this case the future-proofing for flags [7,9] would be lost. Also, there is possible conflict for programs built with old version of K macros running on newer kernels. The macros would have to be renamed. --- Affected users ============== KTYP or KVAL are used in (they would all have to be updated): - kernel/debug/kdb/kdb_keyboard.c - drivers/s390/char/keyboard.c - drivers/s390/char/tty3270.c - drivers/staging/speakup/main.c - drivers/tty/vt/keyboard.c - drivers/accessibility/braille/braille_console.c - arch/m68k/atari/atakeyb.c In addition to those, ``key_maps`` are used in: - drivers/s390/char/defkeymap.c - drivers/tty/vt/defkeymap.c_shipped - drivers/input/keyboard/amikbd.c - include/linux/keyboard.h - arch/m68k/amiga/config.c Also kbd package would have to be updated to take advantage of the change. Is anybody already working on this? Maybe somebody has done it a long time ago already, and I just have to do some magic incantations to make it work? Is it even worth doing? I'm new to kernel programming, comments from people with better insights are very much appreciated. -Reinis [1] https://odo.lv/xwiki/bin/download/Recipes/LatvianKeyboard/Modern.png [2] https://lkml.org/lkml/2019/4/11/362 [3] https://bugzilla.kernel.org/show_bug.cgi?id=7063 [4] https://bugzilla.kernel.org/show_bug.cgi?id=7746 [5] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=404503 [6] https://bugs.launchpad.net/ubuntu/+source/linux/+bug/16638 [7] https://blog.ffwll.ch/2013/11/botching-up-ioctls.html [8] https://www.happyassassin.net/2013/11/23/keyboard-layouts-in-fedora-20-and-previously/ [9] https://lwn.net/Articles/585415/
next reply other threads:[~2019-04-26 10:52 UTC|newest] Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top 2019-04-26 10:52 Reinis Danne [this message] 2019-05-08 10:24 ` Alexey Gladkov
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20190426105224.GB11020@rd-oc \ --to=rei4dan@gmail.com \ --cc=gregkh@linuxfoundation.org \ --cc=jslaby@suse.com \ --cc=kbd@lists.altlinux.org \ --cc=linux-input@vger.kernel.org \ --cc=linux-kernel@vger.kernel.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
Linux console tools development discussion This inbox may be cloned and mirrored by anyone: git clone --mirror http://lore.altlinux.org/kbd/0 kbd/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 kbd kbd/ http://lore.altlinux.org/kbd \ kbd@lists.altlinux.org kbd@lists.altlinux.ru kbd@lists.altlinux.com public-inbox-index kbd Example config snippet for mirrors. Newsgroup available over NNTP: nntp://lore.altlinux.org/org.altlinux.lists.kbd AGPL code for this site: git clone https://public-inbox.org/public-inbox.git