1
0

hooks.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875
  1. use crossterm::event::{
  2. Event as TermEvent, KeyCode as TermKeyCode, KeyModifiers, MouseButton, MouseEventKind,
  3. };
  4. use dioxus_core::*;
  5. use fxhash::{FxHashMap, FxHashSet};
  6. use dioxus_html::geometry::euclid::{Point2D, Rect, Size2D};
  7. use dioxus_html::geometry::{ClientPoint, Coordinates, ElementPoint, PagePoint, ScreenPoint};
  8. use dioxus_html::input_data::keyboard_types::Modifiers;
  9. use dioxus_html::input_data::MouseButtonSet as DioxusMouseButtons;
  10. use dioxus_html::input_data::{MouseButton as DioxusMouseButton, MouseButtonSet};
  11. use dioxus_html::{on::*, KeyCode};
  12. use std::{
  13. any::Any,
  14. cell::{RefCell, RefMut},
  15. rc::Rc,
  16. sync::Arc,
  17. time::{Duration, Instant},
  18. };
  19. use taffy::geometry::{Point, Size};
  20. use taffy::{prelude::Layout, Taffy};
  21. use crate::FocusState;
  22. use crate::{Dom, Node};
  23. // a wrapper around the input state for easier access
  24. // todo: fix loop
  25. // pub struct InputState(Rc<Rc<RefCell<InnerInputState>>>);
  26. // impl InputState {
  27. // pub fn get(cx: &ScopeState) -> InputState {
  28. // let inner = cx
  29. // .consume_context::<Rc<RefCell<InnerInputState>>>()
  30. // .expect("Rink InputState can only be used in Rink apps!");
  31. // (**inner).borrow_mut().subscribe(cx.schedule_update());
  32. // InputState(inner)
  33. // }
  34. // pub fn mouse(&self) -> Option<MouseData> {
  35. // let data = (**self.0).borrow();
  36. // mouse.as_ref().map(|m| m.clone())
  37. // }
  38. // pub fn wheel(&self) -> Option<WheelData> {
  39. // let data = (**self.0).borrow();
  40. // wheel.as_ref().map(|w| w.clone())
  41. // }
  42. // pub fn screen(&self) -> Option<(u16, u16)> {
  43. // let data = (**self.0).borrow();
  44. // screen.as_ref().map(|m| m.clone())
  45. // }
  46. // pub fn last_key_pressed(&self) -> Option<KeyboardData> {
  47. // let data = (**self.0).borrow();
  48. // last_key_pressed
  49. // .as_ref()
  50. // .map(|k| &k.0.clone())
  51. // }
  52. // }
  53. type EventCore = (&'static str, EventData);
  54. #[derive(Debug)]
  55. enum EventData {
  56. Mouse(MouseData),
  57. Wheel(WheelData),
  58. Screen((u16, u16)),
  59. Keyboard(KeyboardData),
  60. }
  61. impl EventData {
  62. fn into_any(self) -> Arc<dyn Any + Send + Sync> {
  63. match self {
  64. Self::Mouse(m) => Arc::new(m),
  65. Self::Wheel(w) => Arc::new(w),
  66. Self::Screen(s) => Arc::new(s),
  67. Self::Keyboard(k) => Arc::new(k),
  68. }
  69. }
  70. }
  71. const MAX_REPEAT_TIME: Duration = Duration::from_millis(100);
  72. pub struct InnerInputState {
  73. mouse: Option<MouseData>,
  74. wheel: Option<WheelData>,
  75. last_key_pressed: Option<(KeyboardData, Instant)>,
  76. screen: Option<(u16, u16)>,
  77. pub(crate) focus_state: FocusState,
  78. // subscribers: Vec<Rc<dyn Fn() + 'static>>,
  79. }
  80. impl InnerInputState {
  81. fn new() -> Self {
  82. Self {
  83. mouse: None,
  84. wheel: None,
  85. last_key_pressed: None,
  86. screen: None,
  87. // subscribers: Vec::new(),
  88. focus_state: FocusState::default(),
  89. }
  90. }
  91. // stores current input state and transforms events based on that state
  92. fn apply_event(&mut self, evt: &mut EventCore) {
  93. match evt.1 {
  94. // limitations: only two buttons may be held at once
  95. EventData::Mouse(ref mut m) => {
  96. let mut held_buttons = match &self.mouse {
  97. Some(previous_data) => previous_data.held_buttons(),
  98. None => MouseButtonSet::empty(),
  99. };
  100. match evt.0 {
  101. "mousedown" => {
  102. held_buttons.insert(
  103. m.trigger_button()
  104. .expect("No trigger button for mousedown event"),
  105. );
  106. }
  107. "mouseup" => {
  108. held_buttons.remove(
  109. m.trigger_button()
  110. .expect("No trigger button for mouseup event"),
  111. );
  112. }
  113. _ => {}
  114. }
  115. let new_mouse_data = MouseData::new(
  116. m.coordinates(),
  117. m.trigger_button(),
  118. held_buttons,
  119. m.modifiers(),
  120. );
  121. self.mouse = Some(new_mouse_data.clone());
  122. *m = new_mouse_data;
  123. }
  124. EventData::Wheel(ref w) => self.wheel = Some(w.clone()),
  125. EventData::Screen(ref s) => self.screen = Some(*s),
  126. EventData::Keyboard(ref mut k) => {
  127. let repeat = self
  128. .last_key_pressed
  129. .as_ref()
  130. .filter(|k2| k2.0.key == k.key && k2.1.elapsed() < MAX_REPEAT_TIME)
  131. .is_some();
  132. k.repeat = repeat;
  133. let new = k.clone();
  134. self.last_key_pressed = Some((new, Instant::now()));
  135. }
  136. }
  137. }
  138. fn update(
  139. &mut self,
  140. evts: &mut Vec<EventCore>,
  141. resolved_events: &mut Vec<UserEvent>,
  142. layout: &Taffy,
  143. dom: &mut Dom,
  144. ) {
  145. let previous_mouse = self.mouse.clone();
  146. self.wheel = None;
  147. let old_focus = self.focus_state.last_focused_id;
  148. evts.retain(|e| match &e.1 {
  149. EventData::Keyboard(k) => match k.key_code {
  150. KeyCode::Tab => !self.focus_state.progress(dom, !k.shift_key),
  151. _ => true,
  152. },
  153. _ => true,
  154. });
  155. for e in evts.iter_mut() {
  156. self.apply_event(e);
  157. }
  158. self.resolve_mouse_events(previous_mouse, resolved_events, layout, dom);
  159. if old_focus != self.focus_state.last_focused_id {
  160. if let Some(id) = self.focus_state.last_focused_id {
  161. resolved_events.push(UserEvent {
  162. scope_id: None,
  163. priority: EventPriority::Medium,
  164. name: "focus",
  165. element: Some(id),
  166. data: Arc::new(FocusData {}),
  167. });
  168. resolved_events.push(UserEvent {
  169. scope_id: None,
  170. priority: EventPriority::Medium,
  171. name: "focusin",
  172. element: Some(id),
  173. data: Arc::new(FocusData {}),
  174. });
  175. }
  176. if let Some(id) = old_focus {
  177. resolved_events.push(UserEvent {
  178. scope_id: None,
  179. priority: EventPriority::Medium,
  180. name: "focusout",
  181. element: Some(id),
  182. data: Arc::new(FocusData {}),
  183. });
  184. }
  185. }
  186. // for s in &self.subscribers {
  187. // s();
  188. // }
  189. }
  190. fn resolve_mouse_events(
  191. &mut self,
  192. previous_mouse: Option<MouseData>,
  193. resolved_events: &mut Vec<UserEvent>,
  194. layout: &Taffy,
  195. dom: &mut Dom,
  196. ) {
  197. fn layout_contains_point(layout: &Layout, point: ScreenPoint) -> bool {
  198. let Point { x, y } = layout.location;
  199. let Size { width, height } = layout.size;
  200. let layout_rect = Rect::new(Point2D::new(x, y), Size2D::new(width, height));
  201. layout_rect.contains(point.cast())
  202. }
  203. fn try_create_event(
  204. name: &'static str,
  205. data: Arc<dyn Any + Send + Sync>,
  206. will_bubble: &mut FxHashSet<ElementId>,
  207. resolved_events: &mut Vec<UserEvent>,
  208. node: &Node,
  209. dom: &Dom,
  210. ) {
  211. // only trigger event if the event was not triggered already by a child
  212. if will_bubble.insert(node.id) {
  213. let mut parent = node.parent;
  214. while let Some(parent_id) = parent {
  215. will_bubble.insert(parent_id);
  216. parent = dom[parent_id.0].parent;
  217. }
  218. resolved_events.push(UserEvent {
  219. scope_id: None,
  220. priority: EventPriority::Medium,
  221. name,
  222. element: Some(node.id),
  223. data,
  224. })
  225. }
  226. }
  227. fn prepare_mouse_data(mouse_data: &MouseData, layout: &Layout) -> MouseData {
  228. let Point { x, y } = layout.location;
  229. let node_origin = ClientPoint::new(x.into(), y.into());
  230. let new_client_coordinates = (mouse_data.client_coordinates() - node_origin)
  231. .to_point()
  232. .cast_unit();
  233. let coordinates = Coordinates::new(
  234. mouse_data.screen_coordinates(),
  235. mouse_data.client_coordinates(),
  236. new_client_coordinates,
  237. mouse_data.page_coordinates(),
  238. );
  239. MouseData::new(
  240. coordinates,
  241. mouse_data.trigger_button(),
  242. mouse_data.held_buttons(),
  243. mouse_data.modifiers(),
  244. )
  245. }
  246. if let Some(mouse_data) = &self.mouse {
  247. let new_pos = mouse_data.screen_coordinates();
  248. let old_pos = previous_mouse.as_ref().map(|m| m.screen_coordinates());
  249. // a mouse button is pressed if a button was not down and is now down
  250. let previous_buttons = previous_mouse
  251. .map_or(MouseButtonSet::empty(), |previous_data| {
  252. previous_data.held_buttons()
  253. });
  254. let was_pressed = !(mouse_data.held_buttons() - previous_buttons).is_empty();
  255. // a mouse button is released if a button was down and is now not down
  256. let was_released = !(previous_buttons - mouse_data.held_buttons()).is_empty();
  257. let wheel_delta = self.wheel.as_ref().map_or(0.0, |w| w.delta_y);
  258. let wheel_data = &self.wheel;
  259. {
  260. // mousemove
  261. if old_pos != Some(new_pos) {
  262. let mut will_bubble = FxHashSet::default();
  263. for node in dom.get_listening_sorted("mousemove") {
  264. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  265. let previously_contained = old_pos
  266. .filter(|pos| layout_contains_point(node_layout, *pos))
  267. .is_some();
  268. let currently_contains = layout_contains_point(node_layout, new_pos);
  269. if currently_contains && previously_contained {
  270. try_create_event(
  271. "mousemove",
  272. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  273. &mut will_bubble,
  274. resolved_events,
  275. node,
  276. dom,
  277. );
  278. }
  279. }
  280. }
  281. }
  282. {
  283. // mouseenter
  284. let mut will_bubble = FxHashSet::default();
  285. for node in dom.get_listening_sorted("mouseenter") {
  286. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  287. let previously_contained = old_pos
  288. .filter(|pos| layout_contains_point(node_layout, *pos))
  289. .is_some();
  290. let currently_contains = layout_contains_point(node_layout, new_pos);
  291. if currently_contains && !previously_contained {
  292. try_create_event(
  293. "mouseenter",
  294. Arc::new(mouse_data.clone()),
  295. &mut will_bubble,
  296. resolved_events,
  297. node,
  298. dom,
  299. );
  300. }
  301. }
  302. }
  303. {
  304. // mouseover
  305. let mut will_bubble = FxHashSet::default();
  306. for node in dom.get_listening_sorted("mouseover") {
  307. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  308. let previously_contained = old_pos
  309. .filter(|pos| layout_contains_point(node_layout, *pos))
  310. .is_some();
  311. let currently_contains = layout_contains_point(node_layout, new_pos);
  312. if currently_contains && !previously_contained {
  313. try_create_event(
  314. "mouseover",
  315. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  316. &mut will_bubble,
  317. resolved_events,
  318. node,
  319. dom,
  320. );
  321. }
  322. }
  323. }
  324. // mousedown
  325. if was_pressed {
  326. let mut will_bubble = FxHashSet::default();
  327. for node in dom.get_listening_sorted("mousedown") {
  328. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  329. let currently_contains = layout_contains_point(node_layout, new_pos);
  330. if currently_contains {
  331. try_create_event(
  332. "mousedown",
  333. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  334. &mut will_bubble,
  335. resolved_events,
  336. node,
  337. dom,
  338. );
  339. }
  340. }
  341. }
  342. {
  343. // mouseup
  344. if was_released {
  345. let mut will_bubble = FxHashSet::default();
  346. for node in dom.get_listening_sorted("mouseup") {
  347. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  348. let currently_contains = layout_contains_point(node_layout, new_pos);
  349. if currently_contains {
  350. try_create_event(
  351. "mouseup",
  352. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  353. &mut will_bubble,
  354. resolved_events,
  355. node,
  356. dom,
  357. );
  358. }
  359. }
  360. }
  361. }
  362. {
  363. // click
  364. if mouse_data.trigger_button() == Some(DioxusMouseButton::Primary) && was_released {
  365. let mut will_bubble = FxHashSet::default();
  366. for node in dom.get_listening_sorted("click") {
  367. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  368. let currently_contains = layout_contains_point(node_layout, new_pos);
  369. if currently_contains {
  370. try_create_event(
  371. "click",
  372. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  373. &mut will_bubble,
  374. resolved_events,
  375. node,
  376. dom,
  377. );
  378. }
  379. }
  380. }
  381. }
  382. {
  383. // contextmenu
  384. if mouse_data.trigger_button() == Some(DioxusMouseButton::Secondary) && was_released
  385. {
  386. let mut will_bubble = FxHashSet::default();
  387. for node in dom.get_listening_sorted("contextmenu") {
  388. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  389. let currently_contains = layout_contains_point(node_layout, new_pos);
  390. if currently_contains {
  391. try_create_event(
  392. "contextmenu",
  393. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  394. &mut will_bubble,
  395. resolved_events,
  396. node,
  397. dom,
  398. );
  399. }
  400. }
  401. }
  402. }
  403. {
  404. // wheel
  405. if let Some(w) = wheel_data {
  406. if wheel_delta != 0.0 {
  407. let mut will_bubble = FxHashSet::default();
  408. for node in dom.get_listening_sorted("wheel") {
  409. let node_layout =
  410. layout.layout(node.state.layout.node.unwrap()).unwrap();
  411. let currently_contains = layout_contains_point(node_layout, new_pos);
  412. if currently_contains {
  413. try_create_event(
  414. "wheel",
  415. Arc::new(w.clone()),
  416. &mut will_bubble,
  417. resolved_events,
  418. node,
  419. dom,
  420. );
  421. }
  422. }
  423. }
  424. }
  425. }
  426. {
  427. // mouseleave
  428. let mut will_bubble = FxHashSet::default();
  429. for node in dom.get_listening_sorted("mouseleave") {
  430. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  431. let previously_contained = old_pos
  432. .filter(|pos| layout_contains_point(node_layout, *pos))
  433. .is_some();
  434. let currently_contains = layout_contains_point(node_layout, new_pos);
  435. if !currently_contains && previously_contained {
  436. try_create_event(
  437. "mouseleave",
  438. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  439. &mut will_bubble,
  440. resolved_events,
  441. node,
  442. dom,
  443. );
  444. }
  445. }
  446. }
  447. {
  448. // mouseout
  449. let mut will_bubble = FxHashSet::default();
  450. for node in dom.get_listening_sorted("mouseout") {
  451. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  452. let previously_contained = old_pos
  453. .filter(|pos| layout_contains_point(node_layout, *pos))
  454. .is_some();
  455. let currently_contains = layout_contains_point(node_layout, new_pos);
  456. if !currently_contains && previously_contained {
  457. try_create_event(
  458. "mouseout",
  459. Arc::new(prepare_mouse_data(mouse_data, node_layout)),
  460. &mut will_bubble,
  461. resolved_events,
  462. node,
  463. dom,
  464. );
  465. }
  466. }
  467. }
  468. // update focus
  469. if was_released {
  470. let mut focus_id = None;
  471. dom.traverse_depth_first(|node| {
  472. let node_layout = layout.layout(node.state.layout.node.unwrap()).unwrap();
  473. let currently_contains = layout_contains_point(node_layout, new_pos);
  474. if currently_contains && node.state.focus.level.focusable() {
  475. focus_id = Some(node.id);
  476. }
  477. });
  478. if let Some(id) = focus_id {
  479. self.focus_state.set_focus(dom, id);
  480. }
  481. }
  482. }
  483. }
  484. // fn subscribe(&mut self, f: Rc<dyn Fn() + 'static>) {
  485. // self.subscribers.push(f)
  486. // }
  487. }
  488. pub struct RinkInputHandler {
  489. state: Rc<RefCell<InnerInputState>>,
  490. queued_events: Rc<RefCell<Vec<EventCore>>>,
  491. }
  492. impl RinkInputHandler {
  493. /// global context that handles events
  494. /// limitations: GUI key modifier is never detected, key up events are not detected, and only two mouse buttons may be pressed at once
  495. pub fn new() -> (
  496. Self,
  497. Rc<RefCell<InnerInputState>>,
  498. impl FnMut(crossterm::event::Event),
  499. ) {
  500. let queued_events = Rc::new(RefCell::new(Vec::new()));
  501. let queued_events2 = Rc::downgrade(&queued_events);
  502. let regester_event = move |evt: crossterm::event::Event| {
  503. if let Some(evt) = get_event(evt) {
  504. if let Some(v) = queued_events2.upgrade() {
  505. (*v).borrow_mut().push(evt);
  506. }
  507. }
  508. };
  509. let state = Rc::new(RefCell::new(InnerInputState::new()));
  510. (
  511. Self {
  512. state: state.clone(),
  513. queued_events,
  514. },
  515. state,
  516. regester_event,
  517. )
  518. }
  519. pub(crate) fn prune(&self, mutations: &dioxus_core::Mutations, rdom: &Dom) {
  520. self.state.borrow_mut().focus_state.prune(mutations, rdom);
  521. }
  522. pub(crate) fn get_events(&self, layout: &Taffy, dom: &mut Dom) -> Vec<UserEvent> {
  523. let mut resolved_events = Vec::new();
  524. (*self.state).borrow_mut().update(
  525. &mut (*self.queued_events).borrow_mut(),
  526. &mut resolved_events,
  527. layout,
  528. dom,
  529. );
  530. let events = self
  531. .queued_events
  532. .replace(Vec::new())
  533. .into_iter()
  534. // these events were added in the update stage
  535. .filter(|e| {
  536. ![
  537. "mouseenter",
  538. "mouseover",
  539. "mouseleave",
  540. "mouseout",
  541. "mousedown",
  542. "mouseup",
  543. "mousemove",
  544. "drag",
  545. "wheel",
  546. "click",
  547. "contextmenu",
  548. ]
  549. .contains(&e.0)
  550. })
  551. .map(|evt| (evt.0, evt.1.into_any()));
  552. let mut hm: FxHashMap<&'static str, Vec<Arc<dyn Any + Send + Sync>>> = FxHashMap::default();
  553. for (event, data) in events {
  554. if let Some(v) = hm.get_mut(event) {
  555. v.push(data);
  556. } else {
  557. hm.insert(event, vec![data]);
  558. }
  559. }
  560. for (event, datas) in hm {
  561. for node in dom.get_listening_sorted(event) {
  562. for data in &datas {
  563. if node.state.focused {
  564. resolved_events.push(UserEvent {
  565. scope_id: None,
  566. priority: EventPriority::Medium,
  567. name: event,
  568. element: Some(node.id),
  569. data: data.clone(),
  570. });
  571. }
  572. }
  573. }
  574. }
  575. resolved_events
  576. }
  577. pub(crate) fn state(&self) -> RefMut<InnerInputState> {
  578. self.state.borrow_mut()
  579. }
  580. }
  581. // translate crossterm events into dioxus events
  582. fn get_event(evt: TermEvent) -> Option<(&'static str, EventData)> {
  583. let (name, data): (&str, EventData) = match evt {
  584. TermEvent::Key(k) => ("keydown", translate_key_event(k)?),
  585. TermEvent::Mouse(m) => {
  586. let (x, y) = (m.column.into(), m.row.into());
  587. let alt = m.modifiers.contains(KeyModifiers::ALT);
  588. let shift = m.modifiers.contains(KeyModifiers::SHIFT);
  589. let ctrl = m.modifiers.contains(KeyModifiers::CONTROL);
  590. let meta = false;
  591. let get_mouse_data = |crossterm_button: Option<MouseButton>| {
  592. let button = crossterm_button.map(|b| match b {
  593. MouseButton::Left => DioxusMouseButton::Primary,
  594. MouseButton::Right => DioxusMouseButton::Secondary,
  595. MouseButton::Middle => DioxusMouseButton::Auxiliary,
  596. });
  597. // from https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent
  598. // The `page` and `screen` coordinates are inconsistent with the MDN definition, as they are relative to the viewport (client), not the target element/page/screen, respectively.
  599. // todo?
  600. // But then, MDN defines them in terms of pixels, yet crossterm provides only row/column, and it might not be possible to get pixels. So we can't get 100% consistency anyway.
  601. let coordinates = Coordinates::new(
  602. ScreenPoint::new(x, y),
  603. ClientPoint::new(x, y),
  604. // offset x/y are set when the origin of the event is assigned to an element
  605. ElementPoint::new(0., 0.),
  606. PagePoint::new(x, y),
  607. );
  608. let mut modifiers = Modifiers::empty();
  609. if shift {
  610. modifiers.insert(Modifiers::SHIFT);
  611. }
  612. if ctrl {
  613. modifiers.insert(Modifiers::CONTROL);
  614. }
  615. if meta {
  616. modifiers.insert(Modifiers::META);
  617. }
  618. if alt {
  619. modifiers.insert(Modifiers::ALT);
  620. }
  621. // held mouse buttons get set later by maintaining state, as crossterm does not provide them
  622. EventData::Mouse(MouseData::new(
  623. coordinates,
  624. button,
  625. DioxusMouseButtons::empty(),
  626. modifiers,
  627. ))
  628. };
  629. let get_wheel_data = |up| {
  630. // from https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent
  631. EventData::Wheel(WheelData {
  632. delta_mode: 0x01,
  633. delta_x: 0.0,
  634. delta_y: if up { -1.0 } else { 1.0 },
  635. delta_z: 0.0,
  636. })
  637. };
  638. match m.kind {
  639. MouseEventKind::Down(b) => ("mousedown", get_mouse_data(Some(b))),
  640. MouseEventKind::Up(b) => ("mouseup", get_mouse_data(Some(b))),
  641. MouseEventKind::Drag(b) => ("drag", get_mouse_data(Some(b))),
  642. MouseEventKind::Moved => ("mousemove", get_mouse_data(None)),
  643. MouseEventKind::ScrollDown => ("wheel", get_wheel_data(false)),
  644. MouseEventKind::ScrollUp => ("wheel", get_wheel_data(true)),
  645. }
  646. }
  647. TermEvent::Resize(x, y) => ("resize", EventData::Screen((x, y))),
  648. };
  649. Some((name, data))
  650. }
  651. fn translate_key_event(event: crossterm::event::KeyEvent) -> Option<EventData> {
  652. let (code, key_str);
  653. let mut shift_key = event.modifiers.contains(KeyModifiers::SHIFT);
  654. if let TermKeyCode::Char(c) = event.code {
  655. code = match c {
  656. 'A'..='Z' | 'a'..='z' => match c.to_ascii_uppercase() {
  657. 'A' => KeyCode::A,
  658. 'B' => KeyCode::B,
  659. 'C' => KeyCode::C,
  660. 'D' => KeyCode::D,
  661. 'E' => KeyCode::E,
  662. 'F' => KeyCode::F,
  663. 'G' => KeyCode::G,
  664. 'H' => KeyCode::H,
  665. 'I' => KeyCode::I,
  666. 'J' => KeyCode::J,
  667. 'K' => KeyCode::K,
  668. 'L' => KeyCode::L,
  669. 'M' => KeyCode::M,
  670. 'N' => KeyCode::N,
  671. 'O' => KeyCode::O,
  672. 'P' => KeyCode::P,
  673. 'Q' => KeyCode::Q,
  674. 'R' => KeyCode::R,
  675. 'S' => KeyCode::S,
  676. 'T' => KeyCode::T,
  677. 'U' => KeyCode::U,
  678. 'V' => KeyCode::V,
  679. 'W' => KeyCode::W,
  680. 'X' => KeyCode::X,
  681. 'Y' => KeyCode::Y,
  682. 'Z' => KeyCode::Z,
  683. _ => return None,
  684. },
  685. ' ' => KeyCode::Space,
  686. '[' => KeyCode::OpenBracket,
  687. '{' => KeyCode::OpenBracket,
  688. ']' => KeyCode::CloseBraket,
  689. '}' => KeyCode::CloseBraket,
  690. ';' => KeyCode::Semicolon,
  691. ':' => KeyCode::Semicolon,
  692. ',' => KeyCode::Comma,
  693. '<' => KeyCode::Comma,
  694. '.' => KeyCode::Period,
  695. '>' => KeyCode::Period,
  696. '1' => KeyCode::Num1,
  697. '2' => KeyCode::Num2,
  698. '3' => KeyCode::Num3,
  699. '4' => KeyCode::Num4,
  700. '5' => KeyCode::Num5,
  701. '6' => KeyCode::Num6,
  702. '7' => KeyCode::Num7,
  703. '8' => KeyCode::Num8,
  704. '9' => KeyCode::Num9,
  705. '0' => KeyCode::Num0,
  706. '!' => KeyCode::Num1,
  707. '@' => KeyCode::Num2,
  708. '#' => KeyCode::Num3,
  709. '$' => KeyCode::Num4,
  710. '%' => KeyCode::Num5,
  711. '^' => KeyCode::Num6,
  712. '&' => KeyCode::Num7,
  713. '*' => KeyCode::Num8,
  714. '(' => KeyCode::Num9,
  715. ')' => KeyCode::Num0,
  716. // numpad charicter are ambiguous to tui
  717. // '*' => KeyCode::Multiply,
  718. // '/' => KeyCode::Divide,
  719. // '-' => KeyCode::Subtract,
  720. // '+' => KeyCode::Add,
  721. '+' => KeyCode::EqualSign,
  722. '-' => KeyCode::Dash,
  723. '_' => KeyCode::Dash,
  724. '\'' => KeyCode::SingleQuote,
  725. '"' => KeyCode::SingleQuote,
  726. '\\' => KeyCode::BackSlash,
  727. '|' => KeyCode::BackSlash,
  728. '/' => KeyCode::ForwardSlash,
  729. '?' => KeyCode::ForwardSlash,
  730. '=' => KeyCode::EqualSign,
  731. '`' => KeyCode::GraveAccent,
  732. '~' => KeyCode::GraveAccent,
  733. _ => return None,
  734. };
  735. key_str = c.to_string();
  736. } else {
  737. code = match event.code {
  738. TermKeyCode::Esc => KeyCode::Escape,
  739. TermKeyCode::Backspace => KeyCode::Backspace,
  740. TermKeyCode::Enter => KeyCode::Enter,
  741. TermKeyCode::Left => KeyCode::LeftArrow,
  742. TermKeyCode::Right => KeyCode::RightArrow,
  743. TermKeyCode::Up => KeyCode::UpArrow,
  744. TermKeyCode::Down => KeyCode::DownArrow,
  745. TermKeyCode::Home => KeyCode::Home,
  746. TermKeyCode::End => KeyCode::End,
  747. TermKeyCode::PageUp => KeyCode::PageUp,
  748. TermKeyCode::PageDown => KeyCode::PageDown,
  749. TermKeyCode::Tab => KeyCode::Tab,
  750. TermKeyCode::Delete => KeyCode::Delete,
  751. TermKeyCode::Insert => KeyCode::Insert,
  752. TermKeyCode::F(fn_num) => match fn_num {
  753. 1 => KeyCode::F1,
  754. 2 => KeyCode::F2,
  755. 3 => KeyCode::F3,
  756. 4 => KeyCode::F4,
  757. 5 => KeyCode::F5,
  758. 6 => KeyCode::F6,
  759. 7 => KeyCode::F7,
  760. 8 => KeyCode::F8,
  761. 9 => KeyCode::F9,
  762. 10 => KeyCode::F10,
  763. 11 => KeyCode::F11,
  764. 12 => KeyCode::F12,
  765. _ => return None,
  766. },
  767. // backtab is Shift + Tab
  768. TermKeyCode::BackTab => {
  769. shift_key = true;
  770. KeyCode::Tab
  771. }
  772. TermKeyCode::Null => return None,
  773. _ => return None,
  774. };
  775. key_str = if let KeyCode::BackSlash = code {
  776. "\\".to_string()
  777. } else {
  778. format!("{code:?}")
  779. }
  780. };
  781. // from https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent
  782. Some(EventData::Keyboard(KeyboardData {
  783. char_code: code.raw_code(),
  784. key: key_str,
  785. key_code: code,
  786. alt_key: event.modifiers.contains(KeyModifiers::ALT),
  787. ctrl_key: event.modifiers.contains(KeyModifiers::CONTROL),
  788. meta_key: false,
  789. shift_key,
  790. locale: Default::default(),
  791. location: 0x00,
  792. repeat: Default::default(),
  793. which: Default::default(),
  794. }))
  795. }