]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[console] Handle remapping of scancode 86
authorMichael Brown <mcb30@ipxe.org>
Wed, 9 Feb 2022 15:43:42 +0000 (15:43 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 10 Feb 2022 13:59:32 +0000 (13:59 +0000)
The key with scancode 86 appears in the position between left shift
and Z on a US keyboard, where it typically fails to exist entirely.
Most US keyboard maps define this nonexistent key as generating "\|",
with the notable exception of "loadkeys" which instead reports it as
generating "<>".  Both of these mapping choices duplicate keys that
exist elsewhere in the map, which causes problems for our ASCII-based
remapping mechanism.

Work around these quirks by treating the key as generating "\|" with
the high bit set, and making it subject to remapping.  Where the BIOS
generates "\|" as expected, this allows us to remap to the correct
ASCII value.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
28 files changed:
src/arch/x86/interface/pcbios/bios_console.c
src/core/keymap.c
src/drivers/usb/usbkbd.c
src/drivers/usb/usbkbd.h
src/hci/keymap/keymap_al.c
src/hci/keymap/keymap_az.c
src/hci/keymap/keymap_by.c
src/hci/keymap/keymap_de.c
src/hci/keymap/keymap_dk.c
src/hci/keymap/keymap_es.c
src/hci/keymap/keymap_et.c
src/hci/keymap/keymap_fi.c
src/hci/keymap/keymap_fr.c
src/hci/keymap/keymap_gr.c
src/hci/keymap/keymap_il.c
src/hci/keymap/keymap_it.c
src/hci/keymap/keymap_mk.c
src/hci/keymap/keymap_nl.c
src/hci/keymap/keymap_no-latin1.c
src/hci/keymap/keymap_no.c
src/hci/keymap/keymap_pl.c
src/hci/keymap/keymap_pt.c
src/hci/keymap/keymap_ru.c
src/hci/keymap/keymap_sg.c
src/hci/keymap/keymap_sr-latin.c
src/hci/keymap/keymap_ua.c
src/include/ipxe/keymap.h
src/util/genkeymap.py

index 443513e9e45cfab6beceb2b231dd1abcb952e6b5..438a01d0718bf863eb4e3cacba8f62769b97c0e2 100644 (file)
@@ -68,6 +68,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  */
 #define SCANCODE_RSHIFT                0x36
 
+/** Scancode for the "non-US \ and |" key
+ *
+ * This is the key that appears between Left Shift and Z on non-US
+ * keyboards.
+ */
+#define SCANCODE_NON_US                0x56
+
 /* Set default console usage if applicable */
 #if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
 #undef CONSOLE_PCBIOS
@@ -383,6 +390,8 @@ static int bios_getchar ( void ) {
        if ( character && ( character < 0x80 ) ) {
                if ( scancode < SCANCODE_RSHIFT ) {
                        return key_remap ( character );
+               } else if ( scancode == SCANCODE_NON_US ) {
+                       return key_remap ( character | KEYMAP_PSEUDO );
                } else {
                        return character;
                }
index a6707a2ce0bf73a98ed599d425a37f3180876b7e..5054e4769132b32b5f0a252c0f4f5e0552ef809e 100644 (file)
@@ -48,5 +48,8 @@ unsigned int key_remap ( unsigned int character ) {
                }
        }
 
+       /* Clear pseudo key flag */
+       character &= ~KEYMAP_PSEUDO;
+
        return character;
 }
index ba4b2d4d7a3bcd136348f52072220ca85cf34ea5..6954cd69bc2e869108ef07d1e681f82722462a7c 100644 (file)
@@ -114,13 +114,19 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers,
                        };
                        key = keypad[ keycode - USBKBD_KEY_PAD_1 ];
                };
+       } else if ( keycode == USBKBD_KEY_NON_US ) {
+               /* Non-US \ and | */
+               key = ( ( modifiers & USBKBD_SHIFT ) ?
+                       ( KEYMAP_PSEUDO | '|' ) : ( KEYMAP_PSEUDO | '\\' ) );
        } else {
                key = 0;
        }
 
        /* Remap key if applicable */
-       if ( keycode < USBKBD_KEY_CAPS_LOCK )
+       if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) ||
+            ( keycode == USBKBD_KEY_NON_US ) ) {
                key = key_remap ( key );
+       }
 
        /* Handle upper/lower case and Ctrl-<key> */
        if ( islower ( key ) ) {
index cedebfe7131368effd00e78bd5ed9b403a6c784a..1a3fea1ba021e2e1c4874052009e333c4033c9b5 100644 (file)
@@ -75,6 +75,7 @@ enum usb_keycode {
        USBKBD_KEY_PAD_ENTER = 0x58,
        USBKBD_KEY_PAD_1 = 0x59,
        USBKBD_KEY_PAD_DOT = 0x63,
+       USBKBD_KEY_NON_US = 0x64,
 };
 
 /** USB keyboard LEDs */
index e4418361b03219946afdd4188808d1946ea17fad..6b4663489cc1c7f273684536a0d8a8d3c57a544b 100644 (file)
@@ -30,4 +30,6 @@ struct key_mapping al_mapping[] __keymap = {
        { 0x7c, 0x7d }, /* '|' => '}' */
        { 0x7d, 0x27 }, /* '}' => '\'' */
        { 0x7e, 0x7c }, /* '~' => '|' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 525ab233614e11e8ad09ed173ba33a7073f8c618..91a24346075c9241f95d223ba837cf04daad4f29 100644 (file)
@@ -21,4 +21,6 @@ struct key_mapping az_mapping[] __keymap = {
        { 0x40, 0x22 }, /* '@' => '"' */
        { 0x5e, 0x3a }, /* '^' => ':' */
        { 0x7c, 0x2f }, /* '|' => '/' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 514d0b5327894000997e4ff8408f89a5cd024bc3..43fb746bffe4f8929f3648c1d8a5692e66a297ab 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "by" keyboard mapping */
 struct key_mapping by_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 2559e1538127bc57de3ecdb2c9b3994f6bff9dde..85574d487db499e35ef741b5095aaa055705368f 100644 (file)
@@ -36,4 +36,6 @@ struct key_mapping de_mapping[] __keymap = {
        { 0x7a, 0x79 }, /* 'z' => 'y' */
        { 0x7c, 0x27 }, /* '|' => '\'' */
        { 0x7d, 0x2a }, /* '}' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 05110dc898b5b4faded237ebce40e56c0cad547b..4e1d5a7392dc383b4dcab029053362f4b8da9d1e 100644 (file)
@@ -28,4 +28,6 @@ struct key_mapping dk_mapping[] __keymap = {
        { 0x5e, 0x26 }, /* '^' => '&' */
        { 0x5f, 0x3f }, /* '_' => '?' */
        { 0x7c, 0x2a }, /* '|' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 51dedfff78459aba1e54eccb0d1315b8d5b50a54..91327ea513a95d4fc282d2606f614ef921164bc5 100644 (file)
@@ -28,4 +28,6 @@ struct key_mapping es_mapping[] __keymap = {
        { 0x5e, 0x26 }, /* '^' => '&' */
        { 0x5f, 0x3f }, /* '_' => '?' */
        { 0x7d, 0x2a }, /* '}' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index dd0f879b1f64c493275828d44663755ea649cf5d..493ec93d4b4754bd5c0f464606c62942e8588c97 100644 (file)
@@ -26,4 +26,6 @@ struct key_mapping et_mapping[] __keymap = {
        { 0x5e, 0x26 }, /* '^' => '&' */
        { 0x5f, 0x3f }, /* '_' => '?' */
        { 0x7c, 0x2a }, /* '|' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index c489bf0e59ed7895dacffef1d195509f312e6690..18f48d47e7605dc5ac96bcb8bb8ead0510274267 100644 (file)
@@ -26,4 +26,6 @@ struct key_mapping fi_mapping[] __keymap = {
        { 0x5e, 0x26 }, /* '^' => '&' */
        { 0x5f, 0x3f }, /* '_' => '?' */
        { 0x7c, 0x2a }, /* '|' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 8f3b4999d49b5c96d5b68d63a56cc86c02e31384..808cd7945b49c80aa59c36470d091c393fb3f8d2 100644 (file)
@@ -57,4 +57,6 @@ struct key_mapping fr_mapping[] __keymap = {
        { 0x71, 0x61 }, /* 'q' => 'a' */
        { 0x77, 0x7a }, /* 'w' => 'z' */
        { 0x7a, 0x77 }, /* 'z' => 'w' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 42b6418e8f0aa2732e70f33a19cf2c60065f640b..b48142e5e0ca9a73c68ea31b7dc11471c5014af0 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "gr" keyboard mapping */
 struct key_mapping gr_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index f631f7ac96ef279fb7fa3ebad1dbbca8a39360b1..78e7fa970ab27fae9ef0ae82c0712e943d364f96 100644 (file)
@@ -24,4 +24,6 @@ struct key_mapping il_mapping[] __keymap = {
        { 0x60, 0x3b }, /* '`' => ';' */
        { 0x7b, 0x7d }, /* '{' => '}' */
        { 0x7d, 0x7b }, /* '}' => '{' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index d96102c9e0eb0dfb464ae3f2d387e6b971aea20b..5a8e2b38d90d10201513c879a4b7d56c75f94a6a 100644 (file)
@@ -30,4 +30,6 @@ struct key_mapping it_mapping[] __keymap = {
        { 0x60, 0x5c }, /* '`' => '\\' */
        { 0x7d, 0x2a }, /* '}' => '*' */
        { 0x7e, 0x7c }, /* '~' => '|' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 8f5060778e9f382850e0027911c4835b574da316..9f2cff78bf48d2b5c6c369a21131f473544fbc7b 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "mk" keyboard mapping */
 struct key_mapping mk_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 2a0fbbcbd78567fca4cac8192d1e762099ec02fb..d248fc8aeb58c56f3fa1a2c86f13619b5b0ce61e 100644 (file)
@@ -33,4 +33,6 @@ struct key_mapping nl_mapping[] __keymap = {
        { 0x60, 0x40 }, /* '`' => '@' */
        { 0x7c, 0x3e }, /* '|' => '>' */
        { 0x7d, 0x7c }, /* '}' => '|' */
+       { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */
+       { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */
 };
index 655e4cef7cf63267381e8724c56622bed78183cc..d5a721a909db4e68f3b18f874c3a952b6a73ebea 100644 (file)
@@ -32,4 +32,6 @@ struct key_mapping no_latin1_mapping[] __keymap = {
        { 0x60, 0x7c }, /* '`' => '|' */
        { 0x7c, 0x2a }, /* '|' => '*' */
        { 0x7d, 0x5e }, /* '}' => '^' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 7a2df7c5af7e0357fb1d64584c590aac22d2aad9..b6190da4a725c6ac35aceac8fe15232952feb7da 100644 (file)
@@ -30,4 +30,6 @@ struct key_mapping no_mapping[] __keymap = {
        { 0x5f, 0x3f }, /* '_' => '?' */
        { 0x60, 0x7c }, /* '`' => '|' */
        { 0x7c, 0x2a }, /* '|' => '*' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 51822e0724dfe195aba5b487d57c87c05f9aa6da..224fbde28f3e646a9445d90b71d595f13f17832b 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "pl" keyboard mapping */
 struct key_mapping pl_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index b993902af1dc201d16f0ecbd370911086643bb76..6d850fee8c28c859def7684379c2d035705d5ef6 100644 (file)
@@ -29,4 +29,6 @@ struct key_mapping pt_mapping[] __keymap = {
        { 0x60, 0x5c }, /* '`' => '\\' */
        { 0x7b, 0x2a }, /* '{' => '*' */
        { 0x7e, 0x7c }, /* '~' => '|' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index c120ffd820178989a1315a3d9afd9742c506c612..f7611c30a888a4d64d15ad9a593e123f97a5060f 100644 (file)
@@ -13,4 +13,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 /** "ru" keyboard mapping */
 struct key_mapping ru_mapping[] __keymap = {
        { 0x0d, 0x0a }, /* Ctrl-M => Ctrl-J */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 0b082092936feb595fdbefac70d9b042d7dc86fd..9a515c745e201153d0113d4adbbb57a41d7dd92e 100644 (file)
@@ -38,4 +38,6 @@ struct key_mapping sg_mapping[] __keymap = {
        { 0x7a, 0x79 }, /* 'z' => 'y' */
        { 0x7c, 0x24 }, /* '|' => '$' */
        { 0x7d, 0x21 }, /* '}' => '!' */
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 9d76e8a6c6bc8600e31a26a707a49ff34ab6e75b..1d4588733f87326edd32a867642ce680f99cea84 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "sr-latin" keyboard mapping */
 struct key_mapping sr_latin_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 1106a8b28b15e23976959fef1c38dcfe164891a3..50f2e184d66520c0c444efa4347f0fc1c053d454 100644 (file)
@@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN );
 
 /** "ua" keyboard mapping */
 struct key_mapping ua_mapping[] __keymap = {
+       { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+       { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
 };
index 62b3bb13120b21718a7d59c1a91bbc18788b663b..93c9e7314987ae48d1074d9667bb0574bf249506 100644 (file)
@@ -27,6 +27,9 @@ struct key_mapping {
 /** Define a keyboard mapping */
 #define __keymap __table_entry ( KEYMAP, 01 )
 
+/** Pseudo key flag */
+#define KEYMAP_PSEUDO 0x80
+
 extern unsigned int key_remap ( unsigned int character );
 
 #endif /* _IPXE_KEYMAP_H */
index 1bb494f832fdac5251cfb8df9d8356e67327bc01..081e314ccaaf1f8814c75009423cccf31beac234 100755 (executable)
@@ -219,12 +219,28 @@ class KeyMapping(UserDict[KeyModifiers, Sequence[Key]]):
 
 
 class BiosKeyMapping(KeyMapping):
-    """Keyboard mapping as used by the BIOS"""
+    """Keyboard mapping as used by the BIOS
+
+    To allow for remappings of the somewhat interesting key 86, we
+    arrange for our keyboard drivers to generate this key as "\\|"
+    with the high bit set.
+    """
+
+    KEY_PSEUDO: ClassVar[int] = 0x80
+    """Flag used to indicate a fake ASCII value"""
+
+    KEY_NON_US_UNSHIFTED: ClassVar[str] = chr(KEY_PSEUDO | ord('\\'))
+    """Fake ASCII value generated for unshifted key code 86"""
+
+    KEY_NON_US_SHIFTED: ClassVar[str] = chr(KEY_PSEUDO | ord('|'))
+    """Fake ASCII value generated for shifted key code 86"""
 
     @property
     def inverse(self) -> MutableMapping[str, Key]:
         inverse = super().inverse
         assert len(inverse) == 0x7f
+        inverse[self.KEY_NON_US_UNSHIFTED] = self.unshifted[self.KEY_NON_US]
+        inverse[self.KEY_NON_US_SHIFTED] = self.shifted[self.KEY_NON_US]
         assert all(x.modifiers in {KeyModifiers.NONE, KeyModifiers.SHIFT,
                                    KeyModifiers.CTRL}
                    for x in inverse.values())
@@ -251,12 +267,13 @@ class KeyRemapping:
         raw = {source: self.target[key.modifiers][key.keycode].ascii
                for source, key in self.source.inverse.items()}
         # Eliminate any null mappings, mappings that attempt to remap
-        # the backspace key, or identity mappings
+        # the backspace key, or mappings that would become identity
+        # mappings after clearing the high bit
         table = {source: target for source, target in raw.items()
                  if target
                  and ord(source) != 0x7f
                  and ord(target) != 0x7f
-                 and ord(source) != ord(target)}
+                 and ord(source) & ~BiosKeyMapping.KEY_PSEUDO != ord(target)}
         # Recursively delete any mappings that would produce
         # unreachable alphanumerics (e.g. the "il" keymap, which maps
         # away the whole lower-case alphabet)
@@ -281,13 +298,17 @@ class KeyRemapping:
         """C variable name"""
         return re.sub(r'\W', '_', self.name) + "_mapping"
 
-    @staticmethod
-    def ascii_name(char: str) -> str:
+    @classmethod
+    def ascii_name(cls, char: str) -> str:
         """ASCII character name"""
         if char == '\\':
             name = "'\\\\'"
         elif char == '\'':
             name = "'\\\''"
+        elif ord(char) & BiosKeyMapping.KEY_PSEUDO:
+            name = "Pseudo-%s" % cls.ascii_name(
+                chr(ord(char) & ~BiosKeyMapping.KEY_PSEUDO)
+            )
         elif char.isprintable():
             name = "'%s'" % char
         elif ord(char) <= 0x1a: