Skip to content

Commit

Permalink
egui-winit: emit physical key presses when a non-Latin layout is acti…
Browse files Browse the repository at this point in the history
…ve (#4461)

resolves #4081 (see discussion
starting from
#3653 (comment) 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.
  • Loading branch information
TicClick committed May 10, 2024
1 parent f19f991 commit 2b2e70c
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 8 deletions.
14 changes: 9 additions & 5 deletions crates/egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -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!
Expand Down
8 changes: 5 additions & 3 deletions crates/egui/src/data/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 2b2e70c

Please sign in to comment.