keymap: learn nothing from presses while right Alt is held

egui-winit reports AltGr with neither Ctrl nor Alt, so AltGr text read as plain
typing: German AltGr+M (µ) marked the layout as not Latin and Ctrl+Z resolved
by position as Ctrl+Y. µ, ª and º no longer count as a sign of another script.
This commit is contained in:
aiongg committed 2026-10-21 06:08:30 +00:00
1 parent 9c75eda598
commit 1a0e7e7bbf
4 files changed
+37 -3

No files matched your search

+12 -1
View File
@@ -199,6 +199,9 @@ pub struct Dispatcher {
/// web build sends them.
text_first: bool,
layout: Layout,
/// Whether right Alt is held. egui-winit reports AltGr with neither Ctrl nor Alt, so its
/// presses would otherwise teach the layout as plain ones.
right_alt: bool,
}
/// eframe's web build sends a press's Text event first when no text field has focus.
@@ -206,7 +209,7 @@ const TEXT_FIRST: bool = cfg!(target_arch = "wasm32");
impl Default for Dispatcher {
fn default() -> Dispatcher {
Dispatcher { last: None, repeat: false, clipboard: false, text_first: TEXT_FIRST, layout: Layout::new() }
Dispatcher { last: None, repeat: false, clipboard: false, text_first: TEXT_FIRST, layout: Layout::new(), right_alt: false }
}
}
@@ -350,6 +353,14 @@ impl Dispatcher {
/// Teaches the layout what this frame's presses typed.
fn learn(&mut self, events: &[Event], text_of: &[Option<usize>], platform: Platform) {
for (event, text) in events.iter().zip(text_of) {
match event {
Event::Key { physical_key: Some(EguiKey::AltRight), pressed, .. } => self.right_alt = *pressed,
Event::WindowFocused(false) => self.right_alt = false,
_ => {}
}
if self.right_alt {
continue;
}
let Some(Event::Text(text)) = text.and_then(|j| events.get(j)) else { continue };
if let Some(KeyInput { mods, physical: Some(physical), .. }) = KeyInput::from_egui(event, platform) {
self.layout.observe(physical, mods, text);
+2 -1
View File
@@ -179,7 +179,8 @@ impl Layout {
return;
}
if physical.is_letter() {
if c.is_alphabetic() {
// ª, µ and º are Latin-1 symbols on Latin layouts, no sign of another script.
if c.is_alphabetic() && !matches!(c, 'ª' | 'µ' | 'º') {
self.seen_latin = Some(is_latin_letter(c));
}
if !c.is_control() {
+21 -1
View File
@@ -1,7 +1,7 @@
#![cfg(feature = "egui")]
use craft_keymap::egui::{Dispatcher, Hit, matches, platform};
use craft_keymap::{Active, Bindable, Binding, Chord, CommandRef, Key, Keymap, Kind, Layout, Mods, Platform, Scope, Scopes, Trigger};
use craft_keymap::{Active, Bindable, Binding, Chord, CommandRef, Key, KeyInput, Keymap, Kind, Layout, Mods, Platform, Scope, Scopes, Trigger};
use egui::{Event, InputState, Key as EguiKey, Modifiers};
fn chord(text: &str) -> Chord {
@@ -482,6 +482,26 @@ fn the_dispatcher_reads_presses_by_the_layout() {
let (ran, _) = run(&mut d, &km, &Active::NONE, frame(2.0, ctrl_shift, vec![at(EguiKey::Slash, EguiKey::Num7, ctrl_shift)]));
assert_eq!(ran, ["edit.comment"]);
// German on egui-winit: AltGr+M types µ and AltGr+] types ~ with no modifiers reported, so
// presses while right Alt is held teach nothing and Ctrl+Z stays Ctrl+Z on the Y position.
let mut d = Dispatcher::new();
let typed = vec![at(EguiKey::Plus, EguiKey::CloseBracket, Modifiers::NONE), Event::Text("+".into())];
run(&mut d, &km, &Active::NONE, frame(1.0, Modifiers::NONE, typed));
let right_alt =
|pressed| Event::Key { key: EguiKey::AltRight, physical_key: Some(EguiKey::AltRight), pressed, repeat: false, modifiers: Modifiers::NONE };
run(&mut d, &km, &Active::NONE, frame(2.0, Modifiers::NONE, vec![right_alt(true)]));
let alt_graph = vec![
at(EguiKey::M, EguiKey::M, Modifiers::NONE),
Event::Text("µ".into()),
at(EguiKey::CloseBracket, EguiKey::CloseBracket, Modifiers::NONE),
Event::Text("~".into()),
right_alt(false),
];
run(&mut d, &km, &Active::NONE, frame(3.0, Modifiers::NONE, alt_graph));
assert!(d.layout().is_latin());
assert_eq!(d.layout().char_at(Key::CloseBracket), Some('+'));
assert_eq!(d.layout().resolve(&KeyInput::new(Mods::CMD).with_typed(Key::Z).with_physical(Key::Y)), Some(chord("Cmd+Z")));
// A layout the platform reports applies from the first press.
let mut d = Dispatcher::new().with_layout(Layout::new().with_latin(false));
let (ran, _) = run(&mut d, &km, &Active::NONE, frame(1.0, ctrl_shift, vec![at(EguiKey::CloseBracket, EguiKey::D, ctrl_shift)]));
+2
View File
@@ -127,6 +127,8 @@ fn typing_decides_whether_the_layout_is_latin() {
assert!(!layout.is_latin(), "a command chord teaches nothing");
layout.observe(Key::S, Mods::NONE, "š");
assert!(layout.is_latin(), "Latin letters beyond ASCII count as Latin");
layout.observe(Key::M, Mods::NONE, "µ");
assert!(layout.is_latin(), "Latin-1 symbols that count as letters say nothing");
// What the platform reports wins.
let mut reported = Layout::new().with_latin(false);