From 2b2e70cb9179eba39f1d306ff70814f68c323ba4 Mon Sep 17 00:00:00 2001 From: TicClick Date: Sat, 11 May 2024 00:07:42 +0200 Subject: [PATCH] egui-winit: emit physical key presses when a non-Latin layout is active (#4461) resolves https://github.com/emilk/egui/issues/4081 (see discussion starting from https://github.com/emilk/egui/issues/3653#issuecomment-1962740175 for extra context) this partly restores event-emitting behaviour to the state before #3649, when shortcuts such as `Ctrl` + `C` used to work regardless of the active layout. the difference is that physical keys are only used in case of the logical ones' absence now among the named keys. while originally I have only limited this to clipboard shortcuts (Ctrl+C/V/X), honestly it felt like a half-assed solution. as a result, I decided to expand this behaviour to all key events to stick to the original logic, in case there are other workflows and hotkeys people rely on or expect to work out of the box. let me know if this is an issue. --- crates/egui-winit/src/lib.rs | 14 +++++++++----- crates/egui/src/data/input.rs | 8 +++++--- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/crates/egui-winit/src/lib.rs b/crates/egui-winit/src/lib.rs index abadd9ee5c2..4ee404e4436 100644 --- a/crates/egui-winit/src/lib.rs +++ b/crates/egui-winit/src/lib.rs @@ -746,15 +746,19 @@ impl State { physical_key ); - if let Some(logical_key) = logical_key { + // "Logical OR physical key" is a fallback mechanism for keyboard layouts without Latin characters: it lets them + // emit events as if the corresponding keys from the Latin layout were pressed. In this case, clipboard shortcuts + // are mapped to the physical keys that normally contain C, X, V, etc. + // See also: https://github.com/emilk/egui/issues/3653 + if let Some(active_key) = logical_key.or(physical_key) { if pressed { - if is_cut_command(self.egui_input.modifiers, logical_key) { + if is_cut_command(self.egui_input.modifiers, active_key) { self.egui_input.events.push(egui::Event::Cut); return; - } else if is_copy_command(self.egui_input.modifiers, logical_key) { + } else if is_copy_command(self.egui_input.modifiers, active_key) { self.egui_input.events.push(egui::Event::Copy); return; - } else if is_paste_command(self.egui_input.modifiers, logical_key) { + } else if is_paste_command(self.egui_input.modifiers, active_key) { if let Some(contents) = self.clipboard.get() { let contents = contents.replace("\r\n", "\n"); if !contents.is_empty() { @@ -766,7 +770,7 @@ impl State { } self.egui_input.events.push(egui::Event::Key { - key: logical_key, + key: active_key, physical_key, pressed, repeat: false, // egui will fill this in for us! diff --git a/crates/egui/src/data/input.rs b/crates/egui/src/data/input.rs index 8217f4f5a4d..2260db1f433 100644 --- a/crates/egui/src/data/input.rs +++ b/crates/egui/src/data/input.rs @@ -361,10 +361,12 @@ pub enum Event { /// A key was pressed or released. Key { - /// The logical key, heeding the users keymap. + /// Most of the time, it's the logical key, heeding the active keymap -- for instance, if the user has Dvorak + /// keyboard layout, it will be taken into account. /// - /// For instance, if the user is using Dvorak keyboard layout, - /// this will take that into account. + /// If it's impossible to determine the logical key on desktop platforms (say, in case of non-Latin letters), + /// `key` falls back to the value of the corresponding physical key. This is necessary for proper work of + /// standard shortcuts that only respond to Latin-based bindings (such as `Ctrl` + `V`). key: Key, /// The physical key, corresponding to the actual position on the keyboard.