Sfoglia il codice sorgente

wallet: correctly handle repeating keys with smoothing

darkfi 2 anni fa
parent
commit
149859454c
3 ha cambiato i file con 572 aggiunte e 147 eliminazioni
  1. 116 13
      bin/darkwallet/src/editbox.rs
  2. 37 134
      bin/darkwallet/src/gfx.rs
  3. 419 0
      bin/darkwallet/src/keysym.rs

+ 116 - 13
bin/darkwallet/src/editbox.rs

@@ -1,6 +1,8 @@
 use miniquad::{KeyMods, UniformType, MouseButton, window};
 use miniquad::{KeyMods, UniformType, MouseButton, window};
 use log::info;
 use log::info;
-use std::{io::Cursor, sync::{Arc, Mutex}};
+use std::{
+    collections::HashMap,
+    io::Cursor, sync::{Arc, Mutex}, time::{Instant, Duration}};
 use darkfi_serial::Decodable;
 use darkfi_serial::Decodable;
 use freetype as ft;
 use freetype as ft;
 
 
@@ -10,6 +12,69 @@ use crate::{error::{Error, Result}, prop::{
 
 
 const CURSOR_WIDTH: f32 = 4.;
 const CURSOR_WIDTH: f32 = 4.;
 
 
+struct PressedKeysSmoothRepeat {
+    /// When holding keys, we track from start and last sent time.
+    /// This is useful for initial delay and smooth scrolling.
+    pressed_keys: HashMap<String, RepeatingKeyTimer>,
+    /// Initial delay before allowing keys
+    start_delay: u32,
+    /// Minimum time between repeated keys
+    step_time: u32,
+}
+
+impl PressedKeysSmoothRepeat {
+    fn new(start_delay: u32, step_time: u32) -> Self {
+        Self {
+            pressed_keys: HashMap::new(),
+            start_delay,
+            step_time
+        }
+    }
+
+    fn key_down(&mut self, key: &str, repeat: bool) -> u32 {
+        if !repeat {
+            return 1;
+        }
+
+        // Insert key if not exists
+        if !self.pressed_keys.contains_key(key) {
+            self.pressed_keys.insert(key.to_string(), RepeatingKeyTimer::new());
+        }
+
+        let repeater = self.pressed_keys.get_mut(key).expect("repeat map");
+        repeater.update(self.start_delay, self.step_time)
+    }
+
+    fn key_up(&mut self, key: &str) {
+        self.pressed_keys.remove(key);
+    }
+}
+
+struct RepeatingKeyTimer {
+    start: Instant,
+    actions: u32,
+}
+
+impl RepeatingKeyTimer {
+    fn new() -> Self {
+        Self {
+            start: Instant::now(),
+            actions: 0
+        }
+    }
+
+    fn update(&mut self, start_delay: u32, step_time: u32) -> u32 {
+        let elapsed = self.start.elapsed().as_millis();
+        if elapsed < start_delay as u128 {
+            return 0
+        }
+        let total_actions = ((elapsed - start_delay as u128) / step_time as u128) as u32;
+        let remaining_actions = total_actions - self.actions;
+        self.actions = total_actions;
+        remaining_actions
+    }
+}
+
 pub type EditBoxPtr = Arc<EditBox>;
 pub type EditBoxPtr = Arc<EditBox>;
 
 
 pub struct EditBox {
 pub struct EditBox {
@@ -28,11 +93,13 @@ pub struct EditBox {
     world_rect: Mutex<Rectangle<f32>>,
     world_rect: Mutex<Rectangle<f32>>,
     glyphs: Mutex<Vec<Glyph>>,
     glyphs: Mutex<Vec<Glyph>>,
     text_shaper: TextShaper,
     text_shaper: TextShaper,
+    key_repeat: Mutex<PressedKeysSmoothRepeat>,
 }
 }
 
 
 impl EditBox {
 impl EditBox {
     pub fn new(scene_graph: &mut SceneGraph, node_id: SceneNodeId, font_faces: Vec<FreetypeFace>) -> Result<Pimpl> {
     pub fn new(scene_graph: &mut SceneGraph, node_id: SceneNodeId, font_faces: Vec<FreetypeFace>) -> Result<Pimpl> {
         let node = scene_graph.get_node(node_id).unwrap();
         let node = scene_graph.get_node(node_id).unwrap();
+        let node_name = node.name.clone();
         let is_active = PropertyBool::wrap(node, "is_active", 0)?;
         let is_active = PropertyBool::wrap(node, "is_active", 0)?;
         let debug = PropertyBool::wrap(node, "debug", 0)?;
         let debug = PropertyBool::wrap(node, "debug", 0)?;
         let baseline = PropertyFloat32::wrap(node, "baseline", 0)?;
         let baseline = PropertyFloat32::wrap(node, "baseline", 0)?;
@@ -65,12 +132,13 @@ impl EditBox {
             world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
             world_rect: Mutex::new(Rectangle { x: 0., y: 0., w: 0., h: 0. }),
             glyphs: Mutex::new(vec![]),
             glyphs: Mutex::new(vec![]),
             text_shaper,
             text_shaper,
+            key_repeat: Mutex::new(PressedKeysSmoothRepeat::new(400, 50)),
         });
         });
         self_.regen_glyphs().unwrap();
         self_.regen_glyphs().unwrap();
 
 
         let weak_self = Arc::downgrade(&self_);
         let weak_self = Arc::downgrade(&self_);
-        let slot = Slot {
-            name: "editbox::key_down".to_string(),
+        let slot_key_down = Slot {
+            name: format!("{}::key_down", node_name),
             func: Box::new(move |data| {
             func: Box::new(move |data| {
                 let mut cur = Cursor::new(&data);
                 let mut cur = Cursor::new(&data);
                 let keymods = KeyMods {
                 let keymods = KeyMods {
@@ -84,7 +152,26 @@ impl EditBox {
 
 
                 let self_ = weak_self.upgrade();
                 let self_ = weak_self.upgrade();
                 if let Some(self_) = self_ {
                 if let Some(self_) = self_ {
-                    self_.key_press(key, keymods, repeat);
+                    self_.key_down(key, keymods, repeat);
+                }
+            }),
+        };
+        let weak_self = Arc::downgrade(&self_);
+        let slot_key_up = Slot {
+            name: format!("{}::key_up", node_name),
+            func: Box::new(move |data| {
+                let mut cur = Cursor::new(&data);
+                let keymods = KeyMods {
+                    shift: Decodable::decode(&mut cur).unwrap(),
+                    ctrl: Decodable::decode(&mut cur).unwrap(),
+                    alt: Decodable::decode(&mut cur).unwrap(),
+                    logo: Decodable::decode(&mut cur).unwrap(),
+                };
+                let key = String::decode(&mut cur).unwrap();
+
+                let self_ = weak_self.upgrade();
+                if let Some(self_) = self_ {
+                    self_.key_up(key, keymods);
                 }
                 }
             }),
             }),
         };
         };
@@ -93,11 +180,12 @@ impl EditBox {
             scene_graph
             scene_graph
             .lookup_node_mut("/window/input/keyboard")
             .lookup_node_mut("/window/input/keyboard")
             .expect("no keyboard attached!");
             .expect("no keyboard attached!");
-        keyb_node.register("key_down", slot);
+        keyb_node.register("key_down", slot_key_down);
+        keyb_node.register("key_up", slot_key_up);
 
 
         let weak_self = Arc::downgrade(&self_);
         let weak_self = Arc::downgrade(&self_);
         let slot_btn_down = Slot {
         let slot_btn_down = Slot {
-            name: "editbox::mouse_button_down".to_string(),
+            name: format!("{}::mouse_button_down", node_name),
             func: Box::new(move |data| {
             func: Box::new(move |data| {
                 let mut cur = Cursor::new(&data);
                 let mut cur = Cursor::new(&data);
                 let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
                 let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
@@ -113,7 +201,7 @@ impl EditBox {
 
 
         let weak_self = Arc::downgrade(&self_);
         let weak_self = Arc::downgrade(&self_);
         let slot_btn_up = Slot {
         let slot_btn_up = Slot {
-            name: "editbox::mouse_button_up".to_string(),
+            name: format!("{}::mouse_button_up", node_name),
             func: Box::new(move |data| {
             func: Box::new(move |data| {
                 let mut cur = Cursor::new(&data);
                 let mut cur = Cursor::new(&data);
                 let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
                 let button = MouseButton::from_u8(u8::decode(&mut cur).unwrap());
@@ -129,7 +217,7 @@ impl EditBox {
 
 
         let weak_self = Arc::downgrade(&self_);
         let weak_self = Arc::downgrade(&self_);
         let slot_move = Slot {
         let slot_move = Slot {
-            name: "editbox::mouse_move".to_string(),
+            name: format!("{}::mouse_move", node_name),
             func: Box::new(move |data| {
             func: Box::new(move |data| {
                 let mut cur = Cursor::new(&data);
                 let mut cur = Cursor::new(&data);
                 let x = f32::decode(&mut cur).unwrap();
                 let x = f32::decode(&mut cur).unwrap();
@@ -325,14 +413,21 @@ impl EditBox {
         Ok(())
         Ok(())
     }
     }
 
 
-    fn key_press(self: Arc<Self>, key: String, mods: KeyMods, repeat: bool) {
-        if repeat {
-            return;
-        }
+    fn key_down(self: Arc<Self>, key: String, mods: KeyMods, repeat: bool) {
         if !self.is_active.get() {
         if !self.is_active.get() {
             return
             return
         }
         }
-        match key.as_str() {
+        let actions = {
+            let mut repeater = self.key_repeat.lock().unwrap();
+            repeater.key_down(&key, repeat)
+        };
+        for _ in 0..actions {
+            self.do_key_down(&key, &mods)
+        }
+    }
+
+    fn do_key_down(&self, key: &str, mods: &KeyMods) {
+        match key {
             "PageUp" => {
             "PageUp" => {
                 println!("pageup!");
                 println!("pageup!");
             }
             }
@@ -429,6 +524,9 @@ impl EditBox {
         }
         }
     }
     }
 
 
+    fn insert_char(key: String) {
+    }
+
     fn copy_highlighted_text(&self) -> Result<()> {
     fn copy_highlighted_text(&self) -> Result<()> {
         let start = self.selected.get_u32(0)? as usize;
         let start = self.selected.get_u32(0)? as usize;
         let end = self.selected.get_u32(1)? as usize;
         let end = self.selected.get_u32(1)? as usize;
@@ -450,6 +548,11 @@ impl EditBox {
         Ok(())
         Ok(())
     }
     }
 
 
+    fn key_up(self: Arc<Self>, key: String, mods: KeyMods) {
+        let mut repeater = self.key_repeat.lock().unwrap();
+        repeater.key_up(&key);
+    }
+
     fn mouse_button_down(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
     fn mouse_button_down(self: Arc<Self>, button: MouseButton, x: f32, y: f32) {
         let mouse_pos = Point { x, y };
         let mouse_pos = Point { x, y };
         let rect = self.world_rect.lock().unwrap();
         let rect = self.world_rect.lock().unwrap();

+ 37 - 134
bin/darkwallet/src/gfx.rs

@@ -18,7 +18,7 @@ use crate::{
     error::{Error, Result},
     error::{Error, Result},
     editbox,
     editbox,
     expr::{SExprMachine, SExprVal},
     expr::{SExprMachine, SExprVal},
-    keysym::MouseButtonAsU8,
+    keysym::{KeyCodeAsStr, MouseButtonAsU8},
     prop::{Property, PropertySubType, PropertyType},
     prop::{Property, PropertySubType, PropertyType},
     res::{ResourceId, ResourceManager},
     res::{ResourceId, ResourceManager},
     scene::{
     scene::{
@@ -288,6 +288,19 @@ impl Stage {
             ],
             ],
         )
         )
         .unwrap();
         .unwrap();
+        keyb.add_signal(
+            "key_up",
+            "Key press up event",
+            vec![
+                ("shift", "", PropertyType::Bool),
+                ("ctrl", "", PropertyType::Bool),
+                ("alt", "", PropertyType::Bool),
+                ("logo", "", PropertyType::Bool),
+                ("repeat", "", PropertyType::Bool),
+                ("keycode", "", PropertyType::Enum),
+            ],
+        )
+        .unwrap();
         let keyb_id = keyb.id;
         let keyb_id = keyb.id;
         scene_graph.link(keyb_id, input_id).unwrap();
         scene_graph.link(keyb_id, input_id).unwrap();
 
 
@@ -1035,140 +1048,30 @@ impl EventHandler for Stage {
         let mut scene_graph = self.scene_graph.lock().unwrap();
         let mut scene_graph = self.scene_graph.lock().unwrap();
         let win = scene_graph.lookup_node_mut("/window/input/keyboard").unwrap();
         let win = scene_graph.lookup_node_mut("/window/input/keyboard").unwrap();
 
 
-        let send_key_down = |key: &str| {
-            let mut data = vec![];
-            modifiers.shift.encode(&mut data).unwrap();
-            modifiers.ctrl.encode(&mut data).unwrap();
-            modifiers.alt.encode(&mut data).unwrap();
-            modifiers.logo.encode(&mut data).unwrap();
-            repeat.encode(&mut data).unwrap();
-            key.encode(&mut data).unwrap();
-            win.trigger("key_down", data).unwrap();
-        };
+        let key = keycode.to_str();
 
 
-        match keycode {
-            KeyCode::Space => send_key_down(" "),
-            KeyCode::Apostrophe => send_key_down("'"),
-            KeyCode::Comma => send_key_down(","),
-            KeyCode::Minus => send_key_down("-"),
-            KeyCode::Period => send_key_down("."),
-            KeyCode::Slash => send_key_down("/"),
-            KeyCode::Key0 => send_key_down("0"),
-            KeyCode::Key1 => send_key_down("1"),
-            KeyCode::Key2 => send_key_down("2"),
-            KeyCode::Key3 => send_key_down("3"),
-            KeyCode::Key4 => send_key_down("4"),
-            KeyCode::Key5 => send_key_down("5"),
-            KeyCode::Key6 => send_key_down("6"),
-            KeyCode::Key7 => send_key_down("7"),
-            KeyCode::Key8 => send_key_down("8"),
-            KeyCode::Key9 => send_key_down("9"),
-            KeyCode::Semicolon => send_key_down(":"),
-            KeyCode::Equal => send_key_down("="),
-            KeyCode::A => send_key_down("A"),
-            KeyCode::B => send_key_down("B"),
-            KeyCode::C => send_key_down("C"),
-            KeyCode::D => send_key_down("D"),
-            KeyCode::E => send_key_down("E"),
-            KeyCode::F => send_key_down("F"),
-            KeyCode::G => send_key_down("G"),
-            KeyCode::H => send_key_down("H"),
-            KeyCode::I => send_key_down("I"),
-            KeyCode::J => send_key_down("J"),
-            KeyCode::K => send_key_down("K"),
-            KeyCode::L => send_key_down("L"),
-            KeyCode::M => send_key_down("M"),
-            KeyCode::N => send_key_down("N"),
-            KeyCode::O => send_key_down("O"),
-            KeyCode::P => send_key_down("P"),
-            KeyCode::Q => send_key_down("Q"),
-            KeyCode::R => send_key_down("R"),
-            KeyCode::S => send_key_down("S"),
-            KeyCode::T => send_key_down("T"),
-            KeyCode::U => send_key_down("U"),
-            KeyCode::V => send_key_down("V"),
-            KeyCode::W => send_key_down("W"),
-            KeyCode::X => send_key_down("X"),
-            KeyCode::Y => send_key_down("Y"),
-            KeyCode::Z => send_key_down("Z"),
-            KeyCode::LeftBracket => send_key_down("("),
-            KeyCode::Backslash => send_key_down("\\"),
-            KeyCode::RightBracket => send_key_down(")"),
-            KeyCode::GraveAccent => send_key_down("GraveAccent"),
-            KeyCode::World1 => send_key_down("World1"),
-            KeyCode::World2 => send_key_down("World2"),
-            KeyCode::Escape => send_key_down("Escape"),
-            KeyCode::Enter => send_key_down("Enter"),
-            KeyCode::Tab => send_key_down("Tab"),
-            KeyCode::Backspace => send_key_down("Backspace"),
-            KeyCode::Insert => send_key_down("Insert"),
-            KeyCode::Delete => send_key_down("Delete"),
-            KeyCode::Right => send_key_down("Right"),
-            KeyCode::Left => send_key_down("Left"),
-            KeyCode::Down => send_key_down("Down"),
-            KeyCode::Up => send_key_down("Up"),
-            KeyCode::PageUp => send_key_down("PageUp"),
-            KeyCode::PageDown => send_key_down("PageDown"),
-            KeyCode::Home => send_key_down("Home"),
-            KeyCode::End => send_key_down("End"),
-            KeyCode::CapsLock => send_key_down("CapsLock"),
-            KeyCode::ScrollLock => send_key_down("ScrollLock"),
-            KeyCode::NumLock => send_key_down("NumLock"),
-            KeyCode::PrintScreen => send_key_down("PrintScreen"),
-            KeyCode::Pause => send_key_down("Pause"),
-            KeyCode::F1 => send_key_down("F1"),
-            KeyCode::F2 => send_key_down("F2"),
-            KeyCode::F3 => send_key_down("F3"),
-            KeyCode::F4 => send_key_down("F4"),
-            KeyCode::F5 => send_key_down("F5"),
-            KeyCode::F6 => send_key_down("F6"),
-            KeyCode::F7 => send_key_down("F7"),
-            KeyCode::F8 => send_key_down("F8"),
-            KeyCode::F9 => send_key_down("F9"),
-            KeyCode::F10 => send_key_down("F10"),
-            KeyCode::F11 => send_key_down("F11"),
-            KeyCode::F12 => send_key_down("F12"),
-            KeyCode::F13 => send_key_down("F13"),
-            KeyCode::F14 => send_key_down("F14"),
-            KeyCode::F15 => send_key_down("F15"),
-            KeyCode::F16 => send_key_down("F16"),
-            KeyCode::F17 => send_key_down("F17"),
-            KeyCode::F18 => send_key_down("F18"),
-            KeyCode::F19 => send_key_down("F19"),
-            KeyCode::F20 => send_key_down("F20"),
-            KeyCode::F21 => send_key_down("F21"),
-            KeyCode::F22 => send_key_down("F22"),
-            KeyCode::F23 => send_key_down("F23"),
-            KeyCode::F24 => send_key_down("F24"),
-            KeyCode::F25 => send_key_down("F25"),
-            KeyCode::Kp0 => send_key_down("Kp0"),
-            KeyCode::Kp1 => send_key_down("Kp1"),
-            KeyCode::Kp2 => send_key_down("Kp2"),
-            KeyCode::Kp3 => send_key_down("Kp3"),
-            KeyCode::Kp4 => send_key_down("Kp4"),
-            KeyCode::Kp5 => send_key_down("Kp5"),
-            KeyCode::Kp6 => send_key_down("Kp6"),
-            KeyCode::Kp7 => send_key_down("Kp7"),
-            KeyCode::Kp8 => send_key_down("Kp8"),
-            KeyCode::Kp9 => send_key_down("Kp9"),
-            KeyCode::KpDecimal => send_key_down("KpDecimal"),
-            KeyCode::KpDivide => send_key_down("KpDivide"),
-            KeyCode::KpMultiply => send_key_down("KpMultiply"),
-            KeyCode::KpSubtract => send_key_down("KpSubtract"),
-            KeyCode::KpAdd => send_key_down("KpAdd"),
-            KeyCode::KpEnter => send_key_down("KpEnter"),
-            KeyCode::KpEqual => send_key_down("KpEqual"),
-            KeyCode::LeftShift => send_key_down("LeftShift"),
-            KeyCode::LeftControl => send_key_down("LeftControl"),
-            KeyCode::LeftAlt => send_key_down("LeftAlt"),
-            KeyCode::LeftSuper => send_key_down("LeftSuper"),
-            KeyCode::RightShift => send_key_down("RightShift"),
-            KeyCode::RightControl => send_key_down("RightControl"),
-            KeyCode::RightAlt => send_key_down("RightAlt"),
-            KeyCode::RightSuper => send_key_down("RightSuper"),
-            KeyCode::Menu => send_key_down("Menu"),
-            KeyCode::Unknown => send_key_down("Unknown"),
-        }
+        let mut data = vec![];
+        modifiers.shift.encode(&mut data).unwrap();
+        modifiers.ctrl.encode(&mut data).unwrap();
+        modifiers.alt.encode(&mut data).unwrap();
+        modifiers.logo.encode(&mut data).unwrap();
+        repeat.encode(&mut data).unwrap();
+        key.encode(&mut data).unwrap();
+        win.trigger("key_down", data).unwrap();
+    }
+    fn key_up_event(&mut self, keycode: KeyCode, modifiers: KeyMods) {
+        let mut scene_graph = self.scene_graph.lock().unwrap();
+        let win = scene_graph.lookup_node_mut("/window/input/keyboard").unwrap();
+
+        let key = keycode.to_str();
+
+        let mut data = vec![];
+        modifiers.shift.encode(&mut data).unwrap();
+        modifiers.ctrl.encode(&mut data).unwrap();
+        modifiers.alt.encode(&mut data).unwrap();
+        modifiers.logo.encode(&mut data).unwrap();
+        key.encode(&mut data).unwrap();
+        win.trigger("key_up", data).unwrap();
     }
     }
     fn mouse_motion_event(&mut self, x: f32, y: f32) {
     fn mouse_motion_event(&mut self, x: f32, y: f32) {
         let mut scene_graph = self.scene_graph.lock().unwrap();
         let mut scene_graph = self.scene_graph.lock().unwrap();

+ 419 - 0
bin/darkwallet/src/keysym.rs

@@ -0,0 +1,419 @@
+use miniquad::{
+    KeyCode, MouseButton
+};
+
+pub trait KeyCodeAsStr {
+    fn to_str(&self) -> &str;
+}
+
+impl KeyCodeAsStr for KeyCode {
+    fn to_str(&self) -> &str {
+        match self {
+            Self::Space => " ",
+            Self::Apostrophe => "'",
+            Self::Comma => ",",
+            Self::Minus => "-",
+            Self::Period => ".",
+            Self::Slash => "/",
+            Self::Key0 => "0",
+            Self::Key1 => "1",
+            Self::Key2 => "2",
+            Self::Key3 => "3",
+            Self::Key4 => "4",
+            Self::Key5 => "5",
+            Self::Key6 => "6",
+            Self::Key7 => "7",
+            Self::Key8 => "8",
+            Self::Key9 => "9",
+            Self::Semicolon => ":",
+            Self::Equal => "=",
+            Self::A => "A",
+            Self::B => "B",
+            Self::C => "C",
+            Self::D => "D",
+            Self::E => "E",
+            Self::F => "F",
+            Self::G => "G",
+            Self::H => "H",
+            Self::I => "I",
+            Self::J => "J",
+            Self::K => "K",
+            Self::L => "L",
+            Self::M => "M",
+            Self::N => "N",
+            Self::O => "O",
+            Self::P => "P",
+            Self::Q => "Q",
+            Self::R => "R",
+            Self::S => "S",
+            Self::T => "T",
+            Self::U => "U",
+            Self::V => "V",
+            Self::W => "W",
+            Self::X => "X",
+            Self::Y => "Y",
+            Self::Z => "Z",
+            Self::LeftBracket => "(",
+            Self::Backslash => "\\",
+            Self::RightBracket => ")",
+            Self::GraveAccent => "GraveAccent",
+            Self::World1 => "World1",
+            Self::World2 => "World2",
+            Self::Escape => "Escape",
+            Self::Enter => "Enter",
+            Self::Tab => "Tab",
+            Self::Backspace => "Backspace",
+            Self::Insert => "Insert",
+            Self::Delete => "Delete",
+            Self::Right => "Right",
+            Self::Left => "Left",
+            Self::Down => "Down",
+            Self::Up => "Up",
+            Self::PageUp => "PageUp",
+            Self::PageDown => "PageDown",
+            Self::Home => "Home",
+            Self::End => "End",
+            Self::CapsLock => "CapsLock",
+            Self::ScrollLock => "ScrollLock",
+            Self::NumLock => "NumLock",
+            Self::PrintScreen => "PrintScreen",
+            Self::Pause => "Pause",
+            Self::F1 => "F1",
+            Self::F2 => "F2",
+            Self::F3 => "F3",
+            Self::F4 => "F4",
+            Self::F5 => "F5",
+            Self::F6 => "F6",
+            Self::F7 => "F7",
+            Self::F8 => "F8",
+            Self::F9 => "F9",
+            Self::F10 => "F10",
+            Self::F11 => "F11",
+            Self::F12 => "F12",
+            Self::F13 => "F13",
+            Self::F14 => "F14",
+            Self::F15 => "F15",
+            Self::F16 => "F16",
+            Self::F17 => "F17",
+            Self::F18 => "F18",
+            Self::F19 => "F19",
+            Self::F20 => "F20",
+            Self::F21 => "F21",
+            Self::F22 => "F22",
+            Self::F23 => "F23",
+            Self::F24 => "F24",
+            Self::F25 => "F25",
+            Self::Kp0 => "Kp0",
+            Self::Kp1 => "Kp1",
+            Self::Kp2 => "Kp2",
+            Self::Kp3 => "Kp3",
+            Self::Kp4 => "Kp4",
+            Self::Kp5 => "Kp5",
+            Self::Kp6 => "Kp6",
+            Self::Kp7 => "Kp7",
+            Self::Kp8 => "Kp8",
+            Self::Kp9 => "Kp9",
+            Self::KpDecimal => "KpDecimal",
+            Self::KpDivide => "KpDivide",
+            Self::KpMultiply => "KpMultiply",
+            Self::KpSubtract => "KpSubtract",
+            Self::KpAdd => "KpAdd",
+            Self::KpEnter => "KpEnter",
+            Self::KpEqual => "KpEqual",
+            Self::LeftShift => "LeftShift",
+            Self::LeftControl => "LeftControl",
+            Self::LeftAlt => "LeftAlt",
+            Self::LeftSuper => "LeftSuper",
+            Self::RightShift => "RightShift",
+            Self::RightControl => "RightControl",
+            Self::RightAlt => "RightAlt",
+            Self::RightSuper => "RightSuper",
+            Self::Menu => "Menu",
+            Self::Unknown => "Unknown",
+        }
+    }
+}
+
+pub trait KeyCodeAsU16 {
+    fn to_u16(&self) -> u16;
+    fn from_u16(keysym: u16) -> Self;
+}
+
+impl KeyCodeAsU16 for KeyCode {
+    fn to_u16(&self) -> u16 {
+        match self {
+            Self::Space => 0x0020,
+            Self::Apostrophe => 0x0027,
+            Self::Comma => 0x002c,
+            Self::Minus => 0x002d,
+            Self::Period => 0x002e,
+            Self::Slash => 0x002f,
+            Self::Key0 => 0x0030,
+            Self::Key1 => 0x0031,
+            Self::Key2 => 0x0032,
+            Self::Key3 => 0x0033,
+            Self::Key4 => 0x0034,
+            Self::Key5 => 0x0035,
+            Self::Key6 => 0x0036,
+            Self::Key7 => 0x0037,
+            Self::Key8 => 0x0038,
+            Self::Key9 => 0x0039,
+            Self::Semicolon => 0x003b,
+            Self::Equal => 0x003d,
+            Self::A => 0x0041,
+            Self::B => 0x0042,
+            Self::C => 0x0043,
+            Self::D => 0x0044,
+            Self::E => 0x0045,
+            Self::F => 0x0046,
+            Self::G => 0x0047,
+            Self::H => 0x0048,
+            Self::I => 0x0049,
+            Self::J => 0x004a,
+            Self::K => 0x004b,
+            Self::L => 0x004c,
+            Self::M => 0x004d,
+            Self::N => 0x004e,
+            Self::O => 0x004f,
+            Self::P => 0x0050,
+            Self::Q => 0x0051,
+            Self::R => 0x0052,
+            Self::S => 0x0053,
+            Self::T => 0x0054,
+            Self::U => 0x0055,
+            Self::V => 0x0056,
+            Self::W => 0x0057,
+            Self::X => 0x0058,
+            Self::Y => 0x0059,
+            Self::Z => 0x005a,
+            Self::LeftBracket => 0x005b,
+            Self::Backslash => 0x005c,
+            Self::RightBracket => 0x005d,
+            Self::GraveAccent => 0x0060,
+            Self::World1 => 0x0100,
+            Self::World2 => 0x0101,
+            Self::Escape => 0xff1b,
+            Self::Enter => 0xff0d,
+            Self::Tab => 0xff09,
+            Self::Backspace => 0xff08,
+            Self::Insert => 0xff63,
+            Self::Delete => 0xffff,
+            Self::Right => 0xff53,
+            Self::Left => 0xff51,
+            Self::Down => 0xff54,
+            Self::Up => 0xff52,
+            Self::PageUp => 0xff55,
+            Self::PageDown => 0xff56,
+            Self::Home => 0xff50,
+            Self::End => 0xff57,
+            Self::CapsLock => 0xffe5,
+            Self::ScrollLock => 0xff14,
+            Self::NumLock => 0xff7f,
+            Self::PrintScreen => 0xfd1d,
+            Self::Pause => 0xff13,
+            Self::F1 => 0xffbe,
+            Self::F2 => 0xffbf,
+            Self::F3 => 0xffc0,
+            Self::F4 => 0xffc1,
+            Self::F5 => 0xffc2,
+            Self::F6 => 0xffc3,
+            Self::F7 => 0xffc4,
+            Self::F8 => 0xffc5,
+            Self::F9 => 0xffc6,
+            Self::F10 => 0xffc7,
+            Self::F11 => 0xffc8,
+            Self::F12 => 0xffc9,
+            Self::F13 => 0xffca,
+            Self::F14 => 0xffcb,
+            Self::F15 => 0xffcc,
+            Self::F16 => 0xffcd,
+            Self::F17 => 0xffce,
+            Self::F18 => 0xffcf,
+            Self::F19 => 0xffd0,
+            Self::F20 => 0xffd1,
+            Self::F21 => 0xffd2,
+            Self::F22 => 0xffd3,
+            Self::F23 => 0xffd4,
+            Self::F24 => 0xffd5,
+            Self::F25 => 0xffd6,
+            Self::Kp0 => 0xffb0,
+            Self::Kp1 => 0xffb1,
+            Self::Kp2 => 0xffb2,
+            Self::Kp3 => 0xffb3,
+            Self::Kp4 => 0xffb4,
+            Self::Kp5 => 0xffb5,
+            Self::Kp6 => 0xffb6,
+            Self::Kp7 => 0xffb7,
+            Self::Kp8 => 0xffb8,
+            Self::Kp9 => 0xffb9,
+            Self::KpDecimal => 0xffae,
+            Self::KpDivide => 0xffaf,
+            Self::KpMultiply => 0xffaa,
+            Self::KpSubtract => 0xffad,
+            Self::KpAdd => 0xffab,
+            Self::KpEnter => 0xff8d,
+            Self::KpEqual => 0xffbd,
+            Self::LeftShift => 0xffe1,
+            Self::LeftControl => 0xffe3,
+            Self::LeftAlt => 0xffe9,
+            Self::LeftSuper => 0xffeb,
+            Self::RightShift => 0xffe2,
+            Self::RightControl => 0xffe4,
+            Self::RightAlt => 0xffea,
+            Self::RightSuper => 0xffec,
+            Self::Menu => 0xff67,
+            Self::Unknown => 0x01ff,
+        }
+    }
+    fn from_u16(keysym: u16) -> Self {
+        match keysym {
+            0x0020 => Self::Space,
+            0x0027 => Self::Apostrophe,
+            0x002c => Self::Comma,
+            0x002d => Self::Minus,
+            0x002e => Self::Period,
+            0x002f => Self::Slash,
+            0x0030 => Self::Key0,
+            0x0031 => Self::Key1,
+            0x0032 => Self::Key2,
+            0x0033 => Self::Key3,
+            0x0034 => Self::Key4,
+            0x0035 => Self::Key5,
+            0x0036 => Self::Key6,
+            0x0037 => Self::Key7,
+            0x0038 => Self::Key8,
+            0x0039 => Self::Key9,
+            0x003b => Self::Semicolon,
+            0x003d => Self::Equal,
+            0x0041 => Self::A,
+            0x0042 => Self::B,
+            0x0043 => Self::C,
+            0x0044 => Self::D,
+            0x0045 => Self::E,
+            0x0046 => Self::F,
+            0x0047 => Self::G,
+            0x0048 => Self::H,
+            0x0049 => Self::I,
+            0x004a => Self::J,
+            0x004b => Self::K,
+            0x004c => Self::L,
+            0x004d => Self::M,
+            0x004e => Self::N,
+            0x004f => Self::O,
+            0x0050 => Self::P,
+            0x0051 => Self::Q,
+            0x0052 => Self::R,
+            0x0053 => Self::S,
+            0x0054 => Self::T,
+            0x0055 => Self::U,
+            0x0056 => Self::V,
+            0x0057 => Self::W,
+            0x0058 => Self::X,
+            0x0059 => Self::Y,
+            0x005a => Self::Z,
+            0x005b => Self::LeftBracket,
+            0x005c => Self::Backslash,
+            0x005d => Self::RightBracket,
+            0x0060 => Self::GraveAccent,
+            0x0100 => Self::World1,
+            0x0101 => Self::World2,
+            0xff1b => Self::Escape,
+            0xff0d => Self::Enter,
+            0xff09 => Self::Tab,
+            0xff08 => Self::Backspace,
+            0xff63 => Self::Insert,
+            0xffff => Self::Delete,
+            0xff53 => Self::Right,
+            0xff51 => Self::Left,
+            0xff54 => Self::Down,
+            0xff52 => Self::Up,
+            0xff55 => Self::PageUp,
+            0xff56 => Self::PageDown,
+            0xff50 => Self::Home,
+            0xff57 => Self::End,
+            0xffe5 => Self::CapsLock,
+            0xff14 => Self::ScrollLock,
+            0xff7f => Self::NumLock,
+            0xfd1d => Self::PrintScreen,
+            0xff13 => Self::Pause,
+            0xffbe => Self::F1,
+            0xffbf => Self::F2,
+            0xffc0 => Self::F3,
+            0xffc1 => Self::F4,
+            0xffc2 => Self::F5,
+            0xffc3 => Self::F6,
+            0xffc4 => Self::F7,
+            0xffc5 => Self::F8,
+            0xffc6 => Self::F9,
+            0xffc7 => Self::F10,
+            0xffc8 => Self::F11,
+            0xffc9 => Self::F12,
+            0xffca => Self::F13,
+            0xffcb => Self::F14,
+            0xffcc => Self::F15,
+            0xffcd => Self::F16,
+            0xffce => Self::F17,
+            0xffcf => Self::F18,
+            0xffd0 => Self::F19,
+            0xffd1 => Self::F20,
+            0xffd2 => Self::F21,
+            0xffd3 => Self::F22,
+            0xffd4 => Self::F23,
+            0xffd5 => Self::F24,
+            0xffd6 => Self::F25,
+            0xffb0 => Self::Kp0,
+            0xffb1 => Self::Kp1,
+            0xffb2 => Self::Kp2,
+            0xffb3 => Self::Kp3,
+            0xffb4 => Self::Kp4,
+            0xffb5 => Self::Kp5,
+            0xffb6 => Self::Kp6,
+            0xffb7 => Self::Kp7,
+            0xffb8 => Self::Kp8,
+            0xffb9 => Self::Kp9,
+            0xffae => Self::KpDecimal,
+            0xffaf => Self::KpDivide,
+            0xffaa => Self::KpMultiply,
+            0xffad => Self::KpSubtract,
+            0xffab => Self::KpAdd,
+            0xff8d => Self::KpEnter,
+            0xffbd => Self::KpEqual,
+            0xffe1 => Self::LeftShift,
+            0xffe3 => Self::LeftControl,
+            0xffe9 => Self::LeftAlt,
+            0xffeb => Self::LeftSuper,
+            0xffe2 => Self::RightShift,
+            0xffe4 => Self::RightControl,
+            0xffea => Self::RightAlt,
+            0xffec => Self::RightSuper,
+            0xff67 => Self::Menu,
+            _ => Self::Unknown,
+        }
+    }
+}
+
+pub trait MouseButtonAsU8 {
+    fn to_u8(&self) -> u8;
+    fn from_u8(btn: u8) -> Self;
+}
+
+impl MouseButtonAsU8 for MouseButton {
+    fn to_u8(&self) -> u8 {
+        match self {
+            Self::Left => 0,
+            Self::Middle => 1,
+            Self::Right => 2,
+            Self::Unknown => 3,
+        }
+    }
+
+    fn from_u8(btn: u8) -> Self {
+        match btn {
+            0 => Self::Left,
+            1 => Self::Middle,
+            2 => Self::Right,
+            _ => Self::Unknown,
+        }
+    }
+}
+