From f51a62bc3f7abb40e331c16df1f4d9314aefaf23 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Feb 2022 15:54:39 +0000 Subject: [console] Generalise bios_keymap() as key_remap() Allow the keyboard remapping functionality to be exposed to consoles other than the BIOS console. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/bios_console.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 80ebf330e..0692e7a6c 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -339,22 +339,6 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { return NULL; } -/** - * 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 * @@ -387,7 +371,7 @@ static int bios_getchar ( void ) { /* If it's a normal character, just map and return it */ if ( character && ( character < 0x80 ) ) - return bios_keymap ( character ); + return key_remap ( character ); /* Otherwise, check for a special key that we know about */ if ( ( ansi_seq = bios_ansi_seq ( keypress >> 8 ) ) ) { -- cgit v1.2.3-55-g7522 From fa708015e545a5877b1c07e2acf40f25b333c2cd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Feb 2022 16:06:11 +0000 Subject: [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 --- src/arch/x86/interface/pcbios/bios_console.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 0692e7a6c..443513e9e 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -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 ) ) ) { -- cgit v1.2.3-55-g7522 From 0bbd8967830097b9141945ba960e90339c230ccb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 9 Feb 2022 15:43:42 +0000 Subject: [console] Handle remapping of scancode 86 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 --- src/arch/x86/interface/pcbios/bios_console.c | 9 ++++++++ src/core/keymap.c | 3 +++ src/drivers/usb/usbkbd.c | 8 ++++++- src/drivers/usb/usbkbd.h | 1 + src/hci/keymap/keymap_al.c | 2 ++ src/hci/keymap/keymap_az.c | 2 ++ src/hci/keymap/keymap_by.c | 2 ++ src/hci/keymap/keymap_de.c | 2 ++ src/hci/keymap/keymap_dk.c | 2 ++ src/hci/keymap/keymap_es.c | 2 ++ src/hci/keymap/keymap_et.c | 2 ++ src/hci/keymap/keymap_fi.c | 2 ++ src/hci/keymap/keymap_fr.c | 2 ++ src/hci/keymap/keymap_gr.c | 2 ++ src/hci/keymap/keymap_il.c | 2 ++ src/hci/keymap/keymap_it.c | 2 ++ src/hci/keymap/keymap_mk.c | 2 ++ src/hci/keymap/keymap_nl.c | 2 ++ src/hci/keymap/keymap_no-latin1.c | 2 ++ src/hci/keymap/keymap_no.c | 2 ++ src/hci/keymap/keymap_pl.c | 2 ++ src/hci/keymap/keymap_pt.c | 2 ++ src/hci/keymap/keymap_ru.c | 2 ++ src/hci/keymap/keymap_sg.c | 2 ++ src/hci/keymap/keymap_sr-latin.c | 2 ++ src/hci/keymap/keymap_ua.c | 2 ++ src/include/ipxe/keymap.h | 3 +++ src/util/genkeymap.py | 31 +++++++++++++++++++++++----- 28 files changed, 93 insertions(+), 6 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 443513e9e..438a01d07 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -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; } diff --git a/src/core/keymap.c b/src/core/keymap.c index a6707a2ce..5054e4769 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -48,5 +48,8 @@ unsigned int key_remap ( unsigned int character ) { } } + /* Clear pseudo key flag */ + character &= ~KEYMAP_PSEUDO; + return character; } diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index ba4b2d4d7..6954cd69b 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -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- */ if ( islower ( key ) ) { diff --git a/src/drivers/usb/usbkbd.h b/src/drivers/usb/usbkbd.h index cedebfe71..1a3fea1ba 100644 --- a/src/drivers/usb/usbkbd.h +++ b/src/drivers/usb/usbkbd.h @@ -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 */ diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index e4418361b..6b4663489 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -30,4 +30,6 @@ struct key_mapping al_mapping[] __keymap = { { 0x7c, 0x7d }, /* '|' => '}' */ { 0x7d, 0x27 }, /* '}' => '\'' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_az.c b/src/hci/keymap/keymap_az.c index 525ab2336..91a243460 100644 --- a/src/hci/keymap/keymap_az.c +++ b/src/hci/keymap/keymap_az.c @@ -21,4 +21,6 @@ struct key_mapping az_mapping[] __keymap = { { 0x40, 0x22 }, /* '@' => '"' */ { 0x5e, 0x3a }, /* '^' => ':' */ { 0x7c, 0x2f }, /* '|' => '/' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 514d0b532..43fb746bf 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "by" keyboard mapping */ struct key_mapping by_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c index 2559e1538..85574d487 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -36,4 +36,6 @@ struct key_mapping de_mapping[] __keymap = { { 0x7a, 0x79 }, /* 'z' => 'y' */ { 0x7c, 0x27 }, /* '|' => '\'' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c index 05110dc89..4e1d5a739 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -28,4 +28,6 @@ struct key_mapping dk_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c index 51dedfff7..91327ea51 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -28,4 +28,6 @@ struct key_mapping es_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7d, 0x2a }, /* '}' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c index dd0f879b1..493ec93d4 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -26,4 +26,6 @@ struct key_mapping et_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c index c489bf0e5..18f48d47e 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -26,4 +26,6 @@ struct key_mapping fi_mapping[] __keymap = { { 0x5e, 0x26 }, /* '^' => '&' */ { 0x5f, 0x3f }, /* '_' => '?' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c index 8f3b4999d..808cd7945 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -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-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c index 42b6418e8..b48142e5e 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "gr" keyboard mapping */ struct key_mapping gr_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c index f631f7ac9..78e7fa970 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -24,4 +24,6 @@ struct key_mapping il_mapping[] __keymap = { { 0x60, 0x3b }, /* '`' => ';' */ { 0x7b, 0x7d }, /* '{' => '}' */ { 0x7d, 0x7b }, /* '}' => '{' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c index d96102c9e..5a8e2b38d 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -30,4 +30,6 @@ struct key_mapping it_mapping[] __keymap = { { 0x60, 0x5c }, /* '`' => '\\' */ { 0x7d, 0x2a }, /* '}' => '*' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c index 8f5060778..9f2cff78b 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "mk" keyboard mapping */ struct key_mapping mk_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c index 2a0fbbcbd..d248fc8ae 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -33,4 +33,6 @@ struct key_mapping nl_mapping[] __keymap = { { 0x60, 0x40 }, /* '`' => '@' */ { 0x7c, 0x3e }, /* '|' => '>' */ { 0x7d, 0x7c }, /* '}' => '|' */ + { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */ + { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */ }; diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c index 655e4cef7..d5a721a90 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -32,4 +32,6 @@ struct key_mapping no_latin1_mapping[] __keymap = { { 0x60, 0x7c }, /* '`' => '|' */ { 0x7c, 0x2a }, /* '|' => '*' */ { 0x7d, 0x5e }, /* '}' => '^' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c index 7a2df7c5a..b6190da4a 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -30,4 +30,6 @@ struct key_mapping no_mapping[] __keymap = { { 0x5f, 0x3f }, /* '_' => '?' */ { 0x60, 0x7c }, /* '`' => '|' */ { 0x7c, 0x2a }, /* '|' => '*' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c index 51822e072..224fbde28 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "pl" keyboard mapping */ struct key_mapping pl_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c index b993902af..6d850fee8 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -29,4 +29,6 @@ struct key_mapping pt_mapping[] __keymap = { { 0x60, 0x5c }, /* '`' => '\\' */ { 0x7b, 0x2a }, /* '{' => '*' */ { 0x7e, 0x7c }, /* '~' => '|' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c index c120ffd82..f7611c30a 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -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-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c index 0b0820929..9a515c745 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -38,4 +38,6 @@ struct key_mapping sg_mapping[] __keymap = { { 0x7a, 0x79 }, /* 'z' => 'y' */ { 0x7c, 0x24 }, /* '|' => '$' */ { 0x7d, 0x21 }, /* '}' => '!' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c index 9d76e8a6c..1d4588733 100644 --- a/src/hci/keymap/keymap_sr-latin.c +++ b/src/hci/keymap/keymap_sr-latin.c @@ -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-'|' => '>' */ }; diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c index 1106a8b28..50f2e184d 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -12,4 +12,6 @@ FILE_LICENCE ( PUBLIC_DOMAIN ); /** "ua" keyboard mapping */ struct key_mapping ua_mapping[] __keymap = { + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */ }; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 62b3bb131..93c9e7314 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -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 */ diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index 1bb494f83..081e314cc 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -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: -- cgit v1.2.3-55-g7522 From f2a59d5973da2041f93264609698b9b3f4ec101b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 16:31:08 +0000 Subject: [console] Centralise handling of key modifiers Handle Ctrl and CapsLock key modifiers within key_remap(), to provide consistent behaviour across different console types. Signed-off-by: Michael Brown --- src/arch/x86/include/bios.h | 3 ++ src/arch/x86/interface/pcbios/bios_console.c | 23 +++++++++++---- src/core/keymap.c | 41 ++++++++++++++++++++++---- src/drivers/usb/usbkbd.c | 21 ++++++------- src/include/ipxe/keymap.h | 21 +++++++++++++ src/interface/efi/efi_console.c | 44 ++++++++++++++++++---------- 6 files changed, 116 insertions(+), 37 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h index 14e7acbc7..3ba8264ec 100644 --- a/src/arch/x86/include/bios.h +++ b/src/arch/x86/include/bios.h @@ -6,6 +6,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define BDA_SEG 0x0040 #define BDA_EBDA 0x000e #define BDA_EQUIPMENT_WORD 0x0010 +#define BDA_KB0 0x0017 +#define BDA_KB0_CTRL 0x04 +#define BDA_KB0_CAPSLOCK 0x040 #define BDA_FBMS 0x0013 #define BDA_TICKS 0x006c #define BDA_MIDNIGHT 0x0070 diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 438a01d07..2664ac8a5 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -361,6 +361,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { */ static int bios_getchar ( void ) { uint16_t keypress; + uint8_t kb0; unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -385,16 +386,28 @@ static int bios_getchar ( void ) { bios_inject_lock--; scancode = ( keypress >> 8 ); character = ( keypress & 0xff ); + get_real ( kb0, BDA_SEG, BDA_KB0 ); /* 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 if ( scancode == SCANCODE_NON_US ) { - return key_remap ( character | KEYMAP_PSEUDO ); - } else { + + /* 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; + + /* Map and return */ + return key_remap ( character ); } /* Otherwise, check for a special key that we know about */ diff --git a/src/core/keymap.c b/src/core/keymap.c index c0953967a..a5209bc20 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -23,6 +23,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include +#include #include /** @file @@ -31,6 +33,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +/** ASCII character mask */ +#define ASCII_MASK 0x7f + +/** Control character mask */ +#define CTRL_MASK 0x1f + +/** Upper case character mask */ +#define UPPER_MASK 0x5f + +/** Case toggle bit */ +#define CASE_TOGGLE ( ASCII_MASK & ~UPPER_MASK ) + /** Default keyboard mapping */ static TABLE_START ( keymap_start, KEYMAP ); @@ -41,21 +55,36 @@ static struct keymap *keymap = keymap_start; * Remap a key * * @v character Character read from console - * @ret character Mapped character + * @ret mapped Mapped character */ unsigned int key_remap ( unsigned int character ) { + unsigned int mapped = ( character & KEYMAP_MASK ); struct keymap_key *key; + /* Invert case before remapping if applicable */ + if ( ( character & KEYMAP_CAPSLOCK_UNDO ) && isalpha ( mapped ) ) + mapped ^= CASE_TOGGLE; + /* Remap via table */ for ( key = keymap->basic ; key->from ; key++ ) { - if ( key->from == character ) { - character = key->to; + if ( mapped == key->from ) { + mapped = key->to; break; } } - /* Clear pseudo key flag */ - character &= ~KEYMAP_PSEUDO; + /* Handle Ctrl- and CapsLock */ + if ( isalpha ( mapped ) ) { + if ( character & KEYMAP_CTRL ) { + mapped &= CTRL_MASK; + } else if ( character & KEYMAP_CAPSLOCK ) { + mapped ^= CASE_TOGGLE; + } + } + + /* Clear flags */ + mapped &= ASCII_MASK; - return character; + DBGC2 ( &keymap, "KEYMAP mapped %04x => %02x\n", character, mapped ); + return mapped; } diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index 6954cd69b..516667b25 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -71,6 +71,9 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, } else if ( keycode <= USBKBD_KEY_Z ) { /* Alphabetic keys */ key = ( keycode - USBKBD_KEY_A + 'a' ); + if ( modifiers & USBKBD_SHIFT ) { + key -= ( 'a' - 'A' ); + } } else if ( keycode <= USBKBD_KEY_0 ) { /* Numeric key row */ if ( modifiers & USBKBD_SHIFT ) { @@ -125,17 +128,15 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, /* Remap key if applicable */ if ( ( keycode < USBKBD_KEY_CAPS_LOCK ) || ( keycode == USBKBD_KEY_NON_US ) ) { - key = key_remap ( key ); - } - /* Handle upper/lower case and Ctrl- */ - if ( islower ( key ) ) { - if ( modifiers & USBKBD_CTRL ) { - key -= ( 'a' - CTRL_A ); - } else if ( ( modifiers & USBKBD_SHIFT ) || - ( leds & USBKBD_LED_CAPS_LOCK ) ) { - key -= ( 'a' - 'A' ); - } + /* Apply modifiers */ + if ( modifiers & USBKBD_CTRL ) + key |= KEYMAP_CTRL; + if ( leds & USBKBD_LED_CAPS_LOCK ) + key |= KEYMAP_CAPSLOCK; + + /* Remap key */ + key = key_remap ( key ); } return key; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index a64ab9cd4..3da25190b 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -40,9 +40,30 @@ struct keymap { /** Define a keyboard mapping */ #define __keymap __table_entry ( KEYMAP, 01 ) +/** Mappable character mask */ +#define KEYMAP_MASK 0xff + /** Pseudo key flag */ #define KEYMAP_PSEUDO 0x80 +/** Ctrl key flag */ +#define KEYMAP_CTRL 0x0100 + +/** CapsLock key flag */ +#define KEYMAP_CAPSLOCK 0x0200 + +/** Undo CapsLock key flag + * + * Used when the keyboard driver has already interpreted the CapsLock + * key, in which case the effect needs to be undone before remapping + * in order to correctly handle keyboard mappings that swap alphabetic + * and non-alphabetic keys. + */ +#define KEYMAP_CAPSLOCK_UNDO 0x0400 + +/** Undo and redo CapsLock key flags */ +#define KEYMAP_CAPSLOCK_REDO ( KEYMAP_CAPSLOCK | KEYMAP_CAPSLOCK_UNDO ) + extern unsigned int key_remap ( unsigned int character ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 874f54b6c..9adce4a9b 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -55,8 +55,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #define ATTR_DEFAULT ATTR_FCOL_WHITE -#define CTRL_MASK 0x1f - /* Set default console usage if applicable */ #if ! ( defined ( CONSOLE_EFI ) && CONSOLE_EXPLICIT ( CONSOLE_EFI ) ) #undef CONSOLE_EFI @@ -286,6 +284,9 @@ static int efi_getchar ( void ) { EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn; EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex; const char *ansi_seq; + unsigned int character; + unsigned int shift; + unsigned int toggle; EFI_KEY_DATA key; EFI_STATUS efirc; int rc; @@ -318,23 +319,34 @@ static int efi_getchar ( void ) { key.KeyState.KeyToggleState, key.Key.UnicodeChar, key.Key.ScanCode ); - /* Remap key. There is unfortunately no way to avoid - * remapping the numeric keypad, since EFI destroys the scan - * code information that would allow us to differentiate - * between main keyboard and numeric keypad. + /* If key has a Unicode representation, remap and return it. + * There is unfortunately no way to avoid remapping the + * numeric keypad, since EFI destroys the scan code + * information that would allow us to differentiate between + * main keyboard and numeric keypad. */ - key.Key.UnicodeChar = key_remap ( key.Key.UnicodeChar ); + if ( ( character = key.Key.UnicodeChar ) != 0 ) { + + /* Apply shift state */ + shift = key.KeyState.KeyShiftState; + if ( shift & EFI_SHIFT_STATE_VALID ) { + if ( shift & ( EFI_LEFT_CONTROL_PRESSED | + EFI_RIGHT_CONTROL_PRESSED ) ) { + character |= KEYMAP_CTRL; + } + } - /* Translate Ctrl- */ - if ( ( key.KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID ) && - ( key.KeyState.KeyShiftState & ( EFI_LEFT_CONTROL_PRESSED | - EFI_RIGHT_CONTROL_PRESSED ) ) ) { - key.Key.UnicodeChar &= CTRL_MASK; - } + /* Apply toggle state */ + toggle = key.KeyState.KeyToggleState; + if ( toggle & EFI_TOGGLE_STATE_VALID ) { + if ( toggle & EFI_CAPS_LOCK_ACTIVE ) { + character |= KEYMAP_CAPSLOCK_REDO; + } + } - /* If key has a Unicode representation, return it */ - if ( key.Key.UnicodeChar ) - return key.Key.UnicodeChar; + /* Remap and return key */ + return key_remap ( character ); + } /* Otherwise, check for a special key that we know about */ if ( ( ansi_seq = scancode_to_ansi_seq ( key.Key.ScanCode ) ) ) { -- cgit v1.2.3-55-g7522 From e1cedbc0d4fdb0e16818f6b722f4873a50780761 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Feb 2022 13:45:59 +0000 Subject: [console] Support AltGr to access ASCII characters via remapping Several keyboard layouts define ASCII characters as accessible only via the AltGr modifier. Add support for this modifier to ensure that all ASCII characters are accessible. Experiments suggest that the BIOS console is likely to fail to generate ASCII characters when the AltGr key is pressed. Work around this limitation by accepting LShift+RShift (which will definitely produce an ASCII character) as a synonym for AltGr. Signed-off-by: Michael Brown --- src/arch/x86/include/bios.h | 4 +++ src/arch/x86/interface/pcbios/bios_console.c | 12 +++++++++ src/core/keymap.c | 5 +++- src/drivers/usb/usbkbd.c | 2 ++ src/hci/keymap/keymap_al.c | 8 ++++++ src/hci/keymap/keymap_az.c | 7 +++++ src/hci/keymap/keymap_by.c | 6 +++++ src/hci/keymap/keymap_cf.c | 9 +++++++ src/hci/keymap/keymap_cz.c | 26 ++++++++++++++++++ src/hci/keymap/keymap_de.c | 11 ++++++++ src/hci/keymap/keymap_dk.c | 9 +++++++ src/hci/keymap/keymap_es.c | 11 ++++++++ src/hci/keymap/keymap_et.c | 10 +++++++ src/hci/keymap/keymap_fi.c | 9 +++++++ src/hci/keymap/keymap_fr.c | 12 +++++++++ src/hci/keymap/keymap_gr.c | 6 +++++ src/hci/keymap/keymap_hu.c | 17 ++++++++++++ src/hci/keymap/keymap_il.c | 6 +++++ src/hci/keymap/keymap_it.c | 12 +++++++++ src/hci/keymap/keymap_lt.c | 6 +++++ src/hci/keymap/keymap_mk.c | 6 +++++ src/hci/keymap/keymap_mt.c | 7 +++++ src/hci/keymap/keymap_nl.c | 8 ++++++ src/hci/keymap/keymap_no-latin1.c | 10 +++++++ src/hci/keymap/keymap_no.c | 8 ++++++ src/hci/keymap/keymap_pl.c | 6 +++++ src/hci/keymap/keymap_pt.c | 10 +++++++ src/hci/keymap/keymap_ro.c | 6 +++++ src/hci/keymap/keymap_ru.c | 6 +++++ src/hci/keymap/keymap_sg.c | 10 +++++++ src/hci/keymap/keymap_sr-latin.c | 6 +++++ src/hci/keymap/keymap_ua.c | 6 +++++ src/hci/keymap/keymap_uk.c | 6 +++++ src/hci/keymap/keymap_us.c | 6 +++++ src/include/ipxe/keymap.h | 5 ++++ src/interface/efi/efi_console.c | 3 +++ src/util/genkeymap.py | 40 +++++++++++++++++++++++++--- 37 files changed, 332 insertions(+), 5 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/include/bios.h b/src/arch/x86/include/bios.h index 3ba8264ec..6391a4958 100644 --- a/src/arch/x86/include/bios.h +++ b/src/arch/x86/include/bios.h @@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define BDA_EBDA 0x000e #define BDA_EQUIPMENT_WORD 0x0010 #define BDA_KB0 0x0017 +#define BDA_KB0_RSHIFT 0x01 +#define BDA_KB0_LSHIFT 0x02 #define BDA_KB0_CTRL 0x04 #define BDA_KB0_CAPSLOCK 0x040 #define BDA_FBMS 0x0013 @@ -16,5 +18,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define BDA_REBOOT_WARM 0x1234 #define BDA_NUM_DRIVES 0x0075 #define BDA_CHAR_HEIGHT 0x0085 +#define BDA_KB2 0x0096 +#define BDA_KB2_RALT 0x08 #endif /* BIOS_H */ diff --git a/src/arch/x86/interface/pcbios/bios_console.c b/src/arch/x86/interface/pcbios/bios_console.c index 2664ac8a5..0220c8564 100644 --- a/src/arch/x86/interface/pcbios/bios_console.c +++ b/src/arch/x86/interface/pcbios/bios_console.c @@ -362,6 +362,7 @@ static const char * bios_ansi_seq ( unsigned int scancode ) { static int bios_getchar ( void ) { uint16_t keypress; uint8_t kb0; + uint8_t kb2; unsigned int scancode; unsigned int character; const char *ansi_seq; @@ -387,6 +388,7 @@ static int bios_getchar ( void ) { 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 ) ) { @@ -405,6 +407,16 @@ static int bios_getchar ( void ) { 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; + } /* Map and return */ return key_remap ( character ); diff --git a/src/core/keymap.c b/src/core/keymap.c index a5209bc20..3fa85f74e 100644 --- a/src/core/keymap.c +++ b/src/core/keymap.c @@ -65,8 +65,11 @@ unsigned int key_remap ( unsigned int character ) { if ( ( character & KEYMAP_CAPSLOCK_UNDO ) && isalpha ( mapped ) ) mapped ^= CASE_TOGGLE; + /* Select remapping table */ + key = ( ( character & KEYMAP_ALTGR ) ? keymap->altgr : keymap->basic ); + /* Remap via table */ - for ( key = keymap->basic ; key->from ; key++ ) { + for ( ; key->from ; key++ ) { if ( mapped == key->from ) { mapped = key->to; break; diff --git a/src/drivers/usb/usbkbd.c b/src/drivers/usb/usbkbd.c index 516667b25..b284e584f 100644 --- a/src/drivers/usb/usbkbd.c +++ b/src/drivers/usb/usbkbd.c @@ -132,6 +132,8 @@ static unsigned int usbkbd_map ( unsigned int keycode, unsigned int modifiers, /* Apply modifiers */ if ( modifiers & USBKBD_CTRL ) key |= KEYMAP_CTRL; + if ( modifiers & USBKBD_ALT_RIGHT ) + key |= KEYMAP_ALTGR; if ( leds & USBKBD_LED_CAPS_LOCK ) key |= KEYMAP_CAPSLOCK; diff --git a/src/hci/keymap/keymap_al.c b/src/hci/keymap/keymap_al.c index a3df385a9..b68b98878 100644 --- a/src/hci/keymap/keymap_al.c +++ b/src/hci/keymap/keymap_al.c @@ -35,8 +35,16 @@ static struct keymap_key al_basic[] = { { 0, 0 } }; +/** "al" AltGr remapping */ +static struct keymap_key al_altgr[] = { + { 0x31, 0x7e }, /* '1' => '~' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0, 0 } +}; + /** "al" keyboard map */ struct keymap al_keymap __keymap = { .name = "al", .basic = al_basic, + .altgr = al_altgr, }; diff --git a/src/hci/keymap/keymap_az.c b/src/hci/keymap/keymap_az.c index 7b382ca8b..03087e01e 100644 --- a/src/hci/keymap/keymap_az.c +++ b/src/hci/keymap/keymap_az.c @@ -26,8 +26,15 @@ static struct keymap_key az_basic[] = { { 0, 0 } }; +/** "az" AltGr remapping */ +static struct keymap_key az_altgr[] = { + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + /** "az" keyboard map */ struct keymap az_keymap __keymap = { .name = "az", .basic = az_basic, + .altgr = az_altgr, }; diff --git a/src/hci/keymap/keymap_by.c b/src/hci/keymap/keymap_by.c index 4127609e3..9af6c966d 100644 --- a/src/hci/keymap/keymap_by.c +++ b/src/hci/keymap/keymap_by.c @@ -17,8 +17,14 @@ static struct keymap_key by_basic[] = { { 0, 0 } }; +/** "by" AltGr remapping */ +static struct keymap_key by_altgr[] = { + { 0, 0 } +}; + /** "by" keyboard map */ struct keymap by_keymap __keymap = { .name = "by", .basic = by_basic, + .altgr = by_altgr, }; diff --git a/src/hci/keymap/keymap_cf.c b/src/hci/keymap/keymap_cf.c index 0bbe89659..09242ee6f 100644 --- a/src/hci/keymap/keymap_cf.c +++ b/src/hci/keymap/keymap_cf.c @@ -24,8 +24,17 @@ static struct keymap_key cf_basic[] = { { 0, 0 } }; +/** "cf" AltGr remapping */ +static struct keymap_key cf_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x3b, 0x7e }, /* ';' => '~' */ + { 0x60, 0x5c }, /* '`' => '\\' */ + { 0, 0 } +}; + /** "cf" keyboard map */ struct keymap cf_keymap __keymap = { .name = "cf", .basic = cf_basic, + .altgr = cf_altgr, }; diff --git a/src/hci/keymap/keymap_cz.c b/src/hci/keymap/keymap_cz.c index 8655d5b68..cce686d9a 100644 --- a/src/hci/keymap/keymap_cz.c +++ b/src/hci/keymap/keymap_cz.c @@ -46,8 +46,34 @@ static struct keymap_key cz_basic[] = { { 0, 0 } }; +/** "cz" AltGr remapping */ +static struct keymap_key cz_altgr[] = { + { 0x2c, 0x3c }, /* ',' => '<' */ + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x34, 0x24 }, /* '4' => '$' */ + { 0x36, 0x5e }, /* '6' => '^' */ + { 0x37, 0x26 }, /* '7' => '&' */ + { 0x38, 0x2a }, /* '8' => '*' */ + { 0x39, 0x7b }, /* '9' => '{' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x62, 0x7b }, /* 'b' => '{' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x67, 0x5d }, /* 'g' => ']' */ + { 0x68, 0x60 }, /* 'h' => '`' */ + { 0x6d, 0x5e }, /* 'm' => '^' */ + { 0x6e, 0x7d }, /* 'n' => '}' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 0, 0 } +}; + /** "cz" keyboard map */ struct keymap cz_keymap __keymap = { .name = "cz", .basic = cz_basic, + .altgr = cz_altgr, }; diff --git a/src/hci/keymap/keymap_de.c b/src/hci/keymap/keymap_de.c index 4d23c2e60..4a889a242 100644 --- a/src/hci/keymap/keymap_de.c +++ b/src/hci/keymap/keymap_de.c @@ -41,8 +41,19 @@ static struct keymap_key de_basic[] = { { 0, 0 } }; +/** "de" AltGr remapping */ +static struct keymap_key de_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + /** "de" keyboard map */ struct keymap de_keymap __keymap = { .name = "de", .basic = de_basic, + .altgr = de_altgr, }; diff --git a/src/hci/keymap/keymap_dk.c b/src/hci/keymap/keymap_dk.c index 100246bf5..4d40743b1 100644 --- a/src/hci/keymap/keymap_dk.c +++ b/src/hci/keymap/keymap_dk.c @@ -33,8 +33,17 @@ static struct keymap_key dk_basic[] = { { 0, 0 } }; +/** "dk" AltGr remapping */ +static struct keymap_key dk_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x3d, 0x7c }, /* '=' => '|' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + /** "dk" keyboard map */ struct keymap dk_keymap __keymap = { .name = "dk", .basic = dk_basic, + .altgr = dk_altgr, }; diff --git a/src/hci/keymap/keymap_es.c b/src/hci/keymap/keymap_es.c index 2f4b86c47..397e2cbaa 100644 --- a/src/hci/keymap/keymap_es.c +++ b/src/hci/keymap/keymap_es.c @@ -33,8 +33,19 @@ static struct keymap_key es_basic[] = { { 0, 0 } }; +/** "es" AltGr remapping */ +static struct keymap_key es_altgr[] = { + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + /** "es" keyboard map */ struct keymap es_keymap __keymap = { .name = "es", .basic = es_basic, + .altgr = es_altgr, }; diff --git a/src/hci/keymap/keymap_et.c b/src/hci/keymap/keymap_et.c index a8bf46ebc..4120dbed9 100644 --- a/src/hci/keymap/keymap_et.c +++ b/src/hci/keymap/keymap_et.c @@ -31,8 +31,18 @@ static struct keymap_key et_basic[] = { { 0, 0 } }; +/** "et" AltGr remapping */ +static struct keymap_key et_altgr[] = { + { 0x27, 0x5e }, /* '\'' => '^' */ + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + /** "et" keyboard map */ struct keymap et_keymap __keymap = { .name = "et", .basic = et_basic, + .altgr = et_altgr, }; diff --git a/src/hci/keymap/keymap_fi.c b/src/hci/keymap/keymap_fi.c index eb75eb4dc..978121a88 100644 --- a/src/hci/keymap/keymap_fi.c +++ b/src/hci/keymap/keymap_fi.c @@ -31,8 +31,17 @@ static struct keymap_key fi_basic[] = { { 0, 0 } }; +/** "fi" AltGr remapping */ +static struct keymap_key fi_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */ + { 0, 0 } +}; + /** "fi" keyboard map */ struct keymap fi_keymap __keymap = { .name = "fi", .basic = fi_basic, + .altgr = fi_altgr, }; diff --git a/src/hci/keymap/keymap_fr.c b/src/hci/keymap/keymap_fr.c index 523254ee5..c0a959f0d 100644 --- a/src/hci/keymap/keymap_fr.c +++ b/src/hci/keymap/keymap_fr.c @@ -62,8 +62,20 @@ static struct keymap_key fr_basic[] = { { 0, 0 } }; +/** "fr" AltGr remapping */ +static struct keymap_key fr_altgr[] = { + { 0x2d, 0x5d }, /* '-' => ']' */ + { 0x30, 0x40 }, /* '0' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x38, 0x5c }, /* '8' => '\\' */ + { 0x39, 0x5e }, /* '9' => '^' */ + { 0x61, 0x40 }, /* 'a' => '@' */ + { 0, 0 } +}; + /** "fr" keyboard map */ struct keymap fr_keymap __keymap = { .name = "fr", .basic = fr_basic, + .altgr = fr_altgr, }; diff --git a/src/hci/keymap/keymap_gr.c b/src/hci/keymap/keymap_gr.c index 16a2a7032..4826c26c2 100644 --- a/src/hci/keymap/keymap_gr.c +++ b/src/hci/keymap/keymap_gr.c @@ -17,8 +17,14 @@ static struct keymap_key gr_basic[] = { { 0, 0 } }; +/** "gr" AltGr remapping */ +static struct keymap_key gr_altgr[] = { + { 0, 0 } +}; + /** "gr" keyboard map */ struct keymap gr_keymap __keymap = { .name = "gr", .basic = gr_basic, + .altgr = gr_altgr, }; diff --git a/src/hci/keymap/keymap_hu.c b/src/hci/keymap/keymap_hu.c index 5e407161f..64e27dda6 100644 --- a/src/hci/keymap/keymap_hu.c +++ b/src/hci/keymap/keymap_hu.c @@ -35,8 +35,25 @@ static struct keymap_key hu_basic[] = { { 0, 0 } }; +/** "hu" AltGr remapping */ +static struct keymap_key hu_altgr[] = { + { 0x2e, 0x3e }, /* '.' => '>' */ + { 0x2f, 0x2a }, /* '/' => '*' */ + { 0x33, 0x5e }, /* '3' => '^' */ + { 0x37, 0x60 }, /* '7' => '`' */ + { 0x3b, 0x24 }, /* ';' => '$' */ + { 0x63, 0x26 }, /* 'c' => '&' */ + { 0x6d, 0x3c }, /* 'm' => '<' */ + { 0x76, 0x40 }, /* 'v' => '@' */ + { 0x78, 0x23 }, /* 'x' => '#' */ + { 0x7a, 0x3e }, /* 'z' => '>' */ + { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */ + { 0, 0 } +}; + /** "hu" keyboard map */ struct keymap hu_keymap __keymap = { .name = "hu", .basic = hu_basic, + .altgr = hu_altgr, }; diff --git a/src/hci/keymap/keymap_il.c b/src/hci/keymap/keymap_il.c index de5e639ca..e3061fa54 100644 --- a/src/hci/keymap/keymap_il.c +++ b/src/hci/keymap/keymap_il.c @@ -29,8 +29,14 @@ static struct keymap_key il_basic[] = { { 0, 0 } }; +/** "il" AltGr remapping */ +static struct keymap_key il_altgr[] = { + { 0, 0 } +}; + /** "il" keyboard map */ struct keymap il_keymap __keymap = { .name = "il", .basic = il_basic, + .altgr = il_altgr, }; diff --git a/src/hci/keymap/keymap_it.c b/src/hci/keymap/keymap_it.c index a4921020a..f67bbadcb 100644 --- a/src/hci/keymap/keymap_it.c +++ b/src/hci/keymap/keymap_it.c @@ -35,8 +35,20 @@ static struct keymap_key it_basic[] = { { 0, 0 } }; +/** "it" AltGr remapping */ +static struct keymap_key it_altgr[] = { + { 0x2d, 0x60 }, /* '-' => '`' */ + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x3b, 0x40 }, /* ';' => '@' */ + { 0x3d, 0x7e }, /* '=' => '~' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + /** "it" keyboard map */ struct keymap it_keymap __keymap = { .name = "it", .basic = it_basic, + .altgr = it_altgr, }; diff --git a/src/hci/keymap/keymap_lt.c b/src/hci/keymap/keymap_lt.c index 333241d21..5d6ee5a8c 100644 --- a/src/hci/keymap/keymap_lt.c +++ b/src/hci/keymap/keymap_lt.c @@ -15,8 +15,14 @@ static struct keymap_key lt_basic[] = { { 0, 0 } }; +/** "lt" AltGr remapping */ +static struct keymap_key lt_altgr[] = { + { 0, 0 } +}; + /** "lt" keyboard map */ struct keymap lt_keymap __keymap = { .name = "lt", .basic = lt_basic, + .altgr = lt_altgr, }; diff --git a/src/hci/keymap/keymap_mk.c b/src/hci/keymap/keymap_mk.c index 1656fb99c..4b90ef799 100644 --- a/src/hci/keymap/keymap_mk.c +++ b/src/hci/keymap/keymap_mk.c @@ -17,8 +17,14 @@ static struct keymap_key mk_basic[] = { { 0, 0 } }; +/** "mk" AltGr remapping */ +static struct keymap_key mk_altgr[] = { + { 0, 0 } +}; + /** "mk" keyboard map */ struct keymap mk_keymap __keymap = { .name = "mk", .basic = mk_basic, + .altgr = mk_altgr, }; diff --git a/src/hci/keymap/keymap_mt.c b/src/hci/keymap/keymap_mt.c index ebff8506f..f5baf6907 100644 --- a/src/hci/keymap/keymap_mt.c +++ b/src/hci/keymap/keymap_mt.c @@ -20,8 +20,15 @@ static struct keymap_key mt_basic[] = { { 0, 0 } }; +/** "mt" AltGr remapping */ +static struct keymap_key mt_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0, 0 } +}; + /** "mt" keyboard map */ struct keymap mt_keymap __keymap = { .name = "mt", .basic = mt_basic, + .altgr = mt_altgr, }; diff --git a/src/hci/keymap/keymap_nl.c b/src/hci/keymap/keymap_nl.c index 2172e045f..bbee4cbdf 100644 --- a/src/hci/keymap/keymap_nl.c +++ b/src/hci/keymap/keymap_nl.c @@ -38,8 +38,16 @@ static struct keymap_key nl_basic[] = { { 0, 0 } }; +/** "nl" AltGr remapping */ +static struct keymap_key nl_altgr[] = { + { 0x2d, 0x5c }, /* '-' => '\\' */ + { 0x39, 0x7d }, /* '9' => '}' */ + { 0, 0 } +}; + /** "nl" keyboard map */ struct keymap nl_keymap __keymap = { .name = "nl", .basic = nl_basic, + .altgr = nl_altgr, }; diff --git a/src/hci/keymap/keymap_no-latin1.c b/src/hci/keymap/keymap_no-latin1.c index 65f30beae..63fe85548 100644 --- a/src/hci/keymap/keymap_no-latin1.c +++ b/src/hci/keymap/keymap_no-latin1.c @@ -37,8 +37,18 @@ static struct keymap_key no_latin1_basic[] = { { 0, 0 } }; +/** "no-latin1" AltGr remapping */ +static struct keymap_key no_latin1_altgr[] = { + { 0x30, 0x7d }, /* '0' => '}' */ + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x39, 0x5d }, /* '9' => ']' */ + { 0x5b, 0x7d }, /* '[' => '}' */ + { 0, 0 } +}; + /** "no-latin1" keyboard map */ struct keymap no_latin1_keymap __keymap = { .name = "no-latin1", .basic = no_latin1_basic, + .altgr = no_latin1_altgr, }; diff --git a/src/hci/keymap/keymap_no.c b/src/hci/keymap/keymap_no.c index d3d06bce3..95a95428b 100644 --- a/src/hci/keymap/keymap_no.c +++ b/src/hci/keymap/keymap_no.c @@ -35,8 +35,16 @@ static struct keymap_key no_basic[] = { { 0, 0 } }; +/** "no" AltGr remapping */ +static struct keymap_key no_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + /** "no" keyboard map */ struct keymap no_keymap __keymap = { .name = "no", .basic = no_basic, + .altgr = no_altgr, }; diff --git a/src/hci/keymap/keymap_pl.c b/src/hci/keymap/keymap_pl.c index a23c01f2c..a76181fbc 100644 --- a/src/hci/keymap/keymap_pl.c +++ b/src/hci/keymap/keymap_pl.c @@ -17,8 +17,14 @@ static struct keymap_key pl_basic[] = { { 0, 0 } }; +/** "pl" AltGr remapping */ +static struct keymap_key pl_altgr[] = { + { 0, 0 } +}; + /** "pl" keyboard map */ struct keymap pl_keymap __keymap = { .name = "pl", .basic = pl_basic, + .altgr = pl_altgr, }; diff --git a/src/hci/keymap/keymap_pt.c b/src/hci/keymap/keymap_pt.c index c065fd76f..99ba52e4b 100644 --- a/src/hci/keymap/keymap_pt.c +++ b/src/hci/keymap/keymap_pt.c @@ -34,8 +34,18 @@ static struct keymap_key pt_basic[] = { { 0, 0 } }; +/** "pt" AltGr remapping */ +static struct keymap_key pt_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x37, 0x7b }, /* '7' => '{' */ + { 0x38, 0x5b }, /* '8' => '[' */ + { 0x71, 0x40 }, /* 'q' => '@' */ + { 0, 0 } +}; + /** "pt" keyboard map */ struct keymap pt_keymap __keymap = { .name = "pt", .basic = pt_basic, + .altgr = pt_altgr, }; diff --git a/src/hci/keymap/keymap_ro.c b/src/hci/keymap/keymap_ro.c index 334cf6080..620450001 100644 --- a/src/hci/keymap/keymap_ro.c +++ b/src/hci/keymap/keymap_ro.c @@ -15,8 +15,14 @@ static struct keymap_key ro_basic[] = { { 0, 0 } }; +/** "ro" AltGr remapping */ +static struct keymap_key ro_altgr[] = { + { 0, 0 } +}; + /** "ro" keyboard map */ struct keymap ro_keymap __keymap = { .name = "ro", .basic = ro_basic, + .altgr = ro_altgr, }; diff --git a/src/hci/keymap/keymap_ru.c b/src/hci/keymap/keymap_ru.c index a08b115ed..2aafcf9bd 100644 --- a/src/hci/keymap/keymap_ru.c +++ b/src/hci/keymap/keymap_ru.c @@ -18,8 +18,14 @@ static struct keymap_key ru_basic[] = { { 0, 0 } }; +/** "ru" AltGr remapping */ +static struct keymap_key ru_altgr[] = { + { 0, 0 } +}; + /** "ru" keyboard map */ struct keymap ru_keymap __keymap = { .name = "ru", .basic = ru_basic, + .altgr = ru_altgr, }; diff --git a/src/hci/keymap/keymap_sg.c b/src/hci/keymap/keymap_sg.c index 152c5d631..9a6db9cb4 100644 --- a/src/hci/keymap/keymap_sg.c +++ b/src/hci/keymap/keymap_sg.c @@ -43,8 +43,18 @@ static struct keymap_key sg_basic[] = { { 0, 0 } }; +/** "sg" AltGr remapping */ +static struct keymap_key sg_altgr[] = { + { 0x32, 0x40 }, /* '2' => '@' */ + { 0x33, 0x23 }, /* '3' => '#' */ + { 0x37, 0x7c }, /* '7' => '|' */ + { 0x5c, 0x7d }, /* '\\' => '}' */ + { 0, 0 } +}; + /** "sg" keyboard map */ struct keymap sg_keymap __keymap = { .name = "sg", .basic = sg_basic, + .altgr = sg_altgr, }; diff --git a/src/hci/keymap/keymap_sr-latin.c b/src/hci/keymap/keymap_sr-latin.c index ec5efdc89..7e55714a2 100644 --- a/src/hci/keymap/keymap_sr-latin.c +++ b/src/hci/keymap/keymap_sr-latin.c @@ -17,8 +17,14 @@ static struct keymap_key sr_latin_basic[] = { { 0, 0 } }; +/** "sr-latin" AltGr remapping */ +static struct keymap_key sr_latin_altgr[] = { + { 0, 0 } +}; + /** "sr-latin" keyboard map */ struct keymap sr_latin_keymap __keymap = { .name = "sr-latin", .basic = sr_latin_basic, + .altgr = sr_latin_altgr, }; diff --git a/src/hci/keymap/keymap_ua.c b/src/hci/keymap/keymap_ua.c index b4199cdad..44e82cb2d 100644 --- a/src/hci/keymap/keymap_ua.c +++ b/src/hci/keymap/keymap_ua.c @@ -17,8 +17,14 @@ static struct keymap_key ua_basic[] = { { 0, 0 } }; +/** "ua" AltGr remapping */ +static struct keymap_key ua_altgr[] = { + { 0, 0 } +}; + /** "ua" keyboard map */ struct keymap ua_keymap __keymap = { .name = "ua", .basic = ua_basic, + .altgr = ua_altgr, }; diff --git a/src/hci/keymap/keymap_uk.c b/src/hci/keymap/keymap_uk.c index 156b42dff..28cf7aac4 100644 --- a/src/hci/keymap/keymap_uk.c +++ b/src/hci/keymap/keymap_uk.c @@ -19,8 +19,14 @@ static struct keymap_key uk_basic[] = { { 0, 0 } }; +/** "uk" AltGr remapping */ +static struct keymap_key uk_altgr[] = { + { 0, 0 } +}; + /** "uk" keyboard map */ struct keymap uk_keymap __keymap = { .name = "uk", .basic = uk_basic, + .altgr = uk_altgr, }; diff --git a/src/hci/keymap/keymap_us.c b/src/hci/keymap/keymap_us.c index 5d78f80a2..6432474e2 100644 --- a/src/hci/keymap/keymap_us.c +++ b/src/hci/keymap/keymap_us.c @@ -15,8 +15,14 @@ static struct keymap_key us_basic[] = { { 0, 0 } }; +/** "us" AltGr remapping */ +static struct keymap_key us_altgr[] = { + { 0, 0 } +}; + /** "us" keyboard map */ struct keymap us_keymap __keymap = { .name = "us", .basic = us_basic, + .altgr = us_altgr, }; diff --git a/src/include/ipxe/keymap.h b/src/include/ipxe/keymap.h index 3da25190b..72b6961ef 100644 --- a/src/include/ipxe/keymap.h +++ b/src/include/ipxe/keymap.h @@ -32,6 +32,8 @@ struct keymap { const char *name; /** Basic remapping table (zero-terminated) */ struct keymap_key *basic; + /** AltGr remapping table (zero-terminated) */ + struct keymap_key *altgr; }; /** Keyboard mapping table */ @@ -64,6 +66,9 @@ struct keymap { /** Undo and redo CapsLock key flags */ #define KEYMAP_CAPSLOCK_REDO ( KEYMAP_CAPSLOCK | KEYMAP_CAPSLOCK_UNDO ) +/** AltGr key flag */ +#define KEYMAP_ALTGR 0x0800 + extern unsigned int key_remap ( unsigned int character ); #endif /* _IPXE_KEYMAP_H */ diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 9adce4a9b..fc1500afb 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -334,6 +334,9 @@ static int efi_getchar ( void ) { EFI_RIGHT_CONTROL_PRESSED ) ) { character |= KEYMAP_CTRL; } + if ( shift & EFI_RIGHT_ALT_PRESSED ) { + character |= KEYMAP_ALTGR; + } } /* Apply toggle state */ diff --git a/src/util/genkeymap.py b/src/util/genkeymap.py index d38552eb4..ff5ff0a87 100755 --- a/src/util/genkeymap.py +++ b/src/util/genkeymap.py @@ -171,6 +171,11 @@ class KeyLayout(UserDict[KeyModifiers, Sequence[Key]]): """Basic shifted keyboard layout""" return self[KeyModifiers.SHIFT] + @property + def altgr(self): + """AltGr keyboard layout""" + return self.get(KeyModifiers.ALTGR, self.unshifted) + @classmethod def load(cls, name: str) -> KeyLayout: """Load keymap using 'loadkeys -b'""" @@ -278,6 +283,7 @@ class KeymapKeys(UserDict[str, str]): self.ascii_name(source), self.ascii_name(target) ) for source, target in self.items() + if ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target) ) + '\t{ 0, 0 }\n}' @@ -301,13 +307,12 @@ class Keymap: 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 mappings that would become identity - # mappings after clearing the high bit + # the backspace key, or identity mappings table = {source: target for source, target in raw.items() if target and ord(source) != 0x7f and ord(target) != 0x7f - and ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target)} + and source != target} # Recursively delete any mappings that would produce # unreachable alphanumerics (e.g. the "il" keymap, which maps # away the whole lower-case alphabet) @@ -327,6 +332,28 @@ class Keymap: (unshifted, shifted)) return KeymapKeys(dict(sorted(table.items()))) + @property + def altgr(self) -> KeymapKeys: + """AltGr remapping table""" + # Construct raw mapping from source ASCII to target ASCII + raw = {source: self.target.altgr[key.keycode].ascii + for source, key in self.source.inverse.items() + if key.modifiers == KeyModifiers.NONE} + # Identify printable keys that are unreachable via the basic map + basic = self.basic + unmapped = set(x for x in basic.keys() + if x.isascii() and x.isprintable()) + remapped = set(basic.values()) + unreachable = unmapped - remapped + # Eliminate any null mappings, mappings for unprintable + # characters, or mappings for characters that are reachable + # via the basic map + table = {source: target for source, target in raw.items() + if source.isprintable() + and target + and target in unreachable} + return KeymapKeys(dict(sorted(table.items()))) + def cname(self, suffix: str) -> str: """C variable name""" return re.sub(r'\W', '_', (self.name + '_' + suffix)) @@ -336,6 +363,7 @@ class Keymap: """Generated source code""" keymap_name = self.cname("keymap") basic_name = self.cname("basic") + altgr_name = self.cname("altgr") code = textwrap.dedent(f""" /** @file * @@ -352,12 +380,16 @@ class Keymap: /** "{self.name}" basic remapping */ static struct keymap_key {basic_name}[] = %s; + /** "{self.name}" AltGr remapping */ + static struct keymap_key {altgr_name}[] = %s; + /** "{self.name}" keyboard map */ struct keymap {keymap_name} __keymap = {{ \t.name = "{self.name}", \t.basic = {basic_name}, + \t.altgr = {altgr_name}, }}; - """).strip() % self.basic.code + """).strip() % (self.basic.code, self.altgr.code) return code -- cgit v1.2.3-55-g7522 From ba93c9134ce9d9edcba117b690fbbdd35b3e066b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Mar 2022 22:38:24 +0000 Subject: [fbcon] Support Unicode character output Accumulate UTF-8 characters in fbcon_putchar(), and require the frame buffer console's .glyph() method to accept Unicode character values. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/vesafb.c | 25 ++++- src/core/fbcon.c | 5 + src/include/ipxe/fbcon.h | 7 +- src/interface/efi/efi_fbcon.c | 198 +++++++++++++++++++++------------ 4 files changed, 161 insertions(+), 74 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/interface/pcbios/vesafb.c b/src/arch/x86/interface/pcbios/vesafb.c index 50e485852..86edbda42 100644 --- a/src/arch/x86/interface/pcbios/vesafb.c +++ b/src/arch/x86/interface/pcbios/vesafb.c @@ -78,6 +78,15 @@ struct console_driver bios_console __attribute__ (( weak )); /** Font corresponding to selected character width and height */ #define VESAFB_FONT VBE_FONT_8x16 +/** Number of ASCII glyphs within the font */ +#define VESAFB_ASCII 128 + +/** Glyph to render for non-ASCII characters + * + * We choose to use one of the box-drawing glyphs. + */ +#define VESAFB_UNKNOWN 0xfe + /* Forward declaration */ struct console_driver vesafb_console __console_driver; @@ -130,12 +139,24 @@ static int vesafb_rc ( unsigned int status ) { /** * Get character glyph * - * @v character Character + * @v character Unicode character * @v glyph Character glyph to fill in */ static void vesafb_glyph ( unsigned int character, uint8_t *glyph ) { - size_t offset = ( character * VESAFB_CHAR_HEIGHT ); + unsigned int index; + size_t offset; + + /* Identify glyph */ + if ( character < VESAFB_ASCII ) { + /* ASCII character: use corresponding glyph */ + index = character; + } else { + /* Non-ASCII character: use "unknown" glyph */ + index = VESAFB_UNKNOWN; + } + /* Copy glyph from BIOS font table */ + offset = ( index * VESAFB_CHAR_HEIGHT ); copy_from_real ( glyph, vesafb.glyphs.segment, ( vesafb.glyphs.offset + offset ), VESAFB_CHAR_HEIGHT); } diff --git a/src/core/fbcon.c b/src/core/fbcon.c index 44a56e105..ff3132ac7 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -446,6 +446,11 @@ void fbcon_putchar ( struct fbcon *fbcon, int character ) { if ( character < 0 ) return; + /* Accumulate Unicode characters */ + character = utf8_accumulate ( &fbcon->utf8, character ); + if ( character == 0 ) + return; + /* Handle control characters */ switch ( character ) { case '\r': diff --git a/src/include/ipxe/fbcon.h b/src/include/ipxe/fbcon.h index 42ffca3d7..a4c7a9ab3 100644 --- a/src/include/ipxe/fbcon.h +++ b/src/include/ipxe/fbcon.h @@ -11,6 +11,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include @@ -36,7 +37,7 @@ struct fbcon_font { /** * Get character glyph * - * @v character Character + * @v character Unicode character * @v glyph Character glyph to fill in */ void ( * glyph ) ( unsigned int character, uint8_t *glyph ); @@ -92,7 +93,7 @@ struct fbcon_text_cell { uint32_t foreground; /** Background colour */ uint32_t background; - /** Character */ + /** Unicode character */ unsigned int character; }; @@ -138,6 +139,8 @@ struct fbcon { unsigned int ypos; /** ANSI escape sequence context */ struct ansiesc_context ctx; + /** UTF-8 accumulator */ + struct utf8_accumulator utf8; /** Text array */ struct fbcon_text text; /** Background picture */ diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index abc5a9390..d9e3e69e6 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -62,6 +62,9 @@ struct console_driver efi_console __attribute__ (( weak )); #define CONSOLE_EFIFB ( CONSOLE_USAGE_ALL & ~CONSOLE_USAGE_LOG ) #endif +/** Number of ASCII glyphs in cache */ +#define EFIFB_ASCII 128 + /* Forward declaration */ struct console_driver efifb_console __console_driver; @@ -84,7 +87,7 @@ struct efifb { struct fbcon_colour_map map; /** Font definition */ struct fbcon_font font; - /** Character glyphs */ + /** Character glyph cache */ userptr_t glyphs; }; @@ -92,14 +95,112 @@ struct efifb { static struct efifb efifb; /** - * Get character glyph + * Draw character glyph * * @v character Character + * @v index Index within glyph cache + * @v toggle Bits to toggle in each bitmask + * @ret height Character height, or negative error + */ +static int efifb_draw ( unsigned int character, unsigned int index, + unsigned int toggle ) { + EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_IMAGE_OUTPUT *blt; + EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixel; + unsigned int height; + unsigned int x; + unsigned int y; + uint8_t bitmask; + size_t offset; + EFI_STATUS efirc; + int rc; + + /* Clear existing glyph */ + offset = ( index * efifb.font.height ); + memset_user ( efifb.glyphs, offset, 0, efifb.font.height ); + + /* Get glyph */ + blt = NULL; + if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, character, + NULL, &blt, NULL ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( &efifb, "EFIFB could not get glyph %#02x: %s\n", + character, strerror ( rc ) ); + goto err_get; + } + assert ( blt != NULL ); + + /* Sanity check */ + if ( blt->Width > 8 ) { + DBGC ( &efifb, "EFIFB glyph %#02x invalid width %d\n", + character, blt->Width ); + rc = -EINVAL; + goto err_width; + } + + /* Convert glyph to bitmap */ + pixel = blt->Image.Bitmap; + height = blt->Height; + for ( y = 0 ; ( ( y < height ) && ( y < efifb.font.height ) ) ; y++ ) { + bitmask = 0; + for ( x = 0 ; x < blt->Width ; x++ ) { + bitmask = rol8 ( bitmask, 1 ); + if ( pixel->Blue || pixel->Green || pixel->Red ) + bitmask |= 0x01; + pixel++; + } + bitmask ^= toggle; + copy_to_user ( efifb.glyphs, offset++, &bitmask, + sizeof ( bitmask ) ); + } + + /* Free glyph */ + bs->FreePool ( blt ); + + return height; + + err_width: + bs->FreePool ( blt ); + err_get: + return rc; +} + +/** + * Draw "unknown character" glyph + * + * @v index Index within glyph cache + * @ret rc Return status code + */ +static int efifb_draw_unknown ( unsigned int index ) { + + /* Draw an inverted '?' glyph */ + return efifb_draw ( '?', index, -1U ); +} + +/** + * Get character glyph + * + * @v character Unicode character * @v glyph Character glyph to fill in */ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) { - size_t offset = ( character * efifb.font.height ); + unsigned int index; + size_t offset; + + /* Identify glyph */ + if ( character < EFIFB_ASCII ) { + + /* ASCII character: use fixed cache entry */ + index = character; + } else { + + /* Non-ASCII character: use an "unknown" glyph */ + index = 0; + } + + /* Copy cached glyph */ + offset = ( index * efifb.font.height ); copy_from_user ( glyph, efifb.glyphs, offset, efifb.font.height ); } @@ -109,16 +210,10 @@ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) { * @ret rc Return status code */ static int efifb_glyphs ( void ) { - EFI_BOOT_SERVICES *bs = efi_systab->BootServices; - EFI_IMAGE_OUTPUT *blt; - EFI_GRAPHICS_OUTPUT_BLT_PIXEL *pixel; - size_t offset; - size_t len; - uint8_t bitmask; unsigned int character; - unsigned int x; - unsigned int y; - EFI_STATUS efirc; + int height; + int max; + size_t len; int rc; /* Get font height. The GetFontInfo() call nominally returns @@ -128,38 +223,32 @@ static int efifb_glyphs ( void ) { * height. */ efifb.font.height = 0; - for ( character = 0 ; character < 256 ; character++ ) { + max = 0; + for ( character = 0 ; character < EFIFB_ASCII ; character++ ) { /* Skip non-printable characters */ if ( ! isprint ( character ) ) continue; /* Get glyph */ - blt = NULL; - if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, - character, NULL, &blt, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not get glyph %d: %s\n", - character, strerror ( rc ) ); - continue; + height = efifb_draw ( character, 0, 0 ); + if ( height < 0 ) { + rc = height; + goto err_height; } - assert ( blt != NULL ); /* Calculate maximum height */ - if ( efifb.font.height < blt->Height ) - efifb.font.height = blt->Height; - - /* Free glyph */ - bs->FreePool ( blt ); + if ( max < height ) + max = height; } - if ( ! efifb.font.height ) { + if ( ! max ) { DBGC ( &efifb, "EFIFB could not get font height\n" ); return -ENOENT; } + efifb.font.height = max; /* Allocate glyph data */ - len = ( 256 * efifb.font.height * sizeof ( bitmask ) ); + len = ( EFIFB_ASCII * efifb.font.height ); efifb.glyphs = umalloc ( len ); if ( ! efifb.glyphs ) { rc = -ENOMEM; @@ -168,60 +257,29 @@ static int efifb_glyphs ( void ) { memset_user ( efifb.glyphs, 0, 0, len ); /* Get font data */ - for ( character = 0 ; character < 256 ; character++ ) { + for ( character = 0 ; character < EFIFB_ASCII ; character++ ) { /* Skip non-printable characters */ - if ( ! isprint ( character ) ) - continue; - - /* Get glyph */ - blt = NULL; - if ( ( efirc = efifb.hiifont->GetGlyph ( efifb.hiifont, - character, NULL, &blt, - NULL ) ) != 0 ) { - rc = -EEFI ( efirc ); - DBGC ( &efifb, "EFIFB could not get glyph %d: %s\n", - character, strerror ( rc ) ); - continue; - } - assert ( blt != NULL ); - - /* Sanity check */ - if ( blt->Width > 8 ) { - DBGC ( &efifb, "EFIFB glyph %d invalid width %d\n", - character, blt->Width ); - continue; - } - if ( blt->Height > efifb.font.height ) { - DBGC ( &efifb, "EFIFB glyph %d invalid height %d\n", - character, blt->Height ); + if ( ! isprint ( character ) ) { + efifb_draw_unknown ( character ); continue; } - /* Convert glyph to bitmap */ - pixel = blt->Image.Bitmap; - offset = ( character * efifb.font.height ); - for ( y = 0 ; y < blt->Height ; y++ ) { - bitmask = 0; - for ( x = 0 ; x < blt->Width ; x++ ) { - bitmask = rol8 ( bitmask, 1 ); - if ( pixel->Blue || pixel->Green || pixel->Red ) - bitmask |= 0x01; - pixel++; - } - copy_to_user ( efifb.glyphs, offset++, &bitmask, - sizeof ( bitmask ) ); + /* Get glyph */ + height = efifb_draw ( character, character, 0 ); + if ( height < 0 ) { + rc = height; + goto err_draw; } - - /* Free glyph */ - bs->FreePool ( blt ); } efifb.font.glyph = efifb_glyph; return 0; + err_draw: ufree ( efifb.glyphs ); err_alloc: + err_height: return rc; } -- cgit v1.2.3-55-g7522 From 27825e555746c379ac045466f692ed77686af2b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 23 Mar 2022 14:39:11 +0000 Subject: [acpi] Allow for the possibility of overriding ACPI tables at link time Allow for linked-in code to override the mechanism used to locate an ACPI table, thereby opening up the possibility of ACPI self-tests. Signed-off-by: Michael Brown --- src/arch/x86/interface/pcbios/acpi_timer.c | 2 +- src/arch/x86/interface/pcbios/acpipwr.c | 2 +- src/core/acpi.c | 22 ++++++++++++++++++++-- src/core/acpi_settings.c | 2 +- src/include/ipxe/acpi.h | 3 +++ 5 files changed, 26 insertions(+), 5 deletions(-) (limited to 'src/arch/x86/interface/pcbios') diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c index 82e85a034..2e4047e38 100644 --- a/src/arch/x86/interface/pcbios/acpi_timer.c +++ b/src/arch/x86/interface/pcbios/acpi_timer.c @@ -107,7 +107,7 @@ static int acpi_timer_probe ( void ) { unsigned int pm_tmr_blk; /* Locate FADT */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( ! fadt ) { DBGC ( &acpi_timer, "ACPI could not find FADT\n" ); return -ENOENT; diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c index 3dac6b605..f08b4af25 100644 --- a/src/arch/x86/interface/pcbios/acpipwr.c +++ b/src/arch/x86/interface/pcbios/acpipwr.c @@ -123,7 +123,7 @@ int acpi_poweroff ( void ) { int rc; /* Locate FADT */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( ! fadt ) { DBGC ( colour, "ACPI could not find FADT\n" ); return -ENOENT; diff --git a/src/core/acpi.c b/src/core/acpi.c index aa486da93..526bf8555 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -38,6 +38,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Colour for debug messages */ #define colour FADT_SIGNATURE +/** ACPI table finder + * + * May be overridden at link time to inject tables for testing. + */ +typeof ( acpi_find ) *acpi_finder __attribute__ (( weak )) = acpi_find; + /****************************************************************************** * * Utility functions @@ -82,6 +88,18 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { acpi->checksum -= acpi_checksum ( virt_to_user ( acpi ) ); } +/** + * Locate ACPI table + * + * @v signature Requested table signature + * @v index Requested index of table with this signature + * @ret table Table, or UNULL if not found + */ +userptr_t acpi_table ( uint32_t signature, unsigned int index ) { + + return ( *acpi_finder ) ( signature, index ); +} + /** * Locate ACPI table via RSDT * @@ -230,7 +248,7 @@ int acpi_extract ( uint32_t signature, void *data, int rc; /* Try DSDT first */ - fadt = acpi_find ( FADT_SIGNATURE, 0 ); + fadt = acpi_table ( FADT_SIGNATURE, 0 ); if ( fadt ) { copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); dsdt = phys_to_user ( fadtab.dsdt ); @@ -241,7 +259,7 @@ int acpi_extract ( uint32_t signature, void *data, /* Try all SSDTs */ for ( i = 0 ; ; i++ ) { - ssdt = acpi_find ( SSDT_SIGNATURE, i ); + ssdt = acpi_table ( SSDT_SIGNATURE, i ); if ( ! ssdt ) break; if ( ( rc = acpi_zsdt ( ssdt, signature, data, diff --git a/src/core/acpi_settings.c b/src/core/acpi_settings.c index 7ba2e979f..b9e2b7f61 100644 --- a/src/core/acpi_settings.c +++ b/src/core/acpi_settings.c @@ -88,7 +88,7 @@ static int acpi_settings_fetch ( struct settings *settings, acpi_name ( tag_signature ), tag_index, tag_offset, tag_len ); /* Locate ACPI table */ - table = acpi_find ( tag_signature, tag_index ); + table = acpi_table ( tag_signature, tag_index ); if ( ! table ) return -ENOENT; diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index 7df3ec21c..c34681238 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -386,7 +386,10 @@ acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) +extern userptr_t ( * acpi_finder ) ( uint32_t signature, unsigned int index ); + extern void acpi_fix_checksum ( struct acpi_header *acpi ); +extern userptr_t acpi_table ( uint32_t signature, unsigned int index ); extern int acpi_extract ( uint32_t signature, void *data, int ( * extract ) ( userptr_t zsdt, size_t len, size_t offset, void *data ) ); -- cgit v1.2.3-55-g7522