diff options
Diffstat (limited to 'src/arch/x86/interface/pcbios/bios_console.c')
| -rw-r--r-- | src/arch/x86/interface/pcbios/bios_console.c | 71 |
1 files changed, 52 insertions, 19 deletions
diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 80ebf330e..0220c8564 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -60,6 +60,21 @@ 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 + +/** 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 @@ -340,28 +355,15 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { } /** - * Map a key - * - * @v character Character read from console - * @ret character Mapped character - */ -static int bios_keymap ( unsigned int character ) { - struct key_mapping *mapping; - - for_each_table_entry ( mapping, KEYMAP ) { - if ( mapping->from == character ) - return mapping->to; - } - return character; -} - -/** * Get character from BIOS console * * @ret character Character read from console */ static int bios_getchar ( void ) { uint16_t keypress; + uint8_t kb0; + uint8_t kb2; + unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -383,11 +385,42 @@ static int bios_getchar ( void ) { : "=a" ( keypress ) : "a" ( 0x1000 ), "m" ( bios_inject_lock ) ); bios_inject_lock--; + scancode = ( keypress >> 8 ); character = ( keypress & 0xff ); + get_real ( kb0, BDA_SEG, BDA_KB0 ); + get_real ( kb2, BDA_SEG, BDA_KB2 ); + + /* If it's a normal character, map (if applicable) and return it */ + if ( character && ( character < 0x80 ) ) { + + /* Handle special scancodes */ + if ( scancode == SCANCODE_NON_US ) { + /* Treat as "\|" with high bit set */ + character |= KEYMAP_PSEUDO; + } else if ( scancode >= SCANCODE_RSHIFT ) { + /* Non-remappable scancode (e.g. numeric keypad) */ + return character; + } + + /* Apply modifiers */ + if ( kb0 & BDA_KB0_CTRL ) + character |= KEYMAP_CTRL; + if ( kb0 & BDA_KB0_CAPSLOCK ) + character |= KEYMAP_CAPSLOCK_REDO; + if ( kb2 & BDA_KB2_RALT ) + character |= KEYMAP_ALTGR; + + /* Treat LShift+RShift as AltGr since many BIOSes will + * not return ASCII characters when AltGr is pressed. + */ + if ( ( kb0 & ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) == + ( BDA_KB0_LSHIFT | BDA_KB0_RSHIFT ) ) { + character |= KEYMAP_ALTGR; + } - /* If it's a normal character, just map and return it */ - if ( character && ( character < 0x80 ) ) - return bios_keymap ( character ); + /* Map and return */ + return key_remap ( character ); + } /* Otherwise, check for a special key that we know about */ if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) { |
