[console] Fix definition of unreachability for remapped keys

The AltGr remapping table is constructed to include only keys that are
not reachable after applying the basic remapping table.  The logic
currently fails to include keys that are omitted entirely from the
basic remapping table since they would map to a non-ASCII character.

Fix this logic by allowing the remapping tables to include null
mappings, which are then elided only at the point of constructing the
C code fragment.

Reported-by: Christian Nilsson <nikize@gmail.com>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
pull/591/head
Michael Brown 2022-02-15 16:41:19 +00:00
parent 4a37b05008
commit 419b2e71da
19 changed files with 137 additions and 23 deletions

View File

@ -37,10 +37,15 @@ static struct keymap_key al_basic[] = {
/** "al" AltGr remapping */
static struct keymap_key al_altgr[] = {
{ 0x21, 0x7e }, /* '!' => '~' */
{ 0x26, 0x60 }, /* '&' => '`' */
{ 0x30, 0x7e }, /* '0' => '~' */
{ 0x31, 0x7e }, /* '1' => '~' */
{ 0x34, 0x7e }, /* '4' => '~' */
{ 0x37, 0x60 }, /* '7' => '`' */
{ 0x3a, 0x7e }, /* ':' => '~' */
{ 0x56, 0x60 }, /* 'V' => '`' */
{ 0x7c, 0x7e }, /* '|' => '~' */
{ 0, 0 }
};

View File

@ -33,6 +33,7 @@ static struct keymap_key cf_altgr[] = {
{ 0x27, 0x7b }, /* '\'' => '{' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x3b, 0x7e }, /* ';' => '~' */
{ 0x5c, 0x7d }, /* '\\' => '}' */
{ 0x60, 0x5c }, /* '`' => '\\' */
{ 0, 0 }
};

View File

@ -50,6 +50,9 @@ static struct keymap_key cz_basic[] = {
/** "cz" AltGr remapping */
static struct keymap_key cz_altgr[] = {
{ 0x21, 0x7e }, /* '!' => '~' */
{ 0x24, 0x7e }, /* '$' => '~' */
{ 0x29, 0x7e }, /* ')' => '~' */
{ 0x2c, 0x3c }, /* ',' => '<' */
{ 0x2e, 0x3e }, /* '.' => '>' */
{ 0x2f, 0x2a }, /* '/' => '*' */
@ -60,10 +63,15 @@ static struct keymap_key cz_altgr[] = {
{ 0x37, 0x26 }, /* '7' => '&' */
{ 0x38, 0x2a }, /* '8' => '*' */
{ 0x39, 0x7b }, /* '9' => '{' */
{ 0x3a, 0x7e }, /* ':' => '~' */
{ 0x3b, 0x24 }, /* ';' => '$' */
{ 0x4b, 0x26 }, /* 'K' => '&' */
{ 0x58, 0x3e }, /* 'X' => '>' */
{ 0x5a, 0x3c }, /* 'Z' => '<' */
{ 0x61, 0x7e }, /* 'a' => '~' */
{ 0x62, 0x7b }, /* 'b' => '{' */
{ 0x63, 0x26 }, /* 'c' => '&' */
{ 0x66, 0x5b }, /* 'f' => '[' */
{ 0x67, 0x5d }, /* 'g' => ']' */
{ 0x6e, 0x7d }, /* 'n' => '}' */
{ 0x76, 0x40 }, /* 'v' => '@' */

View File

@ -47,8 +47,13 @@ static struct keymap_key de_basic[] = {
static struct keymap_key de_altgr[] = {
{ 0x2d, 0x5c }, /* '-' => '\\' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x3b, 0x7e }, /* ';' => '~' */
{ 0x5d, 0x7e }, /* ']' => '~' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0x7c, 0x7e }, /* '|' => '~' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }
};

View File

@ -39,7 +39,14 @@ static struct keymap_key dk_basic[] = {
static struct keymap_key dk_altgr[] = {
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x34, 0x24 }, /* '4' => '$' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x3a, 0x7e }, /* ':' => '~' */
{ 0x3d, 0x7c }, /* '=' => '|' */
{ 0x5c, 0x7e }, /* '\\' => '~' */
{ 0x5d, 0x7e }, /* ']' => '~' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0, 0 }
};

View File

@ -37,14 +37,27 @@ static struct keymap_key es_basic[] = {
/** "es" AltGr remapping */
static struct keymap_key es_altgr[] = {
{ 0x22, 0x7b }, /* '"' => '{' */
{ 0x27, 0x7b }, /* '\'' => '{' */
{ 0x2b, 0x7e }, /* '+' => '~' */
{ 0x2d, 0x5c }, /* '-' => '\\' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x31, 0x7c }, /* '1' => '|' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x33, 0x23 }, /* '3' => '#' */
{ 0x34, 0x7e }, /* '4' => '~' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x3a, 0x7e }, /* ':' => '~' */
{ 0x3b, 0x7e }, /* ';' => '~' */
{ 0x3d, 0x7e }, /* '=' => '~' */
{ 0x5c, 0x7d }, /* '\\' => '}' */
{ 0x60, 0x5c }, /* '`' => '\\' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0x7c, 0x7e }, /* '|' => '~' */
{ 0x7e, 0x5c }, /* '~' => '\\' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }
};

View File

@ -35,8 +35,18 @@ static struct keymap_key et_basic[] = {
/** "et" AltGr remapping */
static struct keymap_key et_altgr[] = {
{ 0x26, 0x7b }, /* '&' => '{' */
{ 0x28, 0x5d }, /* '(' => ']' */
{ 0x29, 0x7d }, /* ')' => '}' */
{ 0x2a, 0x5b }, /* '*' => '[' */
{ 0x2d, 0x5c }, /* '-' => '\\' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x34, 0x24 }, /* '4' => '$' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x5f, 0x5c }, /* '_' => '\\' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }
};

View File

@ -38,6 +38,12 @@ static struct keymap_key fi_altgr[] = {
{ 0x2d, 0x5c }, /* '-' => '\\' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x34, 0x24 }, /* '4' => '$' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x49, 0x7c }, /* 'I' => '|' */
{ 0x5d, 0x7e }, /* ']' => '~' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }
};

View File

@ -68,9 +68,15 @@ static struct keymap_key fr_altgr[] = {
{ 0x2d, 0x5d }, /* '-' => ']' */
{ 0x30, 0x40 }, /* '0' => '@' */
{ 0x33, 0x23 }, /* '3' => '#' */
{ 0x34, 0x7b }, /* '4' => '{' */
{ 0x35, 0x5b }, /* '5' => '[' */
{ 0x36, 0x7c }, /* '6' => '|' */
{ 0x37, 0x60 }, /* '7' => '`' */
{ 0x38, 0x5c }, /* '8' => '\\' */
{ 0x3d, 0x7d }, /* '=' => '}' */
{ 0x5c, 0x60 }, /* '\\' => '`' */
{ 0x61, 0x40 }, /* 'a' => '@' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }
};

View File

@ -37,18 +37,36 @@ static struct keymap_key hu_basic[] = {
/** "hu" AltGr remapping */
static struct keymap_key hu_altgr[] = {
{ 0x21, 0x7e }, /* '!' => '~' */
{ 0x23, 0x5e }, /* '#' => '^' */
{ 0x26, 0x60 }, /* '&' => '`' */
{ 0x2c, 0x3b }, /* ',' => ';' */
{ 0x2e, 0x3e }, /* '.' => '>' */
{ 0x2f, 0x2a }, /* '/' => '*' */
{ 0x30, 0x7e }, /* '0' => '~' */
{ 0x31, 0x7e }, /* '1' => '~' */
{ 0x32, 0x5e }, /* '2' => '^' */
{ 0x33, 0x5e }, /* '3' => '^' */
{ 0x34, 0x7e }, /* '4' => '~' */
{ 0x37, 0x60 }, /* '7' => '`' */
{ 0x3b, 0x24 }, /* ';' => '$' */
{ 0x4b, 0x26 }, /* 'K' => '&' */
{ 0x58, 0x3e }, /* 'X' => '>' */
{ 0x5a, 0x3c }, /* 'Z' => '<' */
{ 0x62, 0x7b }, /* 'b' => '{' */
{ 0x63, 0x26 }, /* 'c' => '&' */
{ 0x66, 0x5b }, /* 'f' => '[' */
{ 0x67, 0x5d }, /* 'g' => ']' */
{ 0x6d, 0x3c }, /* 'm' => '<' */
{ 0x6e, 0x7d }, /* 'n' => '}' */
{ 0x71, 0x5c }, /* 'q' => '\\' */
{ 0x76, 0x40 }, /* 'v' => '@' */
{ 0x77, 0x7c }, /* 'w' => '|' */
{ 0x78, 0x23 }, /* 'x' => '#' */
{ 0x7a, 0x3e }, /* 'z' => '>' */
{ 0x7c, 0x7e }, /* '|' => '~' */
{ 0xdc, 0x3c }, /* Pseudo-'\\' => '<' */
{ 0xfc, 0x3e }, /* Pseudo-'|' => '>' */
{ 0, 0 }
};

View File

@ -37,13 +37,19 @@ static struct keymap_key it_basic[] = {
/** "it" AltGr remapping */
static struct keymap_key it_altgr[] = {
{ 0x23, 0x7e }, /* '#' => '~' */
{ 0x27, 0x23 }, /* '\'' => '#' */
{ 0x2d, 0x60 }, /* '-' => '`' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x3b, 0x40 }, /* ';' => '@' */
{ 0x3d, 0x7e }, /* '=' => '~' */
{ 0x40, 0x7e }, /* '@' => '~' */
{ 0x5c, 0x60 }, /* '\\' => '`' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0x7c, 0x7e }, /* '|' => '~' */
{ 0, 0 }
};

View File

@ -17,6 +17,10 @@ static struct keymap_key lt_basic[] = {
/** "lt" AltGr remapping */
static struct keymap_key lt_altgr[] = {
{ 0x22, 0x5e }, /* '"' => '^' */
{ 0x27, 0x5e }, /* '\'' => '^' */
{ 0x4b, 0x26 }, /* 'K' => '&' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0, 0 }
};

View File

@ -22,6 +22,11 @@ static struct keymap_key mt_basic[] = {
/** "mt" AltGr remapping */
static struct keymap_key mt_altgr[] = {
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x5c, 0x60 }, /* '\\' => '`' */
{ 0, 0 }
};

View File

@ -39,10 +39,15 @@ static struct keymap_key no_latin1_basic[] = {
/** "no-latin1" AltGr remapping */
static struct keymap_key no_latin1_altgr[] = {
{ 0x22, 0x5b }, /* '"' => '[' */
{ 0x27, 0x7b }, /* '\'' => '{' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x5b, 0x7d }, /* '[' => '}' */
{ 0x7b, 0x5d }, /* '{' => ']' */
{ 0, 0 }
};

View File

@ -41,6 +41,13 @@ static struct keymap_key no_basic[] = {
static struct keymap_key no_altgr[] = {
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x34, 0x24 }, /* '4' => '$' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x3a, 0x7e }, /* ':' => '~' */
{ 0x5c, 0x7e }, /* '\\' => '~' */
{ 0x5d, 0x7e }, /* ']' => '~' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0, 0 }
};

View File

@ -44,6 +44,7 @@ static struct keymap_key pt_altgr[] = {
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0, 0 }
};

View File

@ -40,6 +40,11 @@ static struct keymap_key se_altgr[] = {
{ 0x2d, 0x5c }, /* '-' => '\\' */
{ 0x30, 0x7d }, /* '0' => '}' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x34, 0x24 }, /* '4' => '$' */
{ 0x37, 0x7b }, /* '7' => '{' */
{ 0x38, 0x5b }, /* '8' => '[' */
{ 0x39, 0x5d }, /* '9' => ']' */
{ 0x5d, 0x7e }, /* ']' => '~' */
{ 0x71, 0x40 }, /* 'q' => '@' */
{ 0xdc, 0x7c }, /* Pseudo-'\\' => '|' */
{ 0, 0 }

View File

@ -45,9 +45,11 @@ static struct keymap_key sg_basic[] = {
/** "sg" AltGr remapping */
static struct keymap_key sg_altgr[] = {
{ 0x27, 0x7b }, /* '\'' => '{' */
{ 0x32, 0x40 }, /* '2' => '@' */
{ 0x33, 0x23 }, /* '3' => '#' */
{ 0x37, 0x7c }, /* '7' => '|' */
{ 0x3d, 0x7e }, /* '=' => '~' */
{ 0x5c, 0x7d }, /* '\\' => '}' */
{ 0, 0 }
};

View File

@ -33,6 +33,10 @@ import textwrap
from typing import ClassVar, Optional
BACKSPACE = chr(0x7f)
"""Backspace character"""
class KeyType(IntEnum):
"""Key types"""
@ -174,7 +178,7 @@ class KeyLayout(UserDict[KeyModifiers, Sequence[Key]]):
KeyModifiers.NONE: [(KEY_NON_US, ord('\\'))],
KeyModifiers.SHIFT: [(KEY_NON_US, ord('|'))],
# Treat Ctrl-Backspace as producing Backspace rather than Ctrl-H
KeyModifiers.CTRL: [(KEY_BACKSPACE, 0x7f)],
KeyModifiers.CTRL: [(KEY_BACKSPACE, ord(BACKSPACE))],
},
'il': {
# Redefine some otherwise unreachable ASCII characters
@ -200,11 +204,6 @@ 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'"""
@ -281,7 +280,7 @@ class BiosKeyLayout(KeyLayout):
return inverse
class KeymapKeys(UserDict[str, str]):
class KeymapKeys(UserDict[str, Optional[str]]):
"""An ASCII character remapping"""
@classmethod
@ -312,7 +311,8 @@ 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)
if target
and ord(source) & ~BiosKeyLayout.KEY_PSEUDO != ord(target)
) + '\t{ 0, 0 }\n}'
@ -335,13 +335,12 @@ class Keymap:
# Construct raw mapping from source ASCII to target ASCII
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
# Eliminate any identity mappings, or mappings that attempt to
# remap the backspace key
table = {source: target for source, target in raw.items()
if target
and ord(source) != 0x7f
and ord(target) != 0x7f
and source != target}
if source != target
and source != BACKSPACE
and target != BACKSPACE}
# Recursively delete any mappings that would produce
# unreachable alphanumerics (e.g. the "il" keymap, which maps
# away the whole lower-case alphabet)
@ -354,8 +353,8 @@ class Keymap:
# Sanity check: ensure that all numerics are reachable using
# the same shift state
digits = '1234567890'
unshifted = ''.join(table.get(x, x) for x in '1234567890')
shifted = ''.join(table.get(x, x) for x in '!@#$%^&*()')
unshifted = ''.join(table.get(x) or x for x in '1234567890')
shifted = ''.join(table.get(x) or x for x in '!@#$%^&*()')
if digits not in (shifted, unshifted):
raise ValueError("Inconsistent numeric remapping %s / %s" %
(unshifted, shifted))
@ -365,21 +364,22 @@ class Keymap:
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}
raw = {
source:
self.target.get((key.modifiers | KeyModifiers.ALTGR),
self.target[key.modifiers])[key.keycode].ascii
for source, key in self.source.inverse.items()
}
# 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
# Eliminate any 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}
# Check that all characters are now reachable
unreachable -= set(table.values())