[console] Avoid attempting to remap numeric keypad on BIOS console

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>
pull/576/head
Michael Brown 2022-02-09 16:06:11 +00:00
parent f51a62bc3f
commit fa708015e5
1 changed files with 18 additions and 3 deletions

View File

@ -60,6 +60,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#define ATTR_DEFAULT ATTR_FCOL_WHITE #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 */ /* Set default console usage if applicable */
#if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) ) #if ! ( defined ( CONSOLE_PCBIOS ) && CONSOLE_EXPLICIT ( CONSOLE_PCBIOS ) )
#undef CONSOLE_PCBIOS #undef CONSOLE_PCBIOS
@ -346,6 +354,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) {
*/ */
static int bios_getchar ( void ) { static int bios_getchar ( void ) {
uint16_t keypress; uint16_t keypress;
unsigned int scancode;
unsigned int character; unsigned int character;
const char *ansi_seq; const char *ansi_seq;
@ -367,11 +376,17 @@ static int bios_getchar ( void ) {
: "=a" ( keypress ) : "=a" ( keypress )
: "a" ( 0x1000 ), "m" ( bios_inject_lock ) ); : "a" ( 0x1000 ), "m" ( bios_inject_lock ) );
bios_inject_lock--; bios_inject_lock--;
scancode = ( keypress >> 8 );
character = ( keypress & 0xff ); character = ( keypress & 0xff );
/* If it's a normal character, just map and return it */ /* If it's a normal character, map (if applicable) and return it */
if ( character && ( character < 0x80 ) ) if ( character && ( character < 0x80 ) ) {
return key_remap ( character ); if ( scancode < SCANCODE_RSHIFT ) {
return key_remap ( character );
} else {
return character;
}
}
/* Otherwise, check for a special key that we know about */ /* Otherwise, check for a special key that we know about */
if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) { if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) {