From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1ohlSH-0003J8-1E for mharc-grub-devel@gnu.org; Mon, 10 Oct 2022 01:35:57 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:35098) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1ohlSF-0003Ix-9A for grub-devel@gnu.org; Mon, 10 Oct 2022 01:35:55 -0400 Received: from mail-qk1-x733.google.com ([2607:f8b0:4864:20::733]:33756) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1ohlSD-00074J-A8 for grub-devel@gnu.org; Mon, 10 Oct 2022 01:35:54 -0400 Received: by mail-qk1-x733.google.com with SMTP id a18so3225462qko.0 for ; Sun, 09 Oct 2022 22:35:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:from:to:cc:subject:date:message-id:reply-to; bh=UZlnl0/PrU7HcvK0rtrGnhwWd3JR0M1ZLHwG15lgpdY=; b=ErT1CE3z2DlOSF75qDS4WDyQJhVvkHq7+T7K7OtLRQ5bxOAbkxfIaJidnDWHfwL6Q2 QGEbH3oaTtZVxoXrOKceknFK0PzlVcEHu+y4vMoQuOOZ/Qh8P6ig8VHIyC2oXime8UNn HGbNYd5/CMEU1LB/pRwShHvByFWSkGGAN3pus90NpvYWVoQv/XQGjFSRlREQqI4/8xOS zAjx8G/7c3Q6D8NZz65BV44Of1/6LWTm7ujuV3n10zq6kiRkjQmOr8W5oypYnr3dOtxq CYMLDxMRXd91U6H4V92dd6FXNxYW02oiRY1vGq/ApTlQA38Oh7KZGsYc0E35i+TbENC/ YQTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=UZlnl0/PrU7HcvK0rtrGnhwWd3JR0M1ZLHwG15lgpdY=; b=dxRHVDWCgtbEQlUHaDQ9ubni3N7bkv302ILDyZKGHcw9NmDFcJRiHQWjem6DEfCgxN JMyERfp7bs3bRXHVJmglbhGPeeC/mZvDHQRjAGOKwsKZTVP3T/zaJk9PwGI1Fsd/stoC t4lo099abx3XzZMcD4ipPPE48yv8OsKHVwZjJUQxJDJsyfjdyiRnQKqH8kEzBI00/KY9 /mHtr0rIP3xUS4PhpOCGlENE/OKqd8rMAMYG8TPPQYwgzIRj3Oe6xyiaH2wRpZhCtOeu b88ke6cOWQN71nxVtcMMdTpfIp6lNY8cEVt2AoDrG74R2OBf9fIupA0Ip0n4+eSp1hT/ roCw== X-Gm-Message-State: ACrzQf35S6Bgj5GhZsHv5Kv47lajHxz4Z4r9T1iFXi8Qihz1ebVhP1gP hgqP/N76aiN6oAYGpVgOut6XPOeD0io= X-Google-Smtp-Source: AMsMyM44Ev9/2zRyVRkjTPClfSXJp9okZ6/FmjMqapTMrTmhuQCG/kq/1lFtilGOFjz6F6s3XkVEnA== X-Received: by 2002:a05:620a:1a9d:b0:6cb:e3f3:eb3c with SMTP id bl29-20020a05620a1a9d00b006cbe3f3eb3cmr11487275qkb.711.1665380150770; Sun, 09 Oct 2022 22:35:50 -0700 (PDT) Received: from daniel-desktop2.localnet (bras-base-kntaon1614w-grc-40-76-67-74-208.dsl.bell.ca. [76.67.74.208]) by smtp.gmail.com with ESMTPSA id r22-20020ae9d616000000b006ed30a8fb21sm1434093qkk.76.2022.10.09.22.35.50 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 22:35:50 -0700 (PDT) From: Daniel Tang To: grub-devel@gnu.org Subject: [PATCH] term: keymapforce command for lack of at_keyboard Date: Mon, 10 Oct 2022 01:35:49 -0400 Message-ID: <4784685.GXAFRqVoOG@daniel-desktop2> MIME-Version: 1.0 Content-Transfer-Encoding: 7Bit Content-Type: text/plain; charset="us-ascii" Received-SPF: pass client-ip=2607:f8b0:4864:20::733; envelope-from=danielzgtg.opensource@gmail.com; helo=mail-qk1-x733.google.com X-Spam_score_int: 0 X-Spam_score: -0.1 X-Spam_bar: / X-Spam_report: (-0.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, HK_RANDOM_ENVFROM=0.999, HK_RANDOM_FROM=0.999, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 10 Oct 2022 05:35:55 -0000 >From ba4dfde5037743561bafab617f48163e72989d5c Mon Sep 17 00:00:00 2001 From: Daniel Tang Date: Fri, 23 Sep 2022 23:15:16 -0400 Subject: [PATCH] term: keymapforce command for lack of at_keyboard This adds a command named `keymapforce`. Current behaviour is unchanged until it is run. The use case is people with non-QWERTY keyboards on computers without support for anything else than `terminal_input console`. For example, as a Dvorak user on a Microsoft Surface Pro 7, I would like to enter my encryption key at boot in my preferred layout using the UEFI touchscreen keyboard in order to log in when encryption is set up. The new `keymapforce` command is modeled after the `terminal_x` commands without arguments. This feature is disabled by default to avoid regressions, and this command toggles it. A `grub_term_force_keymap` function pointer global variable is used to hook the end of the key reception logic. The new code simulates reverse engineering the intercepted key back into its source on a US keyboard layout, and then replaying the calculated key code on the keyboard with the proper layout. This works around any specific `terminal_input`s that don't support key mapping and insist on passing the character instead of the key code. This way of moving the key remapping to until after the specific terminal handlers was the only viable way of adding support for gettings key mapping working on `terminal_input console`. I wanted to avoid the global hook by adding instead another `terminal_input` type but that would complicate fini and memory safety. I tried to put the code in `console.c` but got linker errors and software architectural obstacles. The reverse lookup is a loop but it's still fast, close to o(1), and what I wanted to do being calculating the inverse of the `layout_us` map manually would be hard to maintain to keep in sync without `static_assert`. This bug has existed for 10 years. Many users are affected by this bug: - bbs.archlinux.org/viewtopic.php?id=240739 - archived.forum.manjaro.org /t/does-luks-in-manjaro-support-azerty-keyboards/87582/6 - bugs.launchpad.net/ubuntu/+source/grub2/+bug/1914953 - www.mail-archive.com /search?l=bug-grub@gnu.org&q=subject:%22RE%5C%3A +Changing+default+keyboard+layout%22&o=newest&f=1 - askubuntu.com/a/1391658/1004020 I have tested the following: - Machines - VirtualBox BIOS Ubuntu 22.04 - surface-linux Ubuntu 22.10 - UEFI touchscreen - Type cover keyboard - Actions - Timeout then boot - Enter to boot normally - `c` to command line then running a few commands - `terminal_input` - `console` - `at_keyboard` - `terminal_output` - `gfxterm` - `console` - `keymap` from `grub-mklayout` - `none` (qwerty) - `dvorak` - `us -variant colemak` - `fr` (azerty) - The accents don't work but the ASCII does. Someone can add Unicode support in another patch. Signed-off-by: Daniel Tang --- grub-core/commands/keylayouts.c | 48 ++++++++++++++++++++++++++++----- grub-core/kern/term.c | 3 +++ include/grub/term.h | 1 + 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/grub-core/commands/keylayouts.c b/grub-core/commands/keylayouts.c index aa3ba34f2..5ca130904 100644 --- a/grub-core/commands/keylayouts.c +++ b/grub-core/commands/keylayouts.c @@ -135,26 +135,30 @@ map_key_core (int code, int status, int *alt_gr_consumed) if (code >= GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE) return 0; + struct grub_keyboard_layout *current_layout = grub_current_layout; + if (grub_term_force_keymap) + current_layout = &layout_us; + if (status & GRUB_TERM_STATUS_RALT) { if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) { - if (grub_current_layout->keyboard_map_shift_l3[code]) + if (current_layout->keyboard_map_shift_l3[code]) { *alt_gr_consumed = 1; - return grub_current_layout->keyboard_map_shift_l3[code]; + return current_layout->keyboard_map_shift_l3[code]; } } - else if (grub_current_layout->keyboard_map_l3[code]) + else if (current_layout->keyboard_map_l3[code]) { *alt_gr_consumed = 1; - return grub_current_layout->keyboard_map_l3[code]; + return current_layout->keyboard_map_l3[code]; } } if (status & (GRUB_TERM_STATUS_LSHIFT | GRUB_TERM_STATUS_RSHIFT)) - return grub_current_layout->keyboard_map_shift[code]; + return current_layout->keyboard_map_shift[code]; else - return grub_current_layout->keyboard_map[code]; + return current_layout->keyboard_map[code]; } unsigned @@ -293,15 +297,45 @@ grub_cmd_keymap (struct grub_command *cmd __attribute__ ((unused)), return grub_errno; } -static grub_command_t cmd; +static unsigned +grub_term_force_map_key (unsigned key) +{ + if (! key) + return GRUB_TERM_NO_KEY; + unsigned i; + for (i = 0; i < GRUB_KEYBOARD_LAYOUTS_ARRAY_SIZE; i++) + // Loop only once so that '+' doesn't go to numpad + if (layout_us.keyboard_map[i] == key) + return grub_current_layout->keyboard_map[i]; + else if (layout_us.keyboard_map_shift[i] == key) + return grub_current_layout->keyboard_map_shift[i]; + return key; // Fallback for enter key +} + +static grub_err_t +grub_cmd_keymap_force (struct grub_command *cmd __attribute__ ((unused)), + int argc __attribute__ ((unused)), char *argv[] __attribute__ ((unused))) +{ + if (grub_term_force_keymap) + grub_term_force_keymap = NULL; + else + grub_term_force_keymap = grub_term_force_map_key; + return GRUB_ERR_NONE; +} + +static grub_command_t cmd, cmd2; GRUB_MOD_INIT(keylayouts) { cmd = grub_register_command ("keymap", grub_cmd_keymap, 0, N_("Load a keyboard layout.")); + cmd2 = grub_register_command ("keymapforce", grub_cmd_keymap_force, + 0, N_("Toggles the keymap strategy.")); } GRUB_MOD_FINI(keylayouts) { + grub_term_force_keymap = NULL; + grub_unregister_command (cmd2); grub_unregister_command (cmd); } diff --git a/grub-core/kern/term.c b/grub-core/kern/term.c index 14d596498..a7dfffb8c 100644 --- a/grub-core/kern/term.c +++ b/grub-core/kern/term.c @@ -34,6 +34,7 @@ grub_uint8_t grub_term_highlight_color = GRUB_TERM_DEFAULT_HIGHLIGHT_COLOR; void (*grub_term_poll_usb) (int wait_for_completion) = NULL; void (*grub_net_poll_cards_idle) (void) = NULL; +unsigned (*grub_term_force_keymap) (unsigned key) = NULL; /* Put a Unicode character. */ static void @@ -97,6 +98,8 @@ grub_getkey_noblock (void) FOR_ACTIVE_TERM_INPUTS(term) { int key = term->getkey (term); + if (grub_term_force_keymap) + key = grub_term_force_keymap (key); if (key != GRUB_TERM_NO_KEY) return key; } diff --git a/include/grub/term.h b/include/grub/term.h index 7f1a14c84..a2fd0b9ca 100644 --- a/include/grub/term.h +++ b/include/grub/term.h @@ -460,6 +460,7 @@ grub_print_spaces (struct grub_term_output *term, int number_spaces) } extern void (*EXPORT_VAR (grub_term_poll_usb)) (int wait_for_completion); +extern unsigned (*EXPORT_VAR (grub_term_force_keymap)) (unsigned key); #define GRUB_TERM_REPEAT_PRE_INTERVAL 400 #define GRUB_TERM_REPEAT_INTERVAL 50 -- 2.37.2