]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[console] Avoid attempting to remap numeric keypad on BIOS console
authorMichael Brown <mcb30@ipxe.org>
Wed, 9 Feb 2022 16:06:11 +0000 (16:06 +0000)
committerMichael Brown <mcb30@ipxe.org>
Thu, 10 Feb 2022 13:11:27 +0000 (13:11 +0000)
To minimise code size, our keyboard mapping works on the basis of
allowing the BIOS to convert the keyboard scancode into an ASCII
character and then remapping the ASCII character.

This causes problems with keyboard layouts such as "fr" that swap the
shifted and unshifted digit keys, since the ASCII-based remapping will
spuriously remap the numeric keypad (which produces the same ASCII
values as the digit keys).

Fix by checking that the keyboard scancode is within the range of keys
that vary between keyboard mappings before attempting to remap the
ASCII character.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
src/arch/x86/interface/pcbios/bios_console.c

index 0692e7a6ca0cd18151680d5bf0b5df7177eb6193..443513e9e45cfab6beceb2b231dd1abcb952e6b5 100644 (file)
@@ -60,6 +60,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
 
 #define ATTR_DEFAULT           ATTR_FCOL_WHITE
 
+/** Maximum keycode subject to remapping
+ *
+ * This allows us to avoid remapping the numeric keypad, which is
+ * necessary for keyboard layouts such as "fr" that swap the shifted
+ * and unshifted digit keys.
+ */
+#define SCANCODE_RSHIFT                0x36
+
 /* Set default console usage if applicable */
 #if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
 #undef CONSOLE_PCBIOS
@@ -346,6 +354,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
  */
 static int bios_getchar ( void ) {
        uint16_t keypress;
+       unsigned int scancode;
        unsigned int character;
        const char *ansi_seq;
 
@@ -367,11 +376,17 @@ static int bios_getchar ( void ) {
                               : "=a" ( keypress )
                               : "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
        bios_inject_lock--;
+       scancode = ( keypress >> 8 );
        character = ( keypress & 0xff );
 
-       /* If it's a normal character, just map and return it */
-       if ( character && ( character < 0x80 ) )
-               return key_remap ( character );
+       /* If it's a normal character, map (if applicable) and return it */
+       if ( character && ( character < 0x80 ) ) {
+               if ( scancode < SCANCODE_RSHIFT ) {
+                       return key_remap ( character );
+               } else {
+                       return character;
+               }
+       }
 
        /* Otherwise, check for a special key that we know about */
        if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {