1use egui::{Key, Modifiers, MouseWheelUnit, PointerButton, Pos2, Rect};
16use sdl3::event::WindowEvent;
17use sdl3::keyboard::Keycode;
18use sdl3::keyboard::Mod;
19use sdl3::keyboard::Scancode;
20use sdl3::mouse::{Cursor, MouseButton, SystemCursor};
21use sdl3::video::Window;
22
23#[must_use]
24#[derive(Clone, Copy, Debug, Default)]
25pub struct EventResponse {
26 pub consumed: bool,
34
35 pub repaint: bool,
37}
38
39pub struct State {
43 egui_ctx: egui::Context,
44 egui_input: egui::RawInput,
45 start_time: std::time::Instant,
46 viewport_id: egui::ViewportId,
47 pointer_pos_in_points: Option<egui::Pos2>,
48 pointer_touch_id: Option<u64>,
52 current_cursor: Option<CurrentCursor>,
53 clipboard: sdl3::clipboard::ClipboardUtil,
54 window_size: (u32, u32), drawable_size: (u32, u32),
60}
61
62struct CurrentCursor {
66 icon: egui::CursorIcon,
67 cursor: Option<sdl3::mouse::Cursor>, }
69
70impl State {
71 pub fn new(window: &Window, egui_ctx: egui::Context, viewport_id: egui::ViewportId) -> Self {
72 let screen_rect = new_screen_rect(&egui_ctx, window);
73 let mut egui_input = egui::RawInput {
74 focused: false, screen_rect,
76 ..Default::default()
77 };
78 egui_input
79 .viewports
80 .entry(egui::ViewportId::ROOT)
81 .or_default()
82 .native_pixels_per_point = Some(native_pixels_per_point(window));
83 let clipboard = window.subsystem().clipboard();
84 let window_size = window.size();
85 let drawable_size = window.size_in_pixels();
86
87 State {
88 egui_ctx,
89 viewport_id,
90 clipboard,
91 start_time: std::time::Instant::now(),
92 egui_input,
93 pointer_pos_in_points: None,
94 pointer_touch_id: None,
95 current_cursor: None,
96 window_size,
97 drawable_size,
98 }
99 }
100
101 #[inline]
102 pub fn get_window_size(&self) -> (u32, u32) {
103 self.window_size
104 }
105
106 #[inline]
111 pub fn get_drawable_size(&self) -> (u32, u32) {
112 self.drawable_size
113 }
114
115 #[inline]
116 pub fn get_pointer_pos_in_points(&self) -> Option<egui::Pos2> {
117 self.pointer_pos_in_points
118 }
119
120 #[inline]
121 pub fn set_theme(&mut self, theme: egui::Theme) {
122 self.egui_input.system_theme.replace(theme);
123 }
124
125 #[inline]
133 pub fn handle_platform_output(&mut self, platform_output: egui::PlatformOutput) {
134 for command in &platform_output.commands {
135 match command {
136 egui::OutputCommand::CopyText(text) => {
137 let result = self.clipboard.set_clipboard_text(text);
138
139 if result.is_err() {
140 log::warn!("Failed to set copied text to clipboard");
141 }
142 }
143 egui::OutputCommand::CopyImage(_color_image) => {
144 log::warn!("CopyImage is not supported")
145 }
146 egui::OutputCommand::OpenUrl(_url) => {
147 #[cfg(feature = "links")]
148 if let Err(err) = webbrowser::open(&_url.url) {
149 log::warn!("Failed to open url: {}", err);
150 }
151
152 #[cfg(not(feature = "links"))]
153 {
154 log::warn!("Cannot open url - feature \"links\" not enabled.");
155 }
156 }
157 }
158 }
159
160 self.set_cursor_icon(platform_output.cursor_icon);
161 }
162
163 #[inline]
169 pub fn take_egui_input(&mut self) -> egui::RawInput {
170 self.egui_input.time = Some(self.start_time.elapsed().as_secs_f64());
171 self.egui_input.viewport_id = self.viewport_id;
173
174 let native_ppp = self
180 .egui_input
181 .viewports
182 .get(&self.viewport_id)
183 .and_then(|v| v.native_pixels_per_point)
184 .unwrap_or(1.0);
185 let ppp = self.egui_ctx.zoom_factor() * native_ppp;
186 if ppp > 0.0 {
187 let points = egui::vec2(self.drawable_size.0 as f32, self.drawable_size.1 as f32) / ppp;
188 if points.x > 0.0 && points.y > 0.0 {
189 self.egui_input.screen_rect =
190 Some(egui::Rect::from_min_size(egui::Pos2::ZERO, points));
191 }
192 }
193
194 self.egui_input.take()
195 }
196
197 #[inline]
207 fn cached_pixels_per_point(&self) -> f32 {
208 let native_ppp = self
209 .egui_input
210 .viewports
211 .get(&self.viewport_id)
212 .and_then(|v| v.native_pixels_per_point)
213 .unwrap_or(1.0);
214 self.egui_ctx.zoom_factor() * native_ppp
215 }
216
217 #[inline]
219 fn pos_in_points(&self, x: f32, y: f32) -> egui::Pos2 {
220 let ppp = self.cached_pixels_per_point();
221 if ppp > 0.0 {
222 egui::pos2(x, y) / ppp
223 } else {
224 egui::pos2(x, y)
225 }
226 }
227
228 pub fn on_event(
232 &mut self,
233 window: &sdl3::video::Window,
234 event: &sdl3::event::Event,
235 ) -> EventResponse {
236 use sdl3::event::Event::*;
237 match event {
238 Window { win_event, .. } => self.on_window_event(*win_event, window),
239 MouseButtonDown {
240 mouse_btn, x, y, ..
241 } => self.on_mouse_button_event(*mouse_btn, true, *x, *y),
242 MouseButtonUp {
243 mouse_btn, x, y, ..
244 } => self.on_mouse_button_event(*mouse_btn, false, *x, *y),
245 MouseMotion { x, y, .. } => {
246 let pos = self.pos_in_points(*x, *y);
247 self.pointer_pos_in_points = Some(pos);
248 self.egui_input.events.push(egui::Event::PointerMoved(pos));
249 EventResponse {
250 repaint: true,
251 consumed: self.egui_ctx.egui_is_using_pointer(),
252 }
253 }
254 MouseWheel { x, y, .. } => {
255 let dx = *x;
256 let dy = *y;
257
258 if self.egui_input.modifiers.command {
259 let delta = (dy / 125.0).exp();
261 self.egui_input.events.push(egui::Event::Zoom(delta));
262 } else if self.egui_input.modifiers.shift {
263 self.egui_input.events.push(egui::Event::MouseWheel {
265 unit: MouseWheelUnit::Line,
266 delta: egui::vec2(dx + dy, 0.0),
267 phase: egui::TouchPhase::Move,
268 modifiers: self.egui_input.modifiers,
269 });
270 } else {
271 self.egui_input.events.push(egui::Event::MouseWheel {
273 unit: MouseWheelUnit::Line,
274 delta: egui::vec2(dx, dy),
275 phase: egui::TouchPhase::Move,
276 modifiers: self.egui_input.modifiers,
277 });
278 }
279 EventResponse {
280 repaint: true,
281 consumed: self.egui_ctx.egui_wants_pointer_input(),
282 }
283 }
284 KeyUp {
285 keycode: Some(kc),
286 scancode: Some(sc),
287 keymod,
288 repeat,
289 ..
290 } => self.on_keyboard_event(*kc, *sc, *keymod, false, *repeat),
291 KeyDown {
292 keycode: Some(kc),
293 scancode: Some(sc),
294 keymod,
295 repeat,
296 ..
297 } => {
298 let resp = self.on_keyboard_event(*kc, *sc, *keymod, true, *repeat);
299
300 if self.egui_input.modifiers.command && *kc == Keycode::C {
301 self.egui_input.events.push(egui::Event::Copy);
302 } else if self.egui_input.modifiers.command && *kc == Keycode::X {
303 self.egui_input.events.push(egui::Event::Cut);
304 } else if self.egui_input.modifiers.command && *kc == Keycode::V {
305 if let Ok(contents) = self.clipboard.clipboard_text() {
306 self.egui_input.events.push(egui::Event::Text(contents));
307 }
308 }
309
310 resp
311 }
312 TextInput { text, .. } => {
313 let mut resp = EventResponse {
314 consumed: true,
315 repaint: false,
316 };
317 if !text.is_empty() {
318 let is_cmd = self.egui_input.modifiers.ctrl
321 || self.egui_input.modifiers.command
322 || self.egui_input.modifiers.mac_cmd;
323
324 if !is_cmd {
325 self.egui_input
326 .events
327 .push(egui::Event::Text(text.to_owned()));
328
329 resp.repaint = true;
330 }
331 }
332
333 resp
334 }
335 DropFile { filename, .. } => {
336 self.egui_input.dropped_files.push(egui::DroppedFile {
337 path: Some(std::path::PathBuf::from(filename)),
338 ..Default::default()
339 });
340 EventResponse {
341 repaint: true,
342 consumed: false,
343 }
344 }
345 FingerDown {
346 touch_id,
347 finger_id,
348 x,
349 y,
350 pressure,
351 ..
352 } => self.on_touch(TouchInfo {
353 phase: egui::TouchPhase::Start,
354 touch_id: *touch_id,
355 finger_id: *finger_id,
356 x: *x,
357 y: *y,
358 pressure: *pressure,
359 }),
360 FingerUp {
361 touch_id,
362 finger_id,
363 x,
364 y,
365 pressure,
366 ..
367 } => self.on_touch(TouchInfo {
368 phase: egui::TouchPhase::End,
369 touch_id: *touch_id,
370 finger_id: *finger_id,
371 x: *x,
372 y: *y,
373 pressure: *pressure,
374 }),
375 FingerMotion {
376 touch_id,
377 finger_id,
378 x,
379 y,
380 pressure,
381 ..
382 } => self.on_touch(TouchInfo {
383 phase: egui::TouchPhase::Move,
384 touch_id: *touch_id,
385 finger_id: *finger_id,
386 x: *x,
387 y: *y,
388 pressure: *pressure,
389 }),
390 _ => EventResponse::default(),
391 }
392 }
393
394 #[inline]
395 fn on_touch(&mut self, info: TouchInfo) -> EventResponse {
396 let consumed = match info.phase {
397 egui::TouchPhase::Start | egui::TouchPhase::End | egui::TouchPhase::Cancel => {
398 self.egui_ctx.egui_wants_pointer_input()
399 }
400 egui::TouchPhase::Move => self.egui_ctx.egui_is_using_pointer(),
401 };
402
403 let (win_w, win_h) = self.window_size;
411 let pixel_x = info.x * win_w as f32;
412 let pixel_y = info.y * win_h as f32;
413 let pos = self.pos_in_points(pixel_x, pixel_y);
414 self.egui_input.events.push(egui::Event::Touch {
415 device_id: egui::TouchDeviceId(info.touch_id),
416 id: egui::TouchId::from(info.finger_id),
417 phase: info.phase,
418 pos,
419 force: Some(info.pressure),
420 });
421
422 match info.phase {
429 egui::TouchPhase::Start if self.pointer_touch_id.is_none() => {
430 self.pointer_touch_id = Some(info.finger_id);
431 self.pointer_pos_in_points = Some(pos);
432 self.egui_input.events.push(egui::Event::PointerMoved(pos));
434 self.egui_input.events.push(egui::Event::PointerButton {
435 pos,
436 button: egui::PointerButton::Primary,
437 pressed: true,
438 modifiers: self.egui_input.modifiers,
439 });
440 }
441 egui::TouchPhase::Move if self.pointer_touch_id == Some(info.finger_id) => {
442 self.pointer_pos_in_points = Some(pos);
443 self.egui_input.events.push(egui::Event::PointerMoved(pos));
444 }
445 egui::TouchPhase::End | egui::TouchPhase::Cancel
446 if self.pointer_touch_id == Some(info.finger_id) =>
447 {
448 self.pointer_touch_id = None;
449 if info.phase == egui::TouchPhase::End {
450 self.egui_input.events.push(egui::Event::PointerButton {
451 pos,
452 button: egui::PointerButton::Primary,
453 pressed: false,
454 modifiers: self.egui_input.modifiers,
455 });
456 }
457 self.egui_input.events.push(egui::Event::PointerGone);
460 self.pointer_pos_in_points = None;
461 }
462 _ => {}
463 }
464
465 EventResponse {
466 repaint: true,
467 consumed,
468 }
469 }
470
471 fn on_window_event(&mut self, event: WindowEvent, window: &Window) -> EventResponse {
472 match event {
473 WindowEvent::Minimized
474 | WindowEvent::Maximized
475 | WindowEvent::Resized(_, _)
476 | WindowEvent::PixelSizeChanged(_, _) => {
477 self.on_size_chage(window);
478 EventResponse {
479 repaint: true,
480 consumed: false,
481 }
482 }
483 WindowEvent::Shown
484 | WindowEvent::Hidden
485 | WindowEvent::Exposed
486 | WindowEvent::Moved(_, _)
487 | WindowEvent::Restored
488 | WindowEvent::MouseEnter
489 | WindowEvent::Occluded
490 | WindowEvent::CloseRequested => EventResponse {
491 consumed: false,
492 repaint: true,
493 },
494 WindowEvent::MouseLeave => {
495 self.pointer_pos_in_points = None;
496 self.egui_input.events.push(egui::Event::PointerGone);
497 EventResponse {
498 repaint: true,
499 consumed: false,
500 }
501 }
502 WindowEvent::FocusGained => {
503 self.egui_input.focused = true;
504 self.egui_input
505 .events
506 .push(egui::Event::WindowFocused(true));
507 EventResponse {
508 repaint: true,
509 consumed: false,
510 }
511 }
512 WindowEvent::FocusLost => {
513 self.egui_input.focused = false;
514 self.egui_input
515 .events
516 .push(egui::Event::WindowFocused(false));
517 EventResponse {
518 repaint: true,
519 consumed: false,
520 }
521 }
522 WindowEvent::HitTest(_, _)
523 | WindowEvent::ICCProfChanged
524 | WindowEvent::DisplayChanged(_)
525 | WindowEvent::None => EventResponse::default(),
526 }
527 }
528
529 fn on_mouse_button_event(
530 &mut self,
531 button: MouseButton,
532 pressed: bool,
533 x: f32,
534 y: f32,
535 ) -> EventResponse {
536 let Some(button) = into_egui_button(button) else {
537 return EventResponse::default();
538 };
539
540 let pos = self.pos_in_points(x, y);
541 self.pointer_pos_in_points = Some(pos);
542 self.egui_input.events.push(egui::Event::PointerButton {
543 pos,
544 button,
545 pressed,
546 modifiers: self.egui_input.modifiers,
547 });
548 EventResponse {
549 repaint: true,
550 consumed: self.egui_ctx.egui_wants_pointer_input(),
551 }
552 }
553
554 fn on_keyboard_event(
555 &mut self,
556 keycode: Keycode,
557 scancode: Scancode,
558 keymod: Mod,
559 pressed: bool,
560 repeat: bool,
561 ) -> EventResponse {
562 let Some(key) = into_egui_key(keycode) else {
563 return EventResponse::default();
564 };
565
566 self.egui_input.modifiers = into_egui_modifiers(keymod);
567 self.egui_input.events.push(egui::Event::Key {
568 key,
569 physical_key: into_egui_physical_key(scancode),
570 pressed,
571 repeat,
572 modifiers: self.egui_input.modifiers,
573 });
574 let consumed = self.egui_ctx.egui_wants_keyboard_input() || key == Key::Tab;
576 EventResponse {
577 repaint: true,
578 consumed,
579 }
580 }
581
582 #[inline]
587 pub fn sync_window_size(&mut self, window: &Window) {
588 self.on_size_chage(window);
589 }
590
591 #[inline]
592 fn on_size_chage(&mut self, window: &Window) {
593 self.window_size = window.size();
594 self.drawable_size = window.size_in_pixels();
595 self.egui_input.screen_rect = new_screen_rect(&self.egui_ctx, window);
596 self.egui_input
597 .viewports
598 .entry(self.viewport_id)
599 .or_default()
600 .native_pixels_per_point = Some(native_pixels_per_point(window));
601 }
602
603 #[inline]
604 fn set_cursor_icon(&mut self, cursor_icon: egui::CursorIcon) {
605 if let Some(cursor) = &self.current_cursor {
606 if cursor.icon == cursor_icon {
607 return;
608 }
609 }
610
611 if self.pointer_pos_in_points.is_some() {
612 let system_cursor = into_sdl3_cursor(cursor_icon);
613 let mut current_cursor = CurrentCursor {
614 icon: cursor_icon,
615 cursor: None,
616 };
617
618 match Cursor::from_system(system_cursor) {
619 Ok(cursor) => {
620 cursor.set();
621 current_cursor.cursor = Some(cursor);
622 }
623 Err(e) => {
624 log::warn!("Failed to set cursor: {e}")
625 }
626 }
627 self.current_cursor.replace(current_cursor);
628 } else {
629 self.current_cursor = None;
630 }
631 }
632}
633
634#[inline]
635pub fn poiner_pos_in_points(
636 egui_ctx: &egui::Context,
637 window: &Window,
638 x: f32,
639 y: f32,
640) -> egui::Pos2 {
641 let pixels_per_point = pixels_per_point(egui_ctx, window);
642 egui::pos2(x, y) / pixels_per_point
643}
644
645#[inline]
646pub fn into_egui_modifiers(m: Mod) -> Modifiers {
647 let mut mods = Modifiers::NONE;
648
649 if m.intersects(Mod::LCTRLMOD | Mod::RCTRLMOD) {
650 mods.ctrl = true;
651 mods.command = true;
652 }
653
654 if m.intersects(Mod::LSHIFTMOD | Mod::RSHIFTMOD) {
655 mods.shift = true;
656 }
657
658 if m.intersects(Mod::LALTMOD | Mod::RALTMOD) {
659 mods.alt = true;
660 }
661
662 if m.intersects(Mod::LGUIMOD | Mod::RGUIMOD) {
663 mods.mac_cmd = true;
664 mods.command = true;
665 }
666
667 mods
668}
669
670#[inline]
671fn into_sdl3_cursor(cursor_icon: egui::CursorIcon) -> SystemCursor {
672 match cursor_icon {
673 egui::CursorIcon::Crosshair => SystemCursor::Crosshair,
674 egui::CursorIcon::Default => SystemCursor::Arrow,
675 egui::CursorIcon::Grab => SystemCursor::Hand,
676 egui::CursorIcon::Grabbing => SystemCursor::SizeAll,
677 egui::CursorIcon::Move => SystemCursor::SizeAll,
678 egui::CursorIcon::PointingHand => SystemCursor::Hand,
679 egui::CursorIcon::ResizeHorizontal => SystemCursor::SizeWE,
680 egui::CursorIcon::ResizeNeSw => SystemCursor::SizeNESW,
681 egui::CursorIcon::ResizeNwSe => SystemCursor::SizeNWSE,
682 egui::CursorIcon::ResizeVertical => SystemCursor::SizeNS,
683 egui::CursorIcon::Text => SystemCursor::IBeam,
684 egui::CursorIcon::NotAllowed | egui::CursorIcon::NoDrop => SystemCursor::No,
685 egui::CursorIcon::Wait => SystemCursor::Wait,
686 _ => SystemCursor::Arrow,
688 }
689}
690
691#[inline]
692pub fn screen_size_in_pixels(window: &Window) -> egui::Vec2 {
693 let (width, height) = window.size_in_pixels();
694 egui::vec2(width as f32, height as f32)
695}
696
697#[inline]
698pub fn pixels_per_point(egui_ctx: &egui::Context, window: &Window) -> f32 {
699 let native_pixels_per_point = native_pixels_per_point(window);
700 let egui_zoom_factor = egui_ctx.zoom_factor();
701 egui_zoom_factor * native_pixels_per_point
702}
703
704#[inline]
705fn new_screen_rect(egui_ctx: &egui::Context, window: &Window) -> Option<Rect> {
706 let screen_size_in_pixels = screen_size_in_pixels(window);
707 let screen_size_in_points = screen_size_in_pixels / pixels_per_point(egui_ctx, window);
708
709 (screen_size_in_points.x > 0.0 && screen_size_in_points.y > 0.0)
710 .then(|| Rect::from_min_size(Pos2::ZERO, screen_size_in_points))
711}
712
713#[inline]
714pub fn native_pixels_per_point(window: &Window) -> f32 {
715 let (win_w, win_h) = window.size();
716 let (draw_w, _draw_h) = window.size_in_pixels();
717
718 if win_w > 0 && win_h > 0 {
719 draw_w as f32 / win_w as f32
720 } else {
721 1.0
722 }
723}
724
725#[inline]
726pub fn into_egui_button(btn: MouseButton) -> Option<PointerButton> {
727 match btn {
728 MouseButton::Left => Some(egui::PointerButton::Primary),
729 MouseButton::Middle => Some(egui::PointerButton::Middle),
730 MouseButton::Right => Some(egui::PointerButton::Secondary),
731 MouseButton::Unknown => None,
732 MouseButton::X1 => Some(egui::PointerButton::Extra1),
733 MouseButton::X2 => Some(egui::PointerButton::Extra2),
734 }
735}
736
737pub fn into_egui_key(key: Keycode) -> Option<Key> {
738 Some(match key {
739 Keycode::Left => Key::ArrowLeft,
740 Keycode::Up => Key::ArrowUp,
741 Keycode::Right => Key::ArrowRight,
742 Keycode::Down => Key::ArrowDown,
743
744 Keycode::Escape => Key::Escape,
745 Keycode::Tab => Key::Tab,
746 Keycode::Backspace => Key::Backspace,
747 Keycode::Space => Key::Space,
748 Keycode::Return => Key::Enter,
749
750 Keycode::Insert => Key::Insert,
751 Keycode::Home => Key::Home,
752 Keycode::Delete => Key::Delete,
753 Keycode::End => Key::End,
754 Keycode::PageDown => Key::PageDown,
755 Keycode::PageUp => Key::PageUp,
756
757 Keycode::Kp0 | Keycode::_0 => Key::Num0,
758 Keycode::Kp1 | Keycode::_1 => Key::Num1,
759 Keycode::Kp2 | Keycode::_2 => Key::Num2,
760 Keycode::Kp3 | Keycode::_3 => Key::Num3,
761 Keycode::Kp4 | Keycode::_4 => Key::Num4,
762 Keycode::Kp5 | Keycode::_5 => Key::Num5,
763 Keycode::Kp6 | Keycode::_6 => Key::Num6,
764 Keycode::Kp7 | Keycode::_7 => Key::Num7,
765 Keycode::Kp8 | Keycode::_8 => Key::Num8,
766 Keycode::Kp9 | Keycode::_9 => Key::Num9,
767
768 Keycode::A => Key::A,
769 Keycode::B => Key::B,
770 Keycode::C => Key::C,
771 Keycode::D => Key::D,
772 Keycode::E => Key::E,
773 Keycode::F => Key::F,
774 Keycode::G => Key::G,
775 Keycode::H => Key::H,
776 Keycode::I => Key::I,
777 Keycode::J => Key::J,
778 Keycode::K => Key::K,
779 Keycode::L => Key::L,
780 Keycode::M => Key::M,
781 Keycode::N => Key::N,
782 Keycode::O => Key::O,
783 Keycode::P => Key::P,
784 Keycode::Q => Key::Q,
785 Keycode::R => Key::R,
786 Keycode::S => Key::S,
787 Keycode::T => Key::T,
788 Keycode::U => Key::U,
789 Keycode::V => Key::V,
790 Keycode::W => Key::W,
791 Keycode::X => Key::X,
792 Keycode::Y => Key::Y,
793 Keycode::Z => Key::Z,
794
795 Keycode::F1 => Key::F1,
796 Keycode::F2 => Key::F2,
797 Keycode::F3 => Key::F3,
798 Keycode::F4 => Key::F4,
799 Keycode::F5 => Key::F5,
800 Keycode::F6 => Key::F6,
801 Keycode::F7 => Key::F7,
802 Keycode::F8 => Key::F8,
803 Keycode::F9 => Key::F9,
804 Keycode::F10 => Key::F10,
805 Keycode::F11 => Key::F11,
806 Keycode::F12 => Key::F12,
807
808 Keycode::Minus => Key::Minus,
809 Keycode::Equals => Key::Equals,
810 Keycode::Semicolon => Key::Semicolon,
811 Keycode::Comma => Key::Comma,
812 Keycode::Period => Key::Period,
813 Keycode::Slash => Key::Slash,
814 Keycode::Backslash => Key::Backslash,
815
816 _ => {
817 return None;
818 }
819 })
820}
821
822pub fn into_egui_physical_key(scancode: Scancode) -> Option<Key> {
823 match scancode {
824 Scancode::A => Some(Key::A),
825 Scancode::B => Some(Key::B),
826 Scancode::C => Some(Key::C),
827 Scancode::D => Some(Key::D),
828 Scancode::E => Some(Key::E),
829 Scancode::F => Some(Key::F),
830 Scancode::G => Some(Key::G),
831 Scancode::H => Some(Key::H),
832 Scancode::I => Some(Key::I),
833 Scancode::J => Some(Key::J),
834 Scancode::K => Some(Key::K),
835 Scancode::L => Some(Key::L),
836 Scancode::M => Some(Key::M),
837 Scancode::N => Some(Key::N),
838 Scancode::O => Some(Key::O),
839 Scancode::P => Some(Key::P),
840 Scancode::Q => Some(Key::Q),
841 Scancode::R => Some(Key::R),
842 Scancode::S => Some(Key::S),
843 Scancode::T => Some(Key::T),
844 Scancode::U => Some(Key::U),
845 Scancode::V => Some(Key::V),
846 Scancode::W => Some(Key::W),
847 Scancode::X => Some(Key::X),
848 Scancode::Y => Some(Key::Y),
849 Scancode::Z => Some(Key::Z),
850
851 Scancode::_0 => Some(Key::Num0),
852 Scancode::_1 => Some(Key::Num1),
853 Scancode::_2 => Some(Key::Num2),
854 Scancode::_3 => Some(Key::Num3),
855 Scancode::_4 => Some(Key::Num4),
856 Scancode::_5 => Some(Key::Num5),
857 Scancode::_6 => Some(Key::Num6),
858 Scancode::_7 => Some(Key::Num7),
859 Scancode::_8 => Some(Key::Num8),
860 Scancode::_9 => Some(Key::Num9),
861
862 Scancode::F1 => Some(Key::F1),
863 Scancode::F2 => Some(Key::F2),
864 Scancode::F3 => Some(Key::F3),
865 Scancode::F4 => Some(Key::F4),
866 Scancode::F5 => Some(Key::F5),
867 Scancode::F6 => Some(Key::F6),
868 Scancode::F7 => Some(Key::F7),
869 Scancode::F8 => Some(Key::F8),
870 Scancode::F9 => Some(Key::F9),
871 Scancode::F10 => Some(Key::F10),
872 Scancode::F11 => Some(Key::F11),
873 Scancode::F12 => Some(Key::F12),
874
875 Scancode::Up => Some(Key::ArrowUp),
876 Scancode::Down => Some(Key::ArrowDown),
877 Scancode::Left => Some(Key::ArrowLeft),
878 Scancode::Right => Some(Key::ArrowRight),
879
880 Scancode::Return => Some(Key::Enter),
881 Scancode::Escape => Some(Key::Escape),
882 Scancode::Backspace => Some(Key::Backspace),
883 Scancode::Tab => Some(Key::Tab),
884 Scancode::Space => Some(Key::Space),
885
886 _ => None,
887 }
888}
889
890struct TouchInfo {
891 phase: egui::TouchPhase,
892 touch_id: u64,
893 finger_id: u64,
894 x: f32,
895 y: f32,
896 pressure: f32,
897}