mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-07 16:52:47 +00:00
Keyboard Shortcuts: the backtick key's label ignores the next key's text on the web
eframe's web build sends each key's text before its press. When several keys arrive in one frame, the editor paired the backtick press with the text typed by the key after it, so a shortcut on that key could show the next key's character. The editor now pairs each text with its press through `shortcuts::typing_presses`, which shortcut dispatch already uses, for both event orders.
This commit is contained in:
@@ -274,19 +274,18 @@ pub fn chord_from_event(key: Key, m: Modifiers) -> Option<String> {
|
||||
|
||||
ui_mirror!(fn backtick_store() -> Option<String>);
|
||||
|
||||
/// Notes what the backtick key (left of 1) typed in `events`: the one-character text whose key, a
|
||||
/// press of it without modifiers, comes right before it (egui-winit) or, when no press comes
|
||||
/// before, right after it (eframe's web build with no text field focused). egui reports that key
|
||||
/// as [`Key::Backtick`] on layouts where it types a character egui has no key for, such as `"` on
|
||||
/// Turkish Q.
|
||||
/// Notes what the backtick key (left of 1) typed in `events`: the last one-character text that
|
||||
/// [`crate::shortcuts::typing_presses`] pairs with a press of that key without modifiers, whether
|
||||
/// the press comes before its text (egui-winit) or after it (eframe's web build with no text field
|
||||
/// focused). egui reports that key as [`Key::Backtick`] on layouts where it types a character egui
|
||||
/// has no key for, such as `"` on Turkish Q.
|
||||
pub(crate) fn note_backtick_text(events: &[egui::Event]) {
|
||||
let is_press = |e: Option<&egui::Event>| matches!(e, Some(egui::Event::Key { pressed: true, .. }));
|
||||
let is_backtick =
|
||||
|e: Option<&egui::Event>| matches!(e, Some(egui::Event::Key { key: Key::Backtick, pressed: true, modifiers, .. }) if modifiers.is_none());
|
||||
let typed = events.iter().enumerate().rev().find_map(|(j, e)| match e {
|
||||
egui::Event::Text(t) if t.chars().count() == 1 && !t.chars().any(char::is_whitespace) => {
|
||||
let before = j.checked_sub(1).and_then(|j| events.get(j));
|
||||
(is_backtick(before) || (!is_press(before) && is_backtick(events.get(j + 1)))).then(|| t.clone())
|
||||
let typed_by = crate::shortcuts::typing_presses(events);
|
||||
let typed = events.iter().zip(typed_by).rev().find_map(|(e, by)| match (e, by.and_then(|k| events.get(k))) {
|
||||
(egui::Event::Text(t), Some(egui::Event::Key { key: Key::Backtick, modifiers, .. }))
|
||||
if modifiers.is_none() && t.chars().count() == 1 && !t.chars().any(char::is_whitespace) =>
|
||||
{
|
||||
Some(t.clone())
|
||||
}
|
||||
_ => None,
|
||||
});
|
||||
@@ -1322,6 +1321,13 @@ mod tests {
|
||||
assert_eq!(backtick_text().as_deref(), Some("\""));
|
||||
note_backtick_text(&[text("`"), press(Key::Backtick)]);
|
||||
assert_eq!(backtick_text(), None);
|
||||
// Several keys typed in one frame on the web: each text goes with the press after it.
|
||||
let web = [text("a"), press(Key::A), text("\""), press(Key::Backtick), text("b"), press(Key::B)];
|
||||
note_backtick_text(&web);
|
||||
assert_eq!(backtick_text().as_deref(), Some("\""));
|
||||
note_backtick_text(&[text("`"), press(Key::Backtick)]);
|
||||
note_backtick_text(&[press(Key::A), text("a"), press(Key::Backtick), text("\""), press(Key::B), text("b")]);
|
||||
assert_eq!(backtick_text().as_deref(), Some("\""));
|
||||
// Only the unshifted key types that character.
|
||||
assert_eq!(on_layout("Shift+~".into(), Some("\"")), "Shift+~");
|
||||
assert_eq!(on_layout("Cmd+~".into(), Some("\"")), "Cmd+\"");
|
||||
|
||||
@@ -929,7 +929,7 @@ fn latin(text: &str, physical: Option<Key>) -> String {
|
||||
/// types at most one text. A text takes the press after it only when every later text in the same
|
||||
/// run of alternating texts and presses has a press after it too; otherwise the text after that
|
||||
/// press takes it as the press before it, and this text has none.
|
||||
fn typing_presses(events: &[egui::Event]) -> Vec<Option<usize>> {
|
||||
pub(crate) fn typing_presses(events: &[egui::Event]) -> Vec<Option<usize>> {
|
||||
let is_press = |k: usize| matches!(events.get(k), Some(egui::Event::Key { key, pressed: true, .. }) if !is_modifier(*key));
|
||||
let is_text = |k: usize| matches!(events.get(k), Some(egui::Event::Text(_)));
|
||||
// Whether the run of alternating texts and presses that starts with the text at `j` ends
|
||||
|
||||
Reference in New Issue
Block a user