From fe0d159324dcab3eed4865945816b842e9827529 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sun, 15 Nov 2020 14:21:21 +0100 Subject: [PATCH] Support Cmd+A ^W ^U ^K and shift-click --- CHANGELOG.md | 2 +- TODO.md | 15 +++--- egui/src/input.rs | 20 +++++++- egui/src/paint/galley.rs | 13 +++++- egui/src/widgets/text_edit.rs | 60 ++++++++++++++++++------ egui_glium/src/lib.rs | 36 ++++++++------ egui_web/src/backend.rs | 17 +++---- egui_web/src/lib.rs | 88 +++++++++++++++++++++++------------ 8 files changed, 174 insertions(+), 77 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 091b7c09..877d10d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). * You must now be explicit when creating a `TextEdit` if you want it to be singeline or multiline. * Improved automatic `Id` generation, making `Id` clashes less likely. * Egui now requires modifier key state from the integration -* Renamed and removed some keys in the `Key` enum. +* Added, renamed and removed some keys in the `Key` enum. ### Fixed 🐛 diff --git a/TODO.md b/TODO.md index b5226ce6..78cb53b8 100644 --- a/TODO.md +++ b/TODO.md @@ -4,7 +4,6 @@ TODO-list for the Egui project. If you looking for something to do, look here. ## Top priority -* Text input: text selection etc * Refactor graphics layers and areas so one don't have to register LayerId:s. ## Other @@ -18,8 +17,9 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [x] Input * [x] Text focus * [x] Cursor movement - * [ ] Text selection - * [ ] Clipboard copy/paste + * [x] Text selection + * [x] Clipboard copy/paste + * [ ] Text edit undo * [ ] Move focus with tab * [ ] Vertical slider * [/] Color picker @@ -43,15 +43,16 @@ TODO-list for the Egui project. If you looking for something to do, look here. * [x] Distinguish between clicks and drags * [x] Double-click * [x] Text + * [x] Get modifier keys * [ ] Support all mouse buttons * [ ] Distinguish between touch input and mouse input - * [ ] Get modifier keys - * [ ] Keyboard shortcuts - * [ ] Copy, paste, undo, ... + * [ ] Keyboard shortcuts (copy, paste, undo, select-all, ...?) * Text * [/] Unicode * [x] Shared mutable expanding texture map - * [ ] Text editing of unicode + * [/] Text editing of unicode (needs more testing) + * [ ] Font with some more unicode characters + * [ ] Emoji support (great for things like ▶️⏸⏹⚠︎) * [ ] Change text style/color and continue in same layout * Menu bar (File, Edit, etc) * [ ] Sub-menus diff --git a/egui/src/input.rs b/egui/src/input.rs index 740ea911..10d95c4d 100644 --- a/egui/src/input.rs +++ b/egui/src/input.rs @@ -33,6 +33,9 @@ pub struct RawInput { /// Time in seconds. Relative to whatever. Used for animations. pub time: f64, + /// Which modifier keys are down at the start of the frame? + pub modifiers: Modifiers, + /// In-order events received this frame pub events: Vec, } @@ -47,6 +50,7 @@ impl RawInput { screen_size: self.screen_size, pixels_per_point: self.pixels_per_point, time: self.time, + modifiers: self.modifiers, events: std::mem::take(&mut self.events), } } @@ -80,6 +84,9 @@ pub struct InputState { /// Should be set to the expected time between frames when painting at vsync speeds. pub predicted_dt: f32, + /// Which modifier keys are down at the start of the frame? + pub modifiers: Modifiers, + /// In-order events received this frame pub events: Vec, } @@ -200,6 +207,12 @@ pub enum Key { PageDown, PageUp, Tab, + + A, // Used for cmd+A (select All) + K, // Used for ctrl+K (delete text after cursor) + U, // Used for ctrl+U (delete text before cursor) + W, // Used for ctrl+W (delete previous word) + Z, // Used for cmd+Z (undo) } impl InputState { @@ -214,7 +227,8 @@ impl InputState { pixels_per_point: new.pixels_per_point.or(self.pixels_per_point), time: new.time, unstable_dt, - predicted_dt: 1.0 / 60.0, // TODO: remove this hack + predicted_dt: 1.0 / 60.0, // TODO: remove this hack + modifiers: new.modifiers, events: new.events.clone(), // TODO: remove clone() and use raw.events raw: new, } @@ -357,6 +371,7 @@ impl RawInput { screen_size, pixels_per_point, time, + modifiers, events, } = self; @@ -371,6 +386,7 @@ impl RawInput { "Also called HDPI factor.\nNumber of physical pixels per each logical pixel.", ); ui.label(format!("time: {:.3} s", time)); + ui.label(format!("modifiers: {:#?}", modifiers)); ui.label(format!("events: {:?}", events)) .on_hover_text("key presses etc"); } @@ -387,6 +403,7 @@ impl InputState { time, unstable_dt, predicted_dt, + modifiers, events, } = self; @@ -411,6 +428,7 @@ impl InputState { 1e3 * unstable_dt )); ui.label(format!("expected dt: {:.1} ms", 1e3 * predicted_dt)); + ui.label(format!("modifiers: {:#?}", modifiers)); ui.label(format!("events: {:?}", events)) .on_hover_text("key presses etc"); } diff --git a/egui/src/paint/galley.rs b/egui/src/paint/galley.rs index 1a6ff72c..02202ef9 100644 --- a/egui/src/paint/galley.rs +++ b/egui/src/paint/galley.rs @@ -192,6 +192,10 @@ impl Row { *self.x_offsets.last().unwrap() } + pub fn height(&self) -> f32 { + self.y_max - self.y_min + } + /// Closest char at the desired x coordinate. /// Returns something in the range `[0, char_count_excluding_newline()]`. pub fn char_at(&self, desired_x: f32) -> usize { @@ -233,7 +237,7 @@ impl Galley { fn end_pos(&self) -> Rect { if let Some(row) = self.rows.last() { let x = row.max_x(); - return Rect::from_min_max(pos2(x, row.y_min), pos2(x, row.y_max)); + Rect::from_min_max(pos2(x, row.y_min), pos2(x, row.y_max)) } else { // Empty galley Rect::from_min_max(pos2(0.0, 0.0), pos2(0.0, 0.0)) @@ -636,6 +640,13 @@ impl Galley { #[test] fn test_text_layout() { + impl PartialEq for Cursor { + fn eq(&self, other: &Cursor) -> bool { + (self.ccursor, self.rcursor, self.pcursor) + == (other.ccursor, other.rcursor, other.pcursor) + } + } + use crate::mutex::Mutex; use crate::paint::{font::Font, *}; diff --git a/egui/src/widgets/text_edit.rs b/egui/src/widgets/text_edit.rs index 3f0723aa..04821e40 100644 --- a/egui/src/widgets/text_edit.rs +++ b/egui/src/widgets/text_edit.rs @@ -267,7 +267,15 @@ impl<'t> Widget for TextEdit<'t> { }); } else if response.hovered && ui.input().mouse.pressed { ui.memory().request_kb_focus(id); - state.cursorp = Some(CursorPair::one(cursor_at_mouse)); + if ui.input().modifiers.shift { + if let Some(cursorp) = &mut state.cursorp { + cursorp.primary = cursor_at_mouse; + } else { + state.cursorp = Some(CursorPair::one(cursor_at_mouse)); + } + } else { + state.cursorp = Some(CursorPair::one(cursor_at_mouse)); + } } else if ui.input().mouse.down && response.active { if let Some(cursorp) = &mut state.cursorp { cursorp.primary = cursor_at_mouse; @@ -332,7 +340,7 @@ impl<'t> Widget for TextEdit<'t> { && text_to_insert != "\n" && text_to_insert != "\r" { - let mut ccursor = delete_selected(text, &cursorp).into(); + let mut ccursor = delete_selected(text, &cursorp); insert_text(&mut ccursor, text, text_to_insert); Some(CCursorPair::one(ccursor)) } else { @@ -345,7 +353,7 @@ impl<'t> Widget for TextEdit<'t> { .. } => { if multiline { - let mut ccursor = delete_selected(text, &cursorp).into(); + let mut ccursor = delete_selected(text, &cursorp); insert_text(&mut ccursor, text, "\n"); Some(CCursorPair::one(ccursor)) } else { @@ -452,7 +460,12 @@ fn paint_cursor_selection( let right = if ri == max.row { row.x_offset(max.column) } else { - row.max_x() + let newline_size = if row.ends_with_newline { + row.height() / 2.0 // visualize that we select the newline + } else { + 0.0 + }; + row.max_x() + newline_size }; let rect = Rect::from_min_max(pos + vec2(left, row.y_min), pos + vec2(right, row.y_max)); ui.painter().rect_filled(rect, 0.0, color); @@ -499,7 +512,7 @@ fn byte_index_from_char_index(s: &str, char_index: usize) -> usize { return bi; } } - return s.len(); + s.len() } fn insert_text(ccursor: &mut CCursor, text: &mut String, text_to_insert: &str) { @@ -555,12 +568,12 @@ fn delete_next_char(text: &mut String, ccursor: CCursor) -> CCursor { } fn delete_previous_word(text: &mut String, max_ccursor: CCursor) -> CCursor { - let min_ccursor = ccursor_previous_word(&text, max_ccursor); + let min_ccursor = ccursor_previous_word(text, max_ccursor); delete_selected_ccursor_range(text, [min_ccursor, max_ccursor]) } fn delete_next_word(text: &mut String, min_ccursor: CCursor) -> CCursor { - let max_ccursor = ccursor_next_word(&text, min_ccursor); + let max_ccursor = ccursor_next_word(text, min_ccursor); delete_selected_ccursor_range(text, [min_ccursor, max_ccursor]) } @@ -610,10 +623,6 @@ fn on_key_press( key: Key, modifiers: &Modifiers, ) -> Option { - // TODO: ctrl-U to clear paragraph before the cursor - // TODO: ctrl-W to delete previous word - // TODO: cmd-A to select all - match key { Key::Backspace => { let ccursor = if modifiers.mac_cmd { @@ -650,6 +659,31 @@ fn on_key_press( Some(CCursorPair::one(ccursor)) } + Key::A if modifiers.command => { + // select all + *cursorp = CursorPair::two(Cursor::default(), galley.end()); + None + } + + Key::K if modifiers.ctrl => { + let ccursor = delete_paragraph_after_cursor(text, galley, cursorp); + Some(CCursorPair::one(ccursor)) + } + + Key::U if modifiers.ctrl => { + let ccursor = delete_paragraph_before_cursor(text, galley, cursorp); + Some(CCursorPair::one(ccursor)) + } + + Key::W if modifiers.ctrl => { + let ccursor = if let Some(cursor) = cursorp.single() { + delete_previous_word(text, cursor.ccursor) + } else { + delete_selected(text, cursorp) + }; + Some(CCursorPair::one(ccursor)) + } + Key::ArrowLeft | Key::ArrowRight | Key::ArrowUp | Key::ArrowDown | Key::Home | Key::End => { move_single_cursor(&mut cursorp.primary, galley, key, modifiers); if !modifiers.shift { @@ -658,9 +692,7 @@ fn on_key_press( None } - Key::Enter | Key::Escape => unreachable!("Handled outside this function"), - - Key::Insert | Key::PageDown | Key::PageUp | Key::Tab => None, + _ => None, } } diff --git a/egui_glium/src/lib.rs b/egui_glium/src/lib.rs index a4bab2b0..0936aef0 100644 --- a/egui_glium/src/lib.rs +++ b/egui_glium/src/lib.rs @@ -20,7 +20,6 @@ pub use clipboard::ClipboardContext; // TODO: remove pub struct GliumInputState { raw: egui::RawInput, - modifiers: egui::Modifiers, } impl GliumInputState { @@ -30,7 +29,6 @@ impl GliumInputState { pixels_per_point: Some(pixels_per_point), ..Default::default() }, - modifiers: Default::default(), // cmd: false, } } } @@ -60,7 +58,10 @@ pub fn input_to_egui( input_state.raw.mouse_pos = None; } ReceivedCharacter(ch) => { - if printable_char(ch) && !input_state.modifiers.ctrl && !input_state.modifiers.mac_cmd { + if printable_char(ch) + && !input_state.raw.modifiers.ctrl + && !input_state.raw.modifiers.mac_cmd + { input_state.raw.events.push(Event::Text(ch.to_string())); } } @@ -69,27 +70,27 @@ pub fn input_to_egui( let pressed = input.state == glutin::event::ElementState::Pressed; if matches!(keycode, VirtualKeyCode::LAlt | VirtualKeyCode::RAlt) { - input_state.modifiers.alt = pressed; + input_state.raw.modifiers.alt = pressed; } if matches!(keycode, VirtualKeyCode::LControl | VirtualKeyCode::RControl) { - input_state.modifiers.ctrl = pressed; + input_state.raw.modifiers.ctrl = pressed; if !cfg!(target_os = "macos") { - input_state.modifiers.command = pressed; + input_state.raw.modifiers.command = pressed; } } if matches!(keycode, VirtualKeyCode::LShift | VirtualKeyCode::RShift) { - input_state.modifiers.shift = pressed; + input_state.raw.modifiers.shift = pressed; } if cfg!(target_os = "macos") && matches!(keycode, VirtualKeyCode::LWin | VirtualKeyCode::RWin) { - input_state.modifiers.mac_cmd = pressed; - input_state.modifiers.command = pressed; + input_state.raw.modifiers.mac_cmd = pressed; + input_state.raw.modifiers.command = pressed; } if pressed { if cfg!(target_os = "macos") - && input_state.modifiers.mac_cmd + && input_state.raw.modifiers.mac_cmd && keycode == VirtualKeyCode::Q { *control_flow = ControlFlow::Exit; @@ -97,11 +98,11 @@ pub fn input_to_egui( // VirtualKeyCode::Paste etc in winit are broken/untrustworthy, // so we detect these things manually: - if input_state.modifiers.command && keycode == VirtualKeyCode::X { + if input_state.raw.modifiers.command && keycode == VirtualKeyCode::X { input_state.raw.events.push(Event::Cut); - } else if input_state.modifiers.command && keycode == VirtualKeyCode::C { + } else if input_state.raw.modifiers.command && keycode == VirtualKeyCode::C { input_state.raw.events.push(Event::Copy); - } else if input_state.modifiers.command && keycode == VirtualKeyCode::V { + } else if input_state.raw.modifiers.command && keycode == VirtualKeyCode::V { if let Some(clipboard) = clipboard { match clipboard.get_contents() { Ok(contents) => { @@ -116,7 +117,7 @@ pub fn input_to_egui( input_state.raw.events.push(Event::Key { key, pressed, - modifiers: input_state.modifiers, + modifiers: input_state.raw.modifiers, }); } } @@ -170,6 +171,13 @@ pub fn translate_virtual_key_code(key: VirtualKeyCode) -> Option { Back => Key::Backspace, Return => Key::Enter, Tab => Key::Tab, + + A => Key::A, + K => Key::K, + U => Key::U, + W => Key::W, + Z => Key::Z, + _ => { return None; } diff --git a/egui_web/src/backend.rs b/egui_web/src/backend.rs index 8c8b1bb1..bc76346d 100644 --- a/egui_web/src/backend.rs +++ b/egui_web/src/backend.rs @@ -92,16 +92,18 @@ impl egui::app::TextureAllocator for webgl::Painter { // ---------------------------------------------------------------------------- -// TODO: Just use RawInput? /// Data gathered between frames. /// Is translated to `egui::RawInput` at the start of each frame. #[derive(Default)] pub struct WebInput { + /// In native points (not same as Egui points) pub mouse_pos: Option, - pub mouse_down: bool, // TODO: which button + /// Is this a touch screen? If so, we ignore mouse events. pub is_touch: bool, + /// In native points (not same as Egui points) pub scroll_delta: egui::Vec2, - pub events: Vec, + + pub raw: egui::RawInput, } impl WebInput { @@ -111,13 +113,12 @@ impl WebInput { let scroll_delta = std::mem::take(&mut self.scroll_delta) * scale; let mouse_pos = self.mouse_pos.map(|mp| pos2(mp.x * scale, mp.y * scale)); egui::RawInput { - mouse_down: self.mouse_down, mouse_pos, scroll_delta, screen_size: screen_size_in_native_points().unwrap() * scale, pixels_per_point: Some(pixels_per_point), time: now_sec(), - events: std::mem::take(&mut self.events), + ..self.raw.take() } } } @@ -127,7 +128,7 @@ impl WebInput { pub struct AppRunner { pixels_per_point: f32, pub web_backend: WebBackend, - pub web_input: WebInput, + pub input: WebInput, pub app: Box, pub needs_repaint: bool, // TODO: move } @@ -138,7 +139,7 @@ impl AppRunner { Ok(Self { pixels_per_point: native_pixels_per_point(), web_backend, - web_input: Default::default(), + input: Default::default(), app, needs_repaint: true, // TODO: move }) @@ -151,7 +152,7 @@ impl AppRunner { pub fn logic(&mut self) -> Result<(egui::Output, egui::PaintJobs), JsValue> { resize_canvas_to_screen_size(self.web_backend.canvas_id()); - let raw_input = self.web_input.new_frame(self.pixels_per_point); + let raw_input = self.input.new_frame(self.pixels_per_point); self.web_backend.begin_frame(raw_input); let mut integration_context = egui::app::IntegrationContext { diff --git a/egui_web/src/lib.rs b/egui_web/src/lib.rs index f4ac01fa..66df5aa7 100644 --- a/egui_web/src/lib.rs +++ b/egui_web/src/lib.rs @@ -195,14 +195,30 @@ fn should_ignore_key(key: &str) -> bool { || matches!( key, "Alt" + | "ArrowDown" + | "ArrowLeft" + | "ArrowRight" + | "ArrowUp" + | "Backspace" | "CapsLock" | "ContextMenu" | "Control" + | "Delete" + | "End" + | "Enter" + | "Esc" + | "Escape" + | "Help" + | "Home" + | "Insert" | "Meta" | "NumLock" + | "PageDown" + | "PageUp" | "Pause" | "ScrollLock" | "Shift" + | "Tab" ) } @@ -224,6 +240,11 @@ pub fn translate_key(key: &str) -> Option { "PageDown" => Some(egui::Key::PageDown), "PageUp" => Some(egui::Key::PageUp), "Tab" => Some(egui::Key::Tab), + "a" | "A" => Some(egui::Key::A), + "k" | "K" => Some(egui::Key::K), + "u" | "U" => Some(egui::Key::U), + "w" | "W" => Some(egui::Key::W), + "z" | "Z" => Some(egui::Key::Z), _ => None, } } @@ -271,20 +292,24 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { // https://www.fxsitecompat.dev/en-CA/docs/2018/keydown-and-keyup-events-are-now-fired-during-ime-composition/ return; } + let mut runner_lock = runner_ref.0.lock(); + let modifiers = modifiers_from_event(&event); + runner_lock.input.raw.modifiers = modifiers; + let key = event.key(); if let Some(key) = translate_key(&key) { - runner_lock.web_input.events.push(egui::Event::Key { + runner_lock.input.raw.events.push(egui::Event::Key { key, pressed: true, - modifiers: modifiers_from_event(&event), + modifiers, }); - runner_lock.needs_repaint = true; - } else if !should_ignore_key(&key) { - runner_lock.web_input.events.push(egui::Event::Text(key)); - runner_lock.needs_repaint = true; } + if !modifiers.ctrl && !modifiers.command && !should_ignore_key(&key) { + runner_lock.input.raw.events.push(egui::Event::Text(key)); + } + runner_lock.needs_repaint = true; }) as Box); document.add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref())?; closure.forget(); @@ -295,15 +320,16 @@ fn install_document_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::KeyboardEvent| { let mut runner_lock = runner_ref.0.lock(); - let key = event.key(); - if let Some(key) = translate_key(&key) { - runner_lock.web_input.events.push(egui::Event::Key { + let modifiers = modifiers_from_event(&event); + runner_lock.input.raw.modifiers = modifiers; + if let Some(key) = translate_key(&event.key()) { + runner_lock.input.raw.events.push(egui::Event::Key { key, pressed: false, - modifiers: modifiers_from_event(&event), + modifiers, }); - runner_lock.needs_repaint = true; } + runner_lock.needs_repaint = true; }) as Box); document.add_event_listener_with_callback("keyup", closure.as_ref().unchecked_ref())?; closure.forget(); @@ -346,10 +372,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { let mut runner_lock = runner_ref.0.lock(); - if !runner_lock.web_input.is_touch { - runner_lock.web_input.mouse_pos = + if !runner_lock.input.is_touch { + runner_lock.input.mouse_pos = Some(pos_from_mouse_event(runner_lock.canvas_id(), &event)); - runner_lock.web_input.mouse_down = true; + runner_lock.input.raw.mouse_down = true; runner_lock.logic().unwrap(); // in case we get "mouseup" the same frame. TODO: handle via events instead runner_lock.needs_repaint = true; event.stop_propagation(); @@ -365,8 +391,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { let mut runner_lock = runner_ref.0.lock(); - if !runner_lock.web_input.is_touch { - runner_lock.web_input.mouse_pos = + if !runner_lock.input.is_touch { + runner_lock.input.mouse_pos = Some(pos_from_mouse_event(runner_lock.canvas_id(), &event)); runner_lock.needs_repaint = true; event.stop_propagation(); @@ -382,10 +408,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { let mut runner_lock = runner_ref.0.lock(); - if !runner_lock.web_input.is_touch { - runner_lock.web_input.mouse_pos = + if !runner_lock.input.is_touch { + runner_lock.input.mouse_pos = Some(pos_from_mouse_event(runner_lock.canvas_id(), &event)); - runner_lock.web_input.mouse_down = false; + runner_lock.input.raw.mouse_down = false; runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default(); @@ -400,8 +426,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::MouseEvent| { let mut runner_lock = runner_ref.0.lock(); - if !runner_lock.web_input.is_touch { - runner_lock.web_input.mouse_pos = None; + if !runner_lock.input.is_touch { + runner_lock.input.mouse_pos = None; runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default(); @@ -416,9 +442,9 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| { let mut runner_lock = runner_ref.0.lock(); - runner_lock.web_input.is_touch = true; - runner_lock.web_input.mouse_pos = Some(pos_from_touch_event(&event)); - runner_lock.web_input.mouse_down = true; + runner_lock.input.is_touch = true; + runner_lock.input.mouse_pos = Some(pos_from_touch_event(&event)); + runner_lock.input.raw.mouse_down = true; runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default(); @@ -432,8 +458,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| { let mut runner_lock = runner_ref.0.lock(); - runner_lock.web_input.is_touch = true; - runner_lock.web_input.mouse_pos = Some(pos_from_touch_event(&event)); + runner_lock.input.is_touch = true; + runner_lock.input.mouse_pos = Some(pos_from_touch_event(&event)); runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default(); @@ -447,10 +473,10 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::TouchEvent| { let mut runner_lock = runner_ref.0.lock(); - runner_lock.web_input.is_touch = true; - runner_lock.web_input.mouse_down = false; // First release mouse to click... + runner_lock.input.is_touch = true; + runner_lock.input.raw.mouse_down = false; // First release mouse to click... runner_lock.logic().unwrap(); // ...do the clicking... (TODO: handle via events instead) - runner_lock.web_input.mouse_pos = None; // ...remove hover effect + runner_lock.input.mouse_pos = None; // ...remove hover effect runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default(); @@ -464,8 +490,8 @@ fn install_canvas_events(runner_ref: &AppRunnerRef) -> Result<(), JsValue> { let runner_ref = runner_ref.clone(); let closure = Closure::wrap(Box::new(move |event: web_sys::WheelEvent| { let mut runner_lock = runner_ref.0.lock(); - runner_lock.web_input.scroll_delta.x -= event.delta_x() as f32; - runner_lock.web_input.scroll_delta.y -= event.delta_y() as f32; + runner_lock.input.scroll_delta.x -= event.delta_x() as f32; + runner_lock.input.scroll_delta.y -= event.delta_y() as f32; runner_lock.needs_repaint = true; event.stop_propagation(); event.prevent_default();