shortcut.rs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2025 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use async_trait::async_trait;
  19. use miniquad::{KeyCode, KeyMods};
  20. use std::sync::Arc;
  21. use crate::{
  22. prop::{
  23. PropertyBool, PropertyColor, PropertyFloat32, PropertyPtr, PropertyRect, PropertyStr,
  24. PropertyUint32, Role,
  25. },
  26. scene::{Pimpl, SceneNodePtr, SceneNodeWeak},
  27. };
  28. use super::UIObject;
  29. macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui::shortcut", $($arg)*); } }
  30. macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::shortcut", $($arg)*); } }
  31. fn vec_to_string(v: Vec<&str>) -> Vec<String> {
  32. v.into_iter().map(|s| s.to_string()).collect()
  33. }
  34. pub type ShortcutPtr = Arc<Shortcut>;
  35. pub struct Shortcut {
  36. node: SceneNodeWeak,
  37. key: PropertyPtr,
  38. priority: PropertyUint32,
  39. }
  40. impl Shortcut {
  41. pub async fn new(node: SceneNodeWeak) -> Pimpl {
  42. t!("Shortcut::new()");
  43. let node_ref = &node.upgrade().unwrap();
  44. let key = node_ref.get_property("key").unwrap();
  45. let priority = PropertyUint32::wrap(node_ref, Role::Internal, "priority", 0).unwrap();
  46. let self_ = Arc::new(Self { node, key, priority });
  47. Pimpl::Shortcut(self_)
  48. }
  49. fn get_key_combo(&self) -> Option<Vec<String>> {
  50. let Ok(key) = self.key.get_str(0) else { return None };
  51. let keys: Vec<&str> = key.split('+').collect();
  52. Some(vec_to_string(keys))
  53. }
  54. }
  55. #[async_trait]
  56. impl UIObject for Shortcut {
  57. fn priority(&self) -> u32 {
  58. self.priority.get()
  59. }
  60. async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool {
  61. t!("handle_key_down({key:?}, {mods:?}, {repeat})");
  62. if repeat {
  63. return false
  64. }
  65. let Some(mut shortcut) = self.get_key_combo() else { return false };
  66. let mut keys = keycode_to_strs(key, mods);
  67. shortcut.sort();
  68. keys.sort();
  69. if shortcut != keys {
  70. t!("shortcut({:?}): {shortcut:?} != {keys:?}", self.node.upgrade().unwrap());
  71. return false
  72. }
  73. let node = self.node.upgrade().unwrap();
  74. d!("Shortcut invoked: {node:?}");
  75. node.trigger("shortcut", vec![]).await.unwrap();
  76. true
  77. }
  78. }
  79. fn keycode_to_strs(key: KeyCode, mods: KeyMods) -> Vec<String> {
  80. let mut keys = vec![];
  81. if mods.shift {
  82. keys.push("shift");
  83. }
  84. if mods.ctrl {
  85. keys.push("ctrl");
  86. }
  87. if mods.alt {
  88. keys.push("alt");
  89. }
  90. if mods.logo {
  91. keys.push("logo");
  92. }
  93. match key {
  94. KeyCode::Space => keys.push("space"),
  95. KeyCode::Apostrophe => keys.push("'"),
  96. KeyCode::Comma => keys.push(","),
  97. KeyCode::Minus => keys.push("-"),
  98. KeyCode::Period => keys.push("."),
  99. KeyCode::Slash => keys.push("/"),
  100. KeyCode::Key0 => keys.push("0"),
  101. KeyCode::Key1 => keys.push("1"),
  102. KeyCode::Key2 => keys.push("2"),
  103. KeyCode::Key3 => keys.push("3"),
  104. KeyCode::Key4 => keys.push("4"),
  105. KeyCode::Key5 => keys.push("5"),
  106. KeyCode::Key6 => keys.push("6"),
  107. KeyCode::Key7 => keys.push("7"),
  108. KeyCode::Key8 => keys.push("8"),
  109. KeyCode::Key9 => keys.push("9"),
  110. KeyCode::Semicolon => keys.push(";"),
  111. KeyCode::Equal => keys.push("="),
  112. KeyCode::A => keys.push("a"),
  113. KeyCode::B => keys.push("b"),
  114. KeyCode::C => keys.push("c"),
  115. KeyCode::D => keys.push("d"),
  116. KeyCode::E => keys.push("e"),
  117. KeyCode::F => keys.push("f"),
  118. KeyCode::G => keys.push("g"),
  119. KeyCode::H => keys.push("h"),
  120. KeyCode::I => keys.push("i"),
  121. KeyCode::J => keys.push("j"),
  122. KeyCode::K => keys.push("k"),
  123. KeyCode::L => keys.push("l"),
  124. KeyCode::M => keys.push("m"),
  125. KeyCode::N => keys.push("n"),
  126. KeyCode::O => keys.push("o"),
  127. KeyCode::P => keys.push("p"),
  128. KeyCode::Q => keys.push("q"),
  129. KeyCode::R => keys.push("r"),
  130. KeyCode::S => keys.push("s"),
  131. KeyCode::T => keys.push("t"),
  132. KeyCode::U => keys.push("u"),
  133. KeyCode::V => keys.push("v"),
  134. KeyCode::W => keys.push("w"),
  135. KeyCode::X => keys.push("x"),
  136. KeyCode::Y => keys.push("y"),
  137. KeyCode::Z => keys.push("z"),
  138. KeyCode::LeftBracket => keys.push("("),
  139. KeyCode::Backslash => keys.push("\\"),
  140. KeyCode::RightBracket => keys.push(")"),
  141. KeyCode::GraveAccent => keys.push("graveaccent"),
  142. KeyCode::World1 => keys.push("world1"),
  143. KeyCode::World2 => keys.push("world2"),
  144. KeyCode::Escape => keys.push("esc"),
  145. KeyCode::Enter => keys.push("enter"),
  146. KeyCode::Tab => keys.push("tab"),
  147. KeyCode::Backspace => keys.push("backspace"),
  148. KeyCode::Insert => keys.push("ins"),
  149. KeyCode::Delete => keys.push("del"),
  150. KeyCode::Right => keys.push("right"),
  151. KeyCode::Left => keys.push("left"),
  152. KeyCode::Down => keys.push("down"),
  153. KeyCode::Up => keys.push("up"),
  154. KeyCode::PageUp => keys.push("pageup"),
  155. KeyCode::PageDown => keys.push("pagedown"),
  156. KeyCode::Home => keys.push("home"),
  157. KeyCode::End => keys.push("end"),
  158. KeyCode::CapsLock => keys.push("capslock"),
  159. KeyCode::ScrollLock => keys.push("scrolllock"),
  160. KeyCode::NumLock => keys.push("numlock"),
  161. KeyCode::PrintScreen => keys.push("printscreen"),
  162. KeyCode::Pause => keys.push("pause"),
  163. KeyCode::F1 => keys.push("f1"),
  164. KeyCode::F2 => keys.push("f2"),
  165. KeyCode::F3 => keys.push("f3"),
  166. KeyCode::F4 => keys.push("f4"),
  167. KeyCode::F5 => keys.push("f5"),
  168. KeyCode::F6 => keys.push("f6"),
  169. KeyCode::F7 => keys.push("f7"),
  170. KeyCode::F8 => keys.push("f8"),
  171. KeyCode::F9 => keys.push("f9"),
  172. KeyCode::F10 => keys.push("f10"),
  173. KeyCode::F11 => keys.push("f11"),
  174. KeyCode::F12 => keys.push("f12"),
  175. KeyCode::F13 => keys.push("f13"),
  176. KeyCode::F14 => keys.push("f14"),
  177. KeyCode::F15 => keys.push("f15"),
  178. KeyCode::F16 => keys.push("f16"),
  179. KeyCode::F17 => keys.push("f17"),
  180. KeyCode::F18 => keys.push("f18"),
  181. KeyCode::F19 => keys.push("f19"),
  182. KeyCode::F20 => keys.push("f20"),
  183. KeyCode::F21 => keys.push("f21"),
  184. KeyCode::F22 => keys.push("f22"),
  185. KeyCode::F23 => keys.push("f23"),
  186. KeyCode::F24 => keys.push("f24"),
  187. KeyCode::F25 => keys.push("f25"),
  188. KeyCode::Kp0 => keys.push("kp0"),
  189. KeyCode::Kp1 => keys.push("kp1"),
  190. KeyCode::Kp2 => keys.push("kp2"),
  191. KeyCode::Kp3 => keys.push("kp3"),
  192. KeyCode::Kp4 => keys.push("kp4"),
  193. KeyCode::Kp5 => keys.push("kp5"),
  194. KeyCode::Kp6 => keys.push("kp6"),
  195. KeyCode::Kp7 => keys.push("kp7"),
  196. KeyCode::Kp8 => keys.push("kp8"),
  197. KeyCode::Kp9 => keys.push("kp9"),
  198. KeyCode::KpDecimal => keys.push("kpdecimal"),
  199. KeyCode::KpDivide => keys.push("kpdivide"),
  200. KeyCode::KpMultiply => keys.push("kpmultiply"),
  201. KeyCode::KpSubtract => keys.push("kpsubtract"),
  202. KeyCode::KpAdd => keys.push("kpadd"),
  203. KeyCode::KpEnter => keys.push("kpenter"),
  204. KeyCode::KpEqual => keys.push("kpequal"),
  205. KeyCode::LeftShift |
  206. KeyCode::LeftControl |
  207. KeyCode::LeftAlt |
  208. KeyCode::LeftSuper |
  209. KeyCode::RightShift |
  210. KeyCode::RightControl |
  211. KeyCode::RightAlt |
  212. KeyCode::RightSuper => {}
  213. KeyCode::Menu => keys.push("menu"),
  214. KeyCode::Back => keys.push("back"),
  215. KeyCode::Unknown => {
  216. // Do nothing...
  217. }
  218. }
  219. vec_to_string(keys)
  220. }