input.rs
1 use crate::{canvas_element, canvas_origin, AppRunner}; 2 3 pub fn pos_from_mouse_event(canvas_id: &str, event: &web_sys::MouseEvent) -> egui::Pos2 { 4 let canvas = canvas_element(canvas_id).unwrap(); 5 let rect = canvas.get_bounding_client_rect(); 6 egui::Pos2 { 7 x: event.client_x() as f32 - rect.left() as f32, 8 y: event.client_y() as f32 - rect.top() as f32, 9 } 10 } 11 12 pub fn button_from_mouse_event(event: &web_sys::MouseEvent) -> Option<egui::PointerButton> { 13 match event.button() { 14 0 => Some(egui::PointerButton::Primary), 15 1 => Some(egui::PointerButton::Middle), 16 2 => Some(egui::PointerButton::Secondary), 17 _ => None, 18 } 19 } 20 21 /// A single touch is translated to a pointer movement. When a second touch is added, the pointer 22 /// should not jump to a different position. Therefore, we do not calculate the average position 23 /// of all touches, but we keep using the same touch as long as it is available. 24 /// 25 /// `touch_id_for_pos` is the [`TouchId`](egui::TouchId) of the [`Touch`](web_sys::Touch) we previously used to determine the 26 /// pointer position. 27 pub fn pos_from_touch_event( 28 canvas_id: &str, 29 event: &web_sys::TouchEvent, 30 touch_id_for_pos: &mut Option<egui::TouchId>, 31 ) -> egui::Pos2 { 32 let touch_for_pos; 33 if let Some(touch_id_for_pos) = touch_id_for_pos { 34 // search for the touch we previously used for the position 35 // (unfortunately, `event.touches()` is not a rust collection): 36 touch_for_pos = (0..event.touches().length()) 37 .into_iter() 38 .map(|i| event.touches().get(i).unwrap()) 39 .find(|touch| egui::TouchId::from(touch.identifier()) == *touch_id_for_pos); 40 } else { 41 touch_for_pos = None; 42 } 43 // Use the touch found above or pick the first, or return a default position if there is no 44 // touch at all. (The latter is not expected as the current method is only called when there is 45 // at least one touch.) 46 touch_for_pos 47 .or_else(|| event.touches().get(0)) 48 .map_or(Default::default(), |touch| { 49 *touch_id_for_pos = Some(egui::TouchId::from(touch.identifier())); 50 pos_from_touch(canvas_origin(canvas_id), &touch) 51 }) 52 } 53 54 fn pos_from_touch(canvas_origin: egui::Pos2, touch: &web_sys::Touch) -> egui::Pos2 { 55 egui::Pos2 { 56 x: touch.page_x() as f32 - canvas_origin.x as f32, 57 y: touch.page_y() as f32 - canvas_origin.y as f32, 58 } 59 } 60 61 pub fn push_touches(runner: &mut AppRunner, phase: egui::TouchPhase, event: &web_sys::TouchEvent) { 62 let canvas_origin = canvas_origin(runner.canvas_id()); 63 for touch_idx in 0..event.changed_touches().length() { 64 if let Some(touch) = event.changed_touches().item(touch_idx) { 65 runner.input.raw.events.push(egui::Event::Touch { 66 device_id: egui::TouchDeviceId(0), 67 id: egui::TouchId::from(touch.identifier()), 68 phase, 69 pos: pos_from_touch(canvas_origin, &touch), 70 force: touch.force(), 71 }); 72 } 73 } 74 } 75 76 /// Web sends all keys as strings, so it is up to us to figure out if it is 77 /// a real text input or the name of a key. 78 pub fn should_ignore_key(key: &str) -> bool { 79 let is_function_key = key.starts_with('F') && key.len() > 1; 80 is_function_key 81 || matches!( 82 key, 83 "Alt" 84 | "ArrowDown" 85 | "ArrowLeft" 86 | "ArrowRight" 87 | "ArrowUp" 88 | "Backspace" 89 | "CapsLock" 90 | "ContextMenu" 91 | "Control" 92 | "Delete" 93 | "End" 94 | "Enter" 95 | "Esc" 96 | "Escape" 97 | "Help" 98 | "Home" 99 | "Insert" 100 | "Meta" 101 | "NumLock" 102 | "PageDown" 103 | "PageUp" 104 | "Pause" 105 | "ScrollLock" 106 | "Shift" 107 | "Tab" 108 ) 109 } 110 111 /// Web sends all all keys as strings, so it is up to us to figure out if it is 112 /// a real text input or the name of a key. 113 pub fn translate_key(key: &str) -> Option<egui::Key> { 114 match key { 115 "ArrowDown" => Some(egui::Key::ArrowDown), 116 "ArrowLeft" => Some(egui::Key::ArrowLeft), 117 "ArrowRight" => Some(egui::Key::ArrowRight), 118 "ArrowUp" => Some(egui::Key::ArrowUp), 119 120 "Esc" | "Escape" => Some(egui::Key::Escape), 121 "Tab" => Some(egui::Key::Tab), 122 "Backspace" => Some(egui::Key::Backspace), 123 "Enter" => Some(egui::Key::Enter), 124 "Space" | " " => Some(egui::Key::Space), 125 126 "Help" | "Insert" => Some(egui::Key::Insert), 127 "Delete" => Some(egui::Key::Delete), 128 "Home" => Some(egui::Key::Home), 129 "End" => Some(egui::Key::End), 130 "PageUp" => Some(egui::Key::PageUp), 131 "PageDown" => Some(egui::Key::PageDown), 132 133 "0" => Some(egui::Key::Num0), 134 "1" => Some(egui::Key::Num1), 135 "2" => Some(egui::Key::Num2), 136 "3" => Some(egui::Key::Num3), 137 "4" => Some(egui::Key::Num4), 138 "5" => Some(egui::Key::Num5), 139 "6" => Some(egui::Key::Num6), 140 "7" => Some(egui::Key::Num7), 141 "8" => Some(egui::Key::Num8), 142 "9" => Some(egui::Key::Num9), 143 144 "a" | "A" => Some(egui::Key::A), 145 "b" | "B" => Some(egui::Key::B), 146 "c" | "C" => Some(egui::Key::C), 147 "d" | "D" => Some(egui::Key::D), 148 "e" | "E" => Some(egui::Key::E), 149 "f" | "F" => Some(egui::Key::F), 150 "g" | "G" => Some(egui::Key::G), 151 "h" | "H" => Some(egui::Key::H), 152 "i" | "I" => Some(egui::Key::I), 153 "j" | "J" => Some(egui::Key::J), 154 "k" | "K" => Some(egui::Key::K), 155 "l" | "L" => Some(egui::Key::L), 156 "m" | "M" => Some(egui::Key::M), 157 "n" | "N" => Some(egui::Key::N), 158 "o" | "O" => Some(egui::Key::O), 159 "p" | "P" => Some(egui::Key::P), 160 "q" | "Q" => Some(egui::Key::Q), 161 "r" | "R" => Some(egui::Key::R), 162 "s" | "S" => Some(egui::Key::S), 163 "t" | "T" => Some(egui::Key::T), 164 "u" | "U" => Some(egui::Key::U), 165 "v" | "V" => Some(egui::Key::V), 166 "w" | "W" => Some(egui::Key::W), 167 "x" | "X" => Some(egui::Key::X), 168 "y" | "Y" => Some(egui::Key::Y), 169 "z" | "Z" => Some(egui::Key::Z), 170 171 _ => None, 172 } 173 } 174 175 pub fn modifiers_from_event(event: &web_sys::KeyboardEvent) -> egui::Modifiers { 176 egui::Modifiers { 177 alt: event.alt_key(), 178 ctrl: event.ctrl_key(), 179 shift: event.shift_key(), 180 181 // Ideally we should know if we are running or mac or not, 182 // but this works good enough for now. 183 mac_cmd: event.meta_key(), 184 185 // Ideally we should know if we are running or mac or not, 186 // but this works good enough for now. 187 command: event.ctrl_key() || event.meta_key(), 188 } 189 }