257 lines
8.6 KiB
Rust
257 lines
8.6 KiB
Rust
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers, MouseButton, MouseEvent, MouseEventKind};
|
|
use ratatui::layout::Rect;
|
|
|
|
pub fn convert_egui_mouse(
|
|
ctx: &egui::Context,
|
|
widget_rect: egui::Rect,
|
|
term: Rect,
|
|
) -> Vec<MouseEvent> {
|
|
let mut events = Vec::new();
|
|
if widget_rect.width() < 1.0 || widget_rect.height() < 1.0 || term.width == 0 || term.height == 0 {
|
|
return events;
|
|
}
|
|
|
|
ctx.input(|i| {
|
|
let Some(pos) = i.pointer.latest_pos() else {
|
|
return;
|
|
};
|
|
if !widget_rect.contains(pos) {
|
|
return;
|
|
}
|
|
|
|
let col =
|
|
((pos.x - widget_rect.left()) / widget_rect.width() * term.width as f32) as u16;
|
|
let row =
|
|
((pos.y - widget_rect.top()) / widget_rect.height() * term.height as f32) as u16;
|
|
let col = col.min(term.width.saturating_sub(1));
|
|
let row = row.min(term.height.saturating_sub(1));
|
|
|
|
if i.pointer.button_clicked(egui::PointerButton::Primary) {
|
|
events.push(MouseEvent {
|
|
kind: MouseEventKind::Down(MouseButton::Left),
|
|
column: col,
|
|
row,
|
|
modifiers: KeyModifiers::empty(),
|
|
});
|
|
}
|
|
|
|
let scroll = i.raw_scroll_delta.y;
|
|
if scroll > 1.0 {
|
|
events.push(MouseEvent {
|
|
kind: MouseEventKind::ScrollUp,
|
|
column: col,
|
|
row,
|
|
modifiers: KeyModifiers::empty(),
|
|
});
|
|
} else if scroll < -1.0 {
|
|
events.push(MouseEvent {
|
|
kind: MouseEventKind::ScrollDown,
|
|
column: col,
|
|
row,
|
|
modifiers: KeyModifiers::empty(),
|
|
});
|
|
}
|
|
});
|
|
|
|
events
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
events
|
|
}
|
|
|
|
fn convert_event(event: &egui::Event) -> Option<KeyEvent> {
|
|
match event {
|
|
egui::Event::Key {
|
|
key,
|
|
pressed,
|
|
modifiers,
|
|
..
|
|
} => {
|
|
if !*pressed {
|
|
return None;
|
|
}
|
|
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()));
|
|
}
|
|
}
|
|
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,
|
|
}
|
|
}
|
|
|
|
fn convert_key(key: egui::Key) -> Option<KeyCode> {
|
|
Some(match key {
|
|
egui::Key::ArrowDown => KeyCode::Down,
|
|
egui::Key::ArrowLeft => KeyCode::Left,
|
|
egui::Key::ArrowRight => KeyCode::Right,
|
|
egui::Key::ArrowUp => KeyCode::Up,
|
|
egui::Key::Escape => KeyCode::Esc,
|
|
egui::Key::Tab => KeyCode::Tab,
|
|
egui::Key::Backspace => KeyCode::Backspace,
|
|
egui::Key::Enter => KeyCode::Enter,
|
|
egui::Key::Space => KeyCode::Char(' '),
|
|
egui::Key::Insert => KeyCode::Insert,
|
|
egui::Key::Delete => KeyCode::Delete,
|
|
egui::Key::Home => KeyCode::Home,
|
|
egui::Key::End => KeyCode::End,
|
|
egui::Key::PageUp => KeyCode::PageUp,
|
|
egui::Key::PageDown => KeyCode::PageDown,
|
|
egui::Key::F1 => KeyCode::F(1),
|
|
egui::Key::F2 => KeyCode::F(2),
|
|
egui::Key::F3 => KeyCode::F(3),
|
|
egui::Key::F4 => KeyCode::F(4),
|
|
egui::Key::F5 => KeyCode::F(5),
|
|
egui::Key::F6 => KeyCode::F(6),
|
|
egui::Key::F7 => KeyCode::F(7),
|
|
egui::Key::F8 => KeyCode::F(8),
|
|
egui::Key::F9 => KeyCode::F(9),
|
|
egui::Key::F10 => KeyCode::F(10),
|
|
egui::Key::F11 => KeyCode::F(11),
|
|
egui::Key::F12 => KeyCode::F(12),
|
|
egui::Key::A => KeyCode::Char('a'),
|
|
egui::Key::B => KeyCode::Char('b'),
|
|
egui::Key::C => KeyCode::Char('c'),
|
|
egui::Key::D => KeyCode::Char('d'),
|
|
egui::Key::E => KeyCode::Char('e'),
|
|
egui::Key::F => KeyCode::Char('f'),
|
|
egui::Key::G => KeyCode::Char('g'),
|
|
egui::Key::H => KeyCode::Char('h'),
|
|
egui::Key::I => KeyCode::Char('i'),
|
|
egui::Key::J => KeyCode::Char('j'),
|
|
egui::Key::K => KeyCode::Char('k'),
|
|
egui::Key::L => KeyCode::Char('l'),
|
|
egui::Key::M => KeyCode::Char('m'),
|
|
egui::Key::N => KeyCode::Char('n'),
|
|
egui::Key::O => KeyCode::Char('o'),
|
|
egui::Key::P => KeyCode::Char('p'),
|
|
egui::Key::Q => KeyCode::Char('q'),
|
|
egui::Key::R => KeyCode::Char('r'),
|
|
egui::Key::S => KeyCode::Char('s'),
|
|
egui::Key::T => KeyCode::Char('t'),
|
|
egui::Key::U => KeyCode::Char('u'),
|
|
egui::Key::V => KeyCode::Char('v'),
|
|
egui::Key::W => KeyCode::Char('w'),
|
|
egui::Key::X => KeyCode::Char('x'),
|
|
egui::Key::Y => KeyCode::Char('y'),
|
|
egui::Key::Z => KeyCode::Char('z'),
|
|
egui::Key::Num0 => KeyCode::Char('0'),
|
|
egui::Key::Num1 => KeyCode::Char('1'),
|
|
egui::Key::Num2 => KeyCode::Char('2'),
|
|
egui::Key::Num3 => KeyCode::Char('3'),
|
|
egui::Key::Num4 => KeyCode::Char('4'),
|
|
egui::Key::Num5 => KeyCode::Char('5'),
|
|
egui::Key::Num6 => KeyCode::Char('6'),
|
|
egui::Key::Num7 => KeyCode::Char('7'),
|
|
egui::Key::Num8 => KeyCode::Char('8'),
|
|
egui::Key::Num9 => KeyCode::Char('9'),
|
|
egui::Key::Minus => KeyCode::Char('-'),
|
|
egui::Key::Equals => KeyCode::Char('='),
|
|
egui::Key::OpenBracket => KeyCode::Char('['),
|
|
egui::Key::CloseBracket => KeyCode::Char(']'),
|
|
egui::Key::Semicolon => KeyCode::Char(';'),
|
|
egui::Key::Comma => KeyCode::Char(','),
|
|
egui::Key::Period => KeyCode::Char('.'),
|
|
egui::Key::Slash => KeyCode::Char('/'),
|
|
egui::Key::Backslash => KeyCode::Char('\\'),
|
|
egui::Key::Backtick => KeyCode::Char('`'),
|
|
egui::Key::Quote => KeyCode::Char('\''),
|
|
_ => return None,
|
|
})
|
|
}
|
|
|
|
fn convert_modifiers(mods: egui::Modifiers) -> KeyModifiers {
|
|
let mut result = KeyModifiers::empty();
|
|
if mods.shift {
|
|
result |= KeyModifiers::SHIFT;
|
|
}
|
|
if mods.ctrl || mods.command {
|
|
result |= KeyModifiers::CONTROL;
|
|
}
|
|
if mods.alt {
|
|
result |= KeyModifiers::ALT;
|
|
}
|
|
result
|
|
}
|
|
|
|
fn is_character_key(key: egui::Key) -> bool {
|
|
matches!(
|
|
key,
|
|
egui::Key::A
|
|
| egui::Key::B
|
|
| egui::Key::C
|
|
| egui::Key::D
|
|
| egui::Key::E
|
|
| egui::Key::F
|
|
| egui::Key::G
|
|
| egui::Key::H
|
|
| egui::Key::I
|
|
| egui::Key::J
|
|
| egui::Key::K
|
|
| egui::Key::L
|
|
| egui::Key::M
|
|
| egui::Key::N
|
|
| egui::Key::O
|
|
| egui::Key::P
|
|
| egui::Key::Q
|
|
| egui::Key::R
|
|
| egui::Key::S
|
|
| egui::Key::T
|
|
| egui::Key::U
|
|
| egui::Key::V
|
|
| egui::Key::W
|
|
| egui::Key::X
|
|
| egui::Key::Y
|
|
| egui::Key::Z
|
|
| egui::Key::Num0
|
|
| egui::Key::Num1
|
|
| egui::Key::Num2
|
|
| egui::Key::Num3
|
|
| egui::Key::Num4
|
|
| egui::Key::Num5
|
|
| egui::Key::Num6
|
|
| egui::Key::Num7
|
|
| egui::Key::Num8
|
|
| egui::Key::Num9
|
|
| egui::Key::Space
|
|
| egui::Key::Minus
|
|
| egui::Key::Equals
|
|
| egui::Key::OpenBracket
|
|
| egui::Key::CloseBracket
|
|
| egui::Key::Semicolon
|
|
| egui::Key::Comma
|
|
| egui::Key::Period
|
|
| egui::Key::Slash
|
|
| egui::Key::Backslash
|
|
| egui::Key::Backtick
|
|
| egui::Key::Quote
|
|
)
|
|
}
|