Feat: lots of convenience stuff

This commit is contained in:
2026-02-24 00:52:40 +01:00
parent 78b20b5ff9
commit 7632bc76f7
15 changed files with 440 additions and 26 deletions

View File

@@ -68,7 +68,9 @@ pub fn handle_key(ctx: &mut InputContext, key: KeyEvent) -> InputResult {
if ctx.app.ui.show_title {
ctx.dispatch(AppCommand::HideTitle);
return InputResult::Continue;
if matches!(key.code, KeyCode::Char('q') | KeyCode::Esc) {
return InputResult::Continue;
}
}
ctx.dispatch(AppCommand::ClearStatus);

View File

@@ -60,15 +60,13 @@ pub fn convert_egui_events(ctx: &egui::Context) -> Vec<KeyEvent> {
let mut events = Vec::new();
for event in &ctx.input(|i| i.events.clone()) {
if let Some(key_event) = convert_event(event) {
events.push(key_event);
}
convert_event(event, &mut events);
}
events
}
fn convert_event(event: &egui::Event) -> Option<KeyEvent> {
fn convert_event(event: &egui::Event, events: &mut Vec<KeyEvent>) {
match event {
egui::Event::Key {
key,
@@ -77,33 +75,39 @@ fn convert_event(event: &egui::Event) -> Option<KeyEvent> {
..
} => {
if !*pressed {
return None;
return;
}
let mods = convert_modifiers(*modifiers);
// For character keys without ctrl/alt, let Event::Text handle it
if is_character_key(*key) && !mods.intersects(KeyModifiers::CONTROL | KeyModifiers::ALT)
{
return None;
}
let code = convert_key(*key)?;
Some(KeyEvent::new(code, mods))
}
egui::Event::Text(text) => {
if text.len() == 1 {
let c = text.chars().next()?;
if !c.is_control() {
return Some(KeyEvent::new(KeyCode::Char(c), KeyModifiers::empty()));
// For character keys, only handle Ctrl+key (without Alt) as shortcuts.
// All other character input (bare, Shift, Alt/Option, AltGr=Ctrl+Alt)
// defers to Event::Text which respects the active keyboard layout.
if is_character_key(*key) {
let ctrl_without_alt =
mods.contains(KeyModifiers::CONTROL) && !mods.contains(KeyModifiers::ALT);
if !ctrl_without_alt {
return;
}
}
if let Some(code) = convert_key(*key) {
events.push(KeyEvent::new(code, mods));
}
}
egui::Event::Text(text) => {
for c in text.chars() {
if !c.is_control() {
events.push(KeyEvent::new(KeyCode::Char(c), KeyModifiers::empty()));
}
}
None
}
// egui intercepts Ctrl+C/V/X and converts them to these high-level events
// instead of passing through raw Key events (see egui issue #4065).
// Synthesize the equivalent KeyEvent so the application's input handler receives them.
egui::Event::Copy => Some(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL)),
egui::Event::Cut => Some(KeyEvent::new(KeyCode::Char('x'), KeyModifiers::CONTROL)),
egui::Event::Paste(_) => Some(KeyEvent::new(KeyCode::Char('v'), KeyModifiers::CONTROL)),
_ => None,
egui::Event::Copy => events.push(KeyEvent::new(KeyCode::Char('c'), KeyModifiers::CONTROL)),
egui::Event::Cut => events.push(KeyEvent::new(KeyCode::Char('x'), KeyModifiers::CONTROL)),
egui::Event::Paste(_) => {
events.push(KeyEvent::new(KeyCode::Char('v'), KeyModifiers::CONTROL));
}
_ => {}
}
}
@@ -136,6 +140,14 @@ fn convert_key(key: egui::Key) -> Option<KeyCode> {
egui::Key::F10 => KeyCode::F(10),
egui::Key::F11 => KeyCode::F(11),
egui::Key::F12 => KeyCode::F(12),
egui::Key::F13 => KeyCode::F(13),
egui::Key::F14 => KeyCode::F(14),
egui::Key::F15 => KeyCode::F(15),
egui::Key::F16 => KeyCode::F(16),
egui::Key::F17 => KeyCode::F(17),
egui::Key::F18 => KeyCode::F(18),
egui::Key::F19 => KeyCode::F(19),
egui::Key::F20 => KeyCode::F(20),
egui::Key::A => KeyCode::Char('a'),
egui::Key::B => KeyCode::Char('b'),
egui::Key::C => KeyCode::Char('c'),
@@ -183,6 +195,13 @@ fn convert_key(key: egui::Key) -> Option<KeyCode> {
egui::Key::Backslash => KeyCode::Char('\\'),
egui::Key::Backtick => KeyCode::Char('`'),
egui::Key::Quote => KeyCode::Char('\''),
egui::Key::Colon => KeyCode::Char(':'),
egui::Key::Pipe => KeyCode::Char('|'),
egui::Key::Questionmark => KeyCode::Char('?'),
egui::Key::Exclamationmark => KeyCode::Char('!'),
egui::Key::OpenCurlyBracket => KeyCode::Char('{'),
egui::Key::CloseCurlyBracket => KeyCode::Char('}'),
egui::Key::Plus => KeyCode::Char('+'),
_ => return None,
})
}
@@ -252,5 +271,12 @@ fn is_character_key(key: egui::Key) -> bool {
| egui::Key::Backslash
| egui::Key::Backtick
| egui::Key::Quote
| egui::Key::Colon
| egui::Key::Pipe
| egui::Key::Questionmark
| egui::Key::Exclamationmark
| egui::Key::OpenCurlyBracket
| egui::Key::CloseCurlyBracket
| egui::Key::Plus
)
}

View File

@@ -465,7 +465,7 @@ fn render_footer(frame: &mut Frame, app: &App, area: Rect) {
Page::Main => vec![
("Space", "Play"),
("Enter", "Edit"),
("t", "Toggle"),
("t", "On/Off"),
("Tab", "Samples"),
("?", "Keys"),
],