*/
#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
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;
}
}
}
+ /* Clear pseudo key flag */
+ character &= ~KEYMAP_PSEUDO;
+
return character;
}
};
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 ) ) {
USBKBD_KEY_PAD_ENTER = 0x58,
USBKBD_KEY_PAD_1 = 0x59,
USBKBD_KEY_PAD_DOT = 0x63,
+ USBKBD_KEY_NON_US = 0x64,
};
/** USB keyboard LEDs */
{ 0x7c, 0x7d }, /* '|' => '}' */
{ 0x7d, 0x27 }, /* '}' => '\'' */
{ 0x7e, 0x7c }, /* '~' => '|' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x40, 0x22 }, /* '@' => '"' */
{ 0x5e, 0x3a }, /* '^' => ':' */
{ 0x7c, 0x2f }, /* '|' => '/' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "by" keyboard mapping */
struct key_mapping by_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x7a, 0x79 }, /* 'z' => 'y' */
{ 0x7c, 0x27 }, /* '|' => '\'' */
{ 0x7d, 0x2a }, /* '}' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x5e, 0x26 }, /* '^' => '&' */
{ 0x5f, 0x3f }, /* '_' => '?' */
{ 0x7c, 0x2a }, /* '|' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x5e, 0x26 }, /* '^' => '&' */
{ 0x5f, 0x3f }, /* '_' => '?' */
{ 0x7d, 0x2a }, /* '}' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x5e, 0x26 }, /* '^' => '&' */
{ 0x5f, 0x3f }, /* '_' => '?' */
{ 0x7c, 0x2a }, /* '|' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x5e, 0x26 }, /* '^' => '&' */
{ 0x5f, 0x3f }, /* '_' => '?' */
{ 0x7c, 0x2a }, /* '|' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x71, 0x61 }, /* 'q' => 'a' */
{ 0x77, 0x7a }, /* 'w' => 'z' */
{ 0x7a, 0x77 }, /* 'z' => 'w' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "gr" keyboard mapping */
struct key_mapping gr_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x60, 0x3b }, /* '`' => ';' */
{ 0x7b, 0x7d }, /* '{' => '}' */
{ 0x7d, 0x7b }, /* '}' => '{' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x60, 0x5c }, /* '`' => '\\' */
{ 0x7d, 0x2a }, /* '}' => '*' */
{ 0x7e, 0x7c }, /* '~' => '|' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "mk" keyboard mapping */
struct key_mapping mk_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x60, 0x40 }, /* '`' => '@' */
{ 0x7c, 0x3e }, /* '|' => '>' */
{ 0x7d, 0x7c }, /* '}' => '|' */
+ { 0xdc, 0x5d }, /* Pseudo-'\\' => ']' */
+ { 0xfc, 0x5b }, /* Pseudo-'|' => '[' */
};
{ 0x60, 0x7c }, /* '`' => '|' */
{ 0x7c, 0x2a }, /* '|' => '*' */
{ 0x7d, 0x5e }, /* '}' => '^' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x5f, 0x3f }, /* '_' => '?' */
{ 0x60, 0x7c }, /* '`' => '|' */
{ 0x7c, 0x2a }, /* '|' => '*' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "pl" keyboard mapping */
struct key_mapping pl_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x60, 0x5c }, /* '`' => '\\' */
{ 0x7b, 0x2a }, /* '{' => '*' */
{ 0x7e, 0x7c }, /* '~' => '|' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "ru" keyboard mapping */
struct key_mapping ru_mapping[] __keymap = {
{ 0x0d, 0x0a }, /* Ctrl-M => Ctrl-J */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
{ 0x7a, 0x79 }, /* 'z' => 'y' */
{ 0x7c, 0x24 }, /* '|' => '$' */
{ 0x7d, 0x21 }, /* '}' => '!' */
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "sr-latin" keyboard mapping */
struct key_mapping sr_latin_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** "ua" keyboard mapping */
struct key_mapping ua_mapping[] __keymap = {
+ { 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
+ { 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
};
/** 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 */
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())
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)
"""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: