boot,vconsole: Propagate UEFI HII keyboard layout to the OS
UEFI firmware can report the currently-active keyboard layout via EFI_HII_DATABASE_PROTOCOL.GetKeyboardLayout(). The layout descriptor includes an RFC 4646 / BCP 47 language tag (e.g. "en-US"). Query this from sd-boot/sd-stub and write it to a new LoaderKeyboardLayout EFI variable, advertised through a new EFI_LOADER_FEATURE_KEYBOARD_LAYOUT feature bit. On the OS side, systemd-vconsole-setup reads the variable as a lowest-priority fallback for the console keymap. To map the BCP 47 tag to a vconsole keymap we extend /usr/share/systemd/kbd-model-map with an optional sixth column listing the comma-separated BCP 47 tags each row covers; a new find_vconsole_keymap_for_bcp47() helper walks the file, preferring an exact tag match and otherwise falling back to the row whose tag matches the input's primary subtag. Credentials, /etc/vconsole.conf, and vconsole.keymap= on the kernel command line continue to take precedence. bootctl status surfaces the new variable, printing the language tag or "n/a (not reported by firmware)" when sd-boot advertises the feature but the firmware HII database didn't expose a layout (common on QEMU without a USB keyboard, since EDK2's PS/2 driver does not register an HII keyboard layout).
This commit is contained in:
committed by
Daan De Meyer
parent
6f49c7e598
commit
7b9d76cba7
@@ -578,6 +578,83 @@ int find_language_fallback(const char *lang, char **ret) {
|
||||
}
|
||||
}
|
||||
|
||||
int find_vconsole_keymap_for_bcp47(const char *tag, char **ret) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *fallback = NULL;
|
||||
const char *map;
|
||||
int r;
|
||||
|
||||
/* Look up a vconsole keymap by RFC 4646 / BCP 47 language tag (e.g. "de-DE") using the optional
|
||||
* sixth column of /usr/share/systemd/kbd-model-map. That column lists comma-separated tags the
|
||||
* row matches. An exact (case-insensitive) tag match returns immediately; if no exact match
|
||||
* exists, the first row whose tag matches the input's primary subtag wins. Returns 1 on match,
|
||||
* 0 otherwise. */
|
||||
|
||||
assert(tag);
|
||||
assert(ret);
|
||||
|
||||
if (isempty(tag)) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t primary_len = strcspn(tag, "-");
|
||||
if (primary_len == 0) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
map = systemd_kbd_model_map();
|
||||
f = fopen(map, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (unsigned n = 0;;) {
|
||||
_cleanup_strv_free_ char **a = NULL, **tags = NULL;
|
||||
|
||||
r = read_next_mapping(map, 5, UINT_MAX, f, &n, &a);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
/* The BCP 47 tag list is the optional 6th column. "-" / empty means "no tags". */
|
||||
if (strv_length(a) < 6 || isempty(a[5]) || streq(a[5], "-"))
|
||||
continue;
|
||||
|
||||
r = strv_split_full(&tags, a[5], ",", /* flags= */ 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
STRV_FOREACH(t, tags) {
|
||||
if (strcaseeq(*t, tag)) {
|
||||
log_debug("Found vconsole keymap '%s' for BCP 47 tag '%s' (exact match).",
|
||||
a[0], tag);
|
||||
|
||||
r = strdup_to(ret, a[0]);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
if (!fallback && strlen(*t) == primary_len && !strchr(*t, '-') && strncaseeq(*t, tag, primary_len)) {
|
||||
fallback = strdup(a[0]);
|
||||
if (!fallback)
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fallback) {
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("Found vconsole keymap '%s' for BCP 47 tag '%s' (primary subtag match).", fallback, tag);
|
||||
*ret = TAKE_PTR(fallback);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int vconsole_serialize(const VCContext *vc, const X11Context *xc, char ***env) {
|
||||
int r;
|
||||
|
||||
|
||||
@@ -39,4 +39,6 @@ typedef int (*X11VerifyCallback)(const X11Context *xc);
|
||||
int vconsole_convert_to_x11(const VCContext *vc, X11VerifyCallback verify, X11Context *ret);
|
||||
int x11_convert_to_vconsole(const X11Context *xc, VCContext *ret);
|
||||
|
||||
int find_vconsole_keymap_for_bcp47(const char *tag, char **ret);
|
||||
|
||||
int vconsole_serialize(const VCContext *vc, const X11Context *xc, char ***env);
|
||||
|
||||
Reference in New Issue
Block a user