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.
This commit is contained in:
TicClick 2024-05-11 00:07:42 +02:00 committed by GitHub
parent f19f99180e
commit 2b2e70cb91
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 14 additions and 8 deletions

View File

@ -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!

View File

@ -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.