From b1eb5f91bed16684d344438655865f904b8fa8a4 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Sun, 28 Sep 2025 10:06:10 +0200 Subject: [PATCH] handwriting: Add test for egui::Event handling --- src/handwriting/mod.rs | 411 ++++++++++++---- ...inkr__handwriting__test__handle_input.snap | 455 ++++++++++++++++++ ...ng__test__input events to handwriting.snap | 7 + 3 files changed, 790 insertions(+), 83 deletions(-) create mode 100644 src/handwriting/snapshots/inkr__handwriting__test__handle_input.snap create mode 100644 src/handwriting/snapshots/inkr__handwriting__test__input events to handwriting.snap diff --git a/src/handwriting/mod.rs b/src/handwriting/mod.rs index 62fcaa8..20f05f5 100644 --- a/src/handwriting/mod.rs +++ b/src/handwriting/mod.rs @@ -15,12 +15,13 @@ use disk_format::{DiskFormat, RawStroke, RawStrokeHeader, f16_le}; use egui::{ Color32, Event, Frame, Id, Mesh, PointerButton, Pos2, Rect, Sense, Shape, Stroke, Theme, Ui, Vec2, - emath::{self, TSTransform}, + emath::{self, RectTransform, TSTransform}, epaint::{TessellationOptions, Tessellator, Vertex}, }; use eyre::{Context, bail}; use eyre::{OptionExt, eyre}; use half::f16; +use serde::Serialize; use zerocopy::{FromBytes, IntoBytes}; use crate::{custom_code_block::try_from_custom_code_block, rasterizer}; @@ -270,88 +271,12 @@ impl Handwriting { // Process input events and turn them into strokes for event in events { - let last_canvas_pos = self.e.current_stroke.last(); - - match event { - Event::PointerMoved(new_position) => { - let new_canvas_pos = from_screen * new_position; - if let Some(&last_canvas_pos) = last_canvas_pos { - if last_canvas_pos != new_canvas_pos { - self.push_to_stroke(new_canvas_pos); - response.mark_changed(); - } - } + let mut last_canvas_pos = self.e.current_stroke.last().copied(); + process_event(&mut last_canvas_pos, from_screen, &event, |tool_event| { + if self.on_tool_event(tool_event) { + hw_response.changed = true; // FIXME: ugly } - - Event::MouseMoved(mut delta) => { - if delta.length() == 0.0 { - continue; - } - - // FIXME: pinenote: MouseMovement delta does *not* take into account screen - // scaling and rotation, so unless you've scaling=1 and no rotation, the - // MouseMoved values will be all wrong. - if cfg!(feature = "pinenote") { - delta /= 1.8; - delta = -delta.rot90(); - } - - if let Some(&last_canvas_pos) = last_canvas_pos { - self.push_to_stroke(last_canvas_pos + delta); - response.mark_changed(); - } else { - println!("Got `MouseMoved`, but have no previous pos"); - } - } - - Event::PointerButton { - pos, - button, - pressed, - modifiers: _, - } => match (button, pressed) { - (PointerButton::Primary, true) => { - if last_canvas_pos.is_none() { - self.e.current_stroke.push(from_screen * pos); - } - } - (PointerButton::Primary, false) => { - if last_canvas_pos.is_some() { - self.push_to_stroke(from_screen * pos); - self.commit_current_line(hw_response); - response.mark_changed(); - } - - // Stop reading events. - // TODO: In theory, we can get multiple press->draw->release series - // in the same frame. Should handle this. - break; - } - (_, _) => continue, - }, - - // Stop drawing after pointer disappears or the window is unfocused - // TODO: In theory, we can get multiple press->draw->release series - // in the same frame. Should handle this. - Event::PointerGone | Event::WindowFocused(false) => { - if !self.e.current_stroke.is_empty() { - self.commit_current_line(hw_response); - break; - } - } - - Event::WindowFocused(true) - | Event::Copy - | Event::Cut - | Event::Paste(..) - | Event::Text(..) - | Event::Key { .. } - | Event::Zoom(..) - | Event::Ime(..) - | Event::Touch { .. } - | Event::MouseWheel { .. } - | Event::Screenshot { .. } => continue, - } + }); } } @@ -587,6 +512,134 @@ impl Handwriting { bytes.into_boxed_slice() } + + /// Handle a [ToolEvent]. Returns true if a stroke was completed. + fn on_tool_event(&mut self, tool_event: ToolEvent) -> bool { + match tool_event { + ToolEvent::Press { at } => { + debug_assert!(self.e.current_stroke.is_empty()); + self.push_to_stroke(at); + false + } + ToolEvent::Move { to } => { + self.push_to_stroke(to); + false + } + ToolEvent::Release => { + debug_assert!(!self.e.current_stroke.is_empty()); + self.strokes.push(mem::take(&mut self.e.current_stroke)); + true + } + } + } +} + +/// A simple event that can defines how a tool (e.g. the pen) is used on a [Handwriting]. +#[derive(Serialize)] +enum ToolEvent { + Press { at: Pos2 }, + Move { to: Pos2 }, + Release, +} + +/// Convert [egui::Event]s to [ToolEvent]s. +fn process_event( + last_canvas_pos: &mut Option, + from_screen: RectTransform, + event: &Event, + mut on_tool_event: impl FnMut(ToolEvent), +) { + match event { + &Event::PointerMoved(new_position) => { + let new_canvas_pos = from_screen * new_position; + if last_canvas_pos.is_some() && *last_canvas_pos != Some(new_canvas_pos) { + //self.push_to_stroke(new_canvas_pos); + //response.mark_changed(); + *last_canvas_pos = Some(new_canvas_pos); + on_tool_event(ToolEvent::Move { to: new_canvas_pos }); + } + } + + &Event::MouseMoved(mut delta) => { + if delta.length() == 0.0 { + return; + } + + // FIXME: pinenote: MouseMovement delta does *not* take into account screen + // scaling and rotation, so unless you've scaling=1 and no rotation, the + // MouseMoved values will be all wrong. + if cfg!(feature = "pinenote") { + delta /= 1.8; + delta = -delta.rot90(); + } + + if let Some(pos) = last_canvas_pos { + *pos += delta; + on_tool_event(ToolEvent::Move { to: *pos }); + //self.push_to_stroke(last_canvas_pos + delta); + //response.mark_changed(); + } else { + println!("Got `MouseMoved`, but have no previous pos"); + } + } + + &Event::PointerButton { + pos, + button, + pressed, + modifiers: _, + } => match (button, pressed) { + (PointerButton::Primary, true) => { + if last_canvas_pos.is_none() { + let pos = from_screen * pos; + *last_canvas_pos = Some(pos); + //self.e.current_stroke.push(from_screen * pos); + + on_tool_event(ToolEvent::Press { at: pos }); + } + } + (PointerButton::Primary, false) => { + if last_canvas_pos.take().is_some() { + let pos = from_screen * pos; + on_tool_event(ToolEvent::Move { to: pos }); + on_tool_event(ToolEvent::Release {}); + //self.push_to_stroke(from_screen * pos); + //self.commit_current_line(hw_response); + //response.mark_changed(); + } + + // Stop reading events. + // TODO: In theory, we can get multiple press->draw->release series + // in the same frame. Should handle this. + //break; + } + (_, _) => {} + }, + + // Stop drawing after pointer disappears or the window is unfocused + // TODO: In theory, we can get multiple press->draw->release series + // in the same frame. Should handle this. + Event::PointerGone | Event::WindowFocused(false) => { + //if !self.e.current_stroke.is_empty() { + if last_canvas_pos.take().is_some() { + on_tool_event(ToolEvent::Release {}); + //self.commit_current_line(hw_response); + //break; + } + } + + Event::WindowFocused(true) + | Event::Copy + | Event::Cut + | Event::Paste(..) + | Event::Text(..) + | Event::Key { .. } + | Event::Zoom(..) + | Event::Ime(..) + | Event::Touch { .. } + | Event::MouseWheel { .. } + | Event::Screenshot { .. } => {} + } } fn new_tessellator(pixels_per_point: f32) -> Tessellator { @@ -732,7 +785,9 @@ fn mesh_triangles(mesh: &Mesh) -> impl Iterator + Clone { mod test { use std::str::FromStr; - use super::Handwriting; + use egui::{Event, Modifiers, PointerButton, Pos2, Rect, emath::RectTransform}; + + use super::{Handwriting, process_event}; #[test] fn serialize_handwriting() { @@ -746,4 +801,194 @@ mod test { Handwriting::from_str(&serialized).expect("Handwriting must de/serialize correctly"); insta::assert_debug_snapshot!("deserialized handwriting", deserialized.strokes); } + + const TEST_EVENTS: &[Event] = &[ + Event::PointerMoved(Pos2::new(749.9, 225.6)), + Event::PointerButton { + pos: Pos2::new(749.9, 225.6), + button: PointerButton::Primary, + pressed: true, + modifiers: Modifiers::NONE, + }, + Event::PointerMoved(Pos2::new(749.9, 225.7)), + Event::PointerMoved(Pos2::new(749.9, 226.4)), + Event::PointerMoved(Pos2::new(750.2, 228.4)), + Event::PointerMoved(Pos2::new(751.0, 231.3)), + Event::PointerMoved(Pos2::new(752.6, 234.4)), + Event::PointerMoved(Pos2::new(754.1, 237.7)), + Event::PointerMoved(Pos2::new(755.8, 241.1)), + Event::PointerMoved(Pos2::new(757.7, 244.4)), + Event::PointerMoved(Pos2::new(759.3, 247.4)), + Event::PointerMoved(Pos2::new(760.8, 250.2)), + Event::PointerMoved(Pos2::new(762.8, 253.4)), + Event::PointerMoved(Pos2::new(765.1, 256.8)), + Event::PointerMoved(Pos2::new(767.7, 260.2)), + Event::PointerMoved(Pos2::new(771.2, 264.3)), + Event::PointerMoved(Pos2::new(774.6, 267.9)), + Event::PointerMoved(Pos2::new(778.2, 271.2)), + Event::PointerMoved(Pos2::new(782.7, 275.2)), + Event::PointerMoved(Pos2::new(786.7, 278.5)), + Event::PointerMoved(Pos2::new(790.4, 280.8)), + Event::PointerMoved(Pos2::new(794.1, 282.6)), + Event::PointerMoved(Pos2::new(797.9, 283.9)), + Event::PointerMoved(Pos2::new(801.9, 284.8)), + Event::PointerMoved(Pos2::new(805.9, 285.5)), + Event::PointerMoved(Pos2::new(810.2, 285.8)), + Event::PointerMoved(Pos2::new(814.5, 285.8)), + Event::PointerMoved(Pos2::new(818.2, 285.6)), + Event::PointerMoved(Pos2::new(821.6, 284.5)), + Event::PointerMoved(Pos2::new(824.7, 283.0)), + Event::PointerMoved(Pos2::new(827.5, 281.4)), + Event::PointerMoved(Pos2::new(830.4, 279.6)), + Event::PointerMoved(Pos2::new(833.4, 277.7)), + Event::PointerMoved(Pos2::new(836.1, 275.7)), + Event::PointerMoved(Pos2::new(838.6, 273.6)), + Event::PointerMoved(Pos2::new(840.9, 271.7)), + Event::PointerMoved(Pos2::new(843.0, 269.6)), + Event::PointerMoved(Pos2::new(845.4, 267.2)), + Event::PointerMoved(Pos2::new(847.7, 265.1)), + Event::PointerMoved(Pos2::new(849.8, 262.7)), + Event::PointerMoved(Pos2::new(852.0, 260.0)), + Event::PointerMoved(Pos2::new(854.3, 256.8)), + Event::PointerMoved(Pos2::new(856.3, 253.4)), + Event::PointerMoved(Pos2::new(858.2, 250.1)), + Event::PointerMoved(Pos2::new(860.0, 247.1)), + Event::PointerMoved(Pos2::new(861.5, 244.3)), + Event::PointerMoved(Pos2::new(862.8, 242.0)), + Event::PointerMoved(Pos2::new(864.1, 240.1)), + Event::PointerMoved(Pos2::new(865.0, 238.2)), + Event::PointerMoved(Pos2::new(865.8, 236.6)), + Event::PointerMoved(Pos2::new(866.5, 234.9)), + Event::PointerMoved(Pos2::new(867.1, 233.1)), + Event::PointerMoved(Pos2::new(867.8, 231.4)), + Event::PointerMoved(Pos2::new(868.4, 229.8)), + Event::PointerMoved(Pos2::new(868.7, 228.4)), + Event::PointerMoved(Pos2::new(868.9, 227.2)), + Event::PointerMoved(Pos2::new(869.1, 226.2)), + Event::PointerMoved(Pos2::new(869.1, 225.1)), + Event::PointerMoved(Pos2::new(869.1, 224.1)), + Event::PointerMoved(Pos2::new(869.1, 223.4)), + Event::PointerMoved(Pos2::new(869.1, 222.8)), + Event::PointerMoved(Pos2::new(869.1, 222.4)), + Event::PointerMoved(Pos2::new(869.1, 222.4)), + // Event::PointerButton { + // pos: Pos2::new(869.1, 222.4), + // button: PointerButton::Primary, + // pressed: false, + // modifiers: Modifiers::NONE, + // }, + Event::PointerGone, + Event::PointerMoved(Pos2::new(779.3, 158.6)), + // -- + // FIXME: This line looks weird. Probably because of a bug in the rasterizer when the X-coord is all the same. + Event::PointerButton { + pos: Pos2::new(779.3, 158.6), + button: PointerButton::Primary, + pressed: true, + modifiers: Modifiers::NONE, + }, + Event::PointerMoved(Pos2::new(779.3, 159.0)), + Event::PointerMoved(Pos2::new(779.3, 160.9)), + Event::PointerMoved(Pos2::new(779.3, 164.6)), + Event::PointerMoved(Pos2::new(779.3, 169.6)), + Event::PointerMoved(Pos2::new(779.3, 175.2)), + Event::PointerMoved(Pos2::new(779.3, 180.3)), + Event::PointerMoved(Pos2::new(779.3, 185.0)), + Event::PointerMoved(Pos2::new(779.3, 189.4)), + Event::PointerMoved(Pos2::new(779.3, 192.8)), + Event::PointerMoved(Pos2::new(779.3, 194.9)), + Event::PointerMoved(Pos2::new(779.3, 196.1)), + Event::PointerMoved(Pos2::new(779.3, 197.0)), + Event::PointerMoved(Pos2::new(779.3, 197.6)), + Event::PointerMoved(Pos2::new(779.3, 198.1)), + Event::PointerMoved(Pos2::new(779.3, 198.5)), + Event::PointerMoved(Pos2::new(779.3, 198.8)), + Event::PointerMoved(Pos2::new(779.3, 199.0)), + Event::PointerMoved(Pos2::new(779.3, 199.2)), + Event::PointerMoved(Pos2::new(779.3, 199.2)), + Event::PointerButton { + pos: Pos2::new(779.3, 199.2), + button: PointerButton::Primary, + pressed: false, + modifiers: Modifiers::NONE, + }, + // -- + Event::PointerMoved(Pos2::new(841.5, 159.2)), + Event::PointerButton { + pos: Pos2::new(841.5, 159.2), + button: PointerButton::Primary, + pressed: true, + modifiers: Modifiers::NONE, + }, + Event::PointerMoved(Pos2::new(841.5, 159.3)), + Event::PointerMoved(Pos2::new(841.5, 159.7)), + Event::PointerMoved(Pos2::new(841.5, 160.5)), + Event::PointerMoved(Pos2::new(841.5, 162.4)), + Event::PointerMoved(Pos2::new(841.5, 165.1)), + Event::PointerMoved(Pos2::new(841.5, 168.4)), + Event::PointerMoved(Pos2::new(841.5, 171.6)), + Event::PointerMoved(Pos2::new(841.5, 174.4)), + Event::PointerMoved(Pos2::new(841.5, 177.1)), + Event::PointerMoved(Pos2::new(841.5, 179.3)), + Event::PointerMoved(Pos2::new(841.5, 180.9)), + Event::PointerMoved(Pos2::new(841.5, 182.4)), + Event::PointerMoved(Pos2::new(841.5, 183.5)), + Event::PointerMoved(Pos2::new(841.5, 184.5)), + Event::PointerMoved(Pos2::new(841.5, 185.6)), + Event::PointerMoved(Pos2::new(841.5, 187.0)), + Event::PointerMoved(Pos2::new(841.5, 188.6)), + Event::PointerMoved(Pos2::new(841.5, 190.3)), + Event::PointerMoved(Pos2::new(841.5, 191.8)), + Event::PointerMoved(Pos2::new(841.3, 192.7)), + Event::PointerMoved(Pos2::new(841.0, 193.3)), + Event::PointerMoved(Pos2::new(841.0, 193.7)), + Event::PointerMoved(Pos2::new(841.1, 193.9)), + Event::PointerMoved(Pos2::new(841.3, 193.9)), + Event::PointerMoved(Pos2::new(841.4, 194.0)), + Event::PointerMoved(Pos2::new(841.4, 194.2)), + Event::PointerMoved(Pos2::new(841.4, 194.6)), + Event::PointerMoved(Pos2::new(841.4, 194.9)), + Event::PointerMoved(Pos2::new(841.4, 195.1)), + Event::PointerMoved(Pos2::new(841.4, 195.1)), + Event::PointerButton { + pos: Pos2::new(841.4, 195.1), + button: PointerButton::Primary, + pressed: false, + modifiers: Modifiers::NONE, + }, + ]; + + fn from_screen() -> RectTransform { + RectTransform::from_to( + Rect::from_two_pos(Pos2::new(570.0, 145.1), Pos2::new(1116.4, 245.1)), + Rect::from_two_pos(Pos2::new(0.0, 0.0), Pos2::new(546.4, 100.0)), + ) + } + + #[test] + fn handle_input() { + let mut tool_events = vec![]; + let mut last_pos = None; + let from_screen = from_screen(); + for event in TEST_EVENTS { + process_event(&mut last_pos, from_screen, event, |tool_event| { + tool_events.push(tool_event) + }); + } + insta::assert_yaml_snapshot!(tool_events); + } + + #[test] + fn input_to_handwriting() { + let mut handwriting = Handwriting::default(); + let mut last_pos = None; + let from_screen = from_screen(); + for event in TEST_EVENTS { + process_event(&mut last_pos, from_screen, event, |tool_event| { + handwriting.on_tool_event(tool_event); + }); + } + let serialized = handwriting.to_string(); + insta::assert_snapshot!("input events to handwriting", serialized); + } } diff --git a/src/handwriting/snapshots/inkr__handwriting__test__handle_input.snap b/src/handwriting/snapshots/inkr__handwriting__test__handle_input.snap new file mode 100644 index 0000000..f06a1cf --- /dev/null +++ b/src/handwriting/snapshots/inkr__handwriting__test__handle_input.snap @@ -0,0 +1,455 @@ +--- +source: src/handwriting/mod.rs +expression: tool_events +--- +- Press: + at: + x: 179.90002 + y: 80.5 +- Move: + to: + x: 179.90002 + y: 80.59999 +- Move: + to: + x: 179.90002 + y: 81.29999 +- Move: + to: + x: 180.20001 + y: 83.29999 +- Move: + to: + x: 181 + y: 86.2 +- Move: + to: + x: 182.59998 + y: 89.29999 +- Move: + to: + x: 184.09998 + y: 92.59999 +- Move: + to: + x: 185.79999 + y: 96 +- Move: + to: + x: 187.70001 + y: 99.29999 +- Move: + to: + x: 189.3 + y: 102.29999 +- Move: + to: + x: 190.8 + y: 105.09999 +- Move: + to: + x: 192.79999 + y: 108.29998 +- Move: + to: + x: 195.09998 + y: 111.69999 +- Move: + to: + x: 197.70001 + y: 115.100006 +- Move: + to: + x: 201.20001 + y: 119.19998 +- Move: + to: + x: 204.59998 + y: 122.799995 +- Move: + to: + x: 208.20001 + y: 126.100006 +- Move: + to: + x: 212.70001 + y: 130.1 +- Move: + to: + x: 216.70001 + y: 133.4 +- Move: + to: + x: 220.40002 + y: 135.69998 +- Move: + to: + x: 224.09998 + y: 137.5 +- Move: + to: + x: 227.90002 + y: 138.79999 +- Move: + to: + x: 231.90002 + y: 139.69998 +- Move: + to: + x: 235.90002 + y: 140.4 +- Move: + to: + x: 240.20001 + y: 140.69998 +- Move: + to: + x: 244.5 + y: 140.69998 +- Move: + to: + x: 248.20001 + y: 140.5 +- Move: + to: + x: 251.59996 + y: 139.4 +- Move: + to: + x: 254.70001 + y: 137.9 +- Move: + to: + x: 257.5 + y: 136.29999 +- Move: + to: + x: 260.40002 + y: 134.5 +- Move: + to: + x: 263.40002 + y: 132.6 +- Move: + to: + x: 266.09998 + y: 130.6 +- Move: + to: + x: 268.59998 + y: 128.5 +- Move: + to: + x: 270.90002 + y: 126.600006 +- Move: + to: + x: 273 + y: 124.5 +- Move: + to: + x: 275.40002 + y: 122.100006 +- Move: + to: + x: 277.70004 + y: 120.00001 +- Move: + to: + x: 279.8 + y: 117.60001 +- Move: + to: + x: 282 + y: 114.899994 +- Move: + to: + x: 284.3 + y: 111.69999 +- Move: + to: + x: 286.3 + y: 108.29998 +- Move: + to: + x: 288.2 + y: 104.99999 +- Move: + to: + x: 290 + y: 102 +- Move: + to: + x: 291.5 + y: 99.2 +- Move: + to: + x: 292.8 + y: 96.899994 +- Move: + to: + x: 294.09995 + y: 95 +- Move: + to: + x: 295 + y: 93.09999 +- Move: + to: + x: 295.8 + y: 91.5 +- Move: + to: + x: 296.5 + y: 89.79999 +- Move: + to: + x: 297.1 + y: 88 +- Move: + to: + x: 297.8 + y: 86.29999 +- Move: + to: + x: 298.40005 + y: 84.7 +- Move: + to: + x: 298.7 + y: 83.29999 +- Move: + to: + x: 298.90002 + y: 82.09999 +- Move: + to: + x: 299.1 + y: 81.09999 +- Move: + to: + x: 299.1 + y: 80 +- Move: + to: + x: 299.1 + y: 79 +- Move: + to: + x: 299.1 + y: 78.29999 +- Move: + to: + x: 299.1 + y: 77.7 +- Move: + to: + x: 299.1 + y: 77.29999 +- Release +- Press: + at: + x: 209.29999 + y: 13.500001 +- Move: + to: + x: 209.29999 + y: 13.899994 +- Move: + to: + x: 209.29999 + y: 15.799988 +- Move: + to: + x: 209.29999 + y: 19.5 +- Move: + to: + x: 209.29999 + y: 24.5 +- Move: + to: + x: 209.29999 + y: 30.09999 +- Move: + to: + x: 209.29999 + y: 35.199997 +- Move: + to: + x: 209.29999 + y: 39.899994 +- Move: + to: + x: 209.29999 + y: 44.299988 +- Move: + to: + x: 209.29999 + y: 47.699997 +- Move: + to: + x: 209.29999 + y: 49.799988 +- Move: + to: + x: 209.29999 + y: 51 +- Move: + to: + x: 209.29999 + y: 51.899994 +- Move: + to: + x: 209.29999 + y: 52.499996 +- Move: + to: + x: 209.29999 + y: 52.999996 +- Move: + to: + x: 209.29999 + y: 53.399994 +- Move: + to: + x: 209.29999 + y: 53.699993 +- Move: + to: + x: 209.29999 + y: 53.89999 +- Move: + to: + x: 209.29999 + y: 54.09999 +- Move: + to: + x: 209.29999 + y: 54.09999 +- Release +- Press: + at: + x: 271.5 + y: 14.099991 +- Move: + to: + x: 271.5 + y: 14.199998 +- Move: + to: + x: 271.5 + y: 14.599991 +- Move: + to: + x: 271.5 + y: 15.399994 +- Move: + to: + x: 271.5 + y: 17.299988 +- Move: + to: + x: 271.5 + y: 20 +- Move: + to: + x: 271.5 + y: 23.299988 +- Move: + to: + x: 271.5 + y: 26.499998 +- Move: + to: + x: 271.5 + y: 29.299986 +- Move: + to: + x: 271.5 + y: 32 +- Move: + to: + x: 271.5 + y: 34.199997 +- Move: + to: + x: 271.5 + y: 35.799988 +- Move: + to: + x: 271.5 + y: 37.299988 +- Move: + to: + x: 271.5 + y: 38.399994 +- Move: + to: + x: 271.5 + y: 39.399994 +- Move: + to: + x: 271.5 + y: 40.5 +- Move: + to: + x: 271.5 + y: 41.899994 +- Move: + to: + x: 271.5 + y: 43.5 +- Move: + to: + x: 271.5 + y: 45.199997 +- Move: + to: + x: 271.5 + y: 46.699997 +- Move: + to: + x: 271.3 + y: 47.59999 +- Move: + to: + x: 271 + y: 48.199997 +- Move: + to: + x: 271 + y: 48.59999 +- Move: + to: + x: 271.09998 + y: 48.799988 +- Move: + to: + x: 271.3 + y: 48.799988 +- Move: + to: + x: 271.40002 + y: 48.899994 +- Move: + to: + x: 271.40002 + y: 49.09999 +- Move: + to: + x: 271.40002 + y: 49.5 +- Move: + to: + x: 271.40002 + y: 49.799988 +- Move: + to: + x: 271.40002 + y: 50 +- Move: + to: + x: 271.40002 + y: 50 +- Release diff --git a/src/handwriting/snapshots/inkr__handwriting__test__input events to handwriting.snap b/src/handwriting/snapshots/inkr__handwriting__test__input events to handwriting.snap new file mode 100644 index 0000000..8ee8cb4 --- /dev/null +++ b/src/handwriting/snapshots/inkr__handwriting__test__input events to handwriting.snap @@ -0,0 +1,7 @@ +--- +source: src/handwriting/mod.rs +expression: serialized +--- +```handwriting +AQA9AJ9ZCFWfWQpVn1kVVaJZNVWoWWNVtVmVVcFZylXOWQBW3lk1VupZZVb2WZJWBlrFVhla+1YuWjJXSlpzV2VarVeCWuJXploRWMZaK1jjWj5YAVtMWB9bVlg/W15YX1tjWIJbZlikW2ZYwltkWN1bW1j2W09YBlxCWBJcNFgeXCVYKFwVWDJcBFg8XOpXRFzIV05coldXXIBXX1xaV2hcLldxXPtWeVzFVoFckFaIXGBWjlwzVpNcDlaYXPBVnFzSVZ9cuFWiXJ1VpFyAVadcZVWqXEtVq1w1VaxcIlWsXBJVrFwAVaxc8FSsXOVUrFzbVKxc1VQTAIpawEqKWvNKilrmS4pa4EyKWiBOilqGT4paZlCKWv1QilqKUYpa9lGKWjpSilpgUopafVKKWpBSilqgUoparVKKWrZSilq9Uopaw1IeAD5cDUs+XBpLPlxNSz5cs0s+XFNMPlwATT5c000+XKBOPlxTTz5cAFA+XEZQPlx6UD5cqlA+XM1QPlztUD5cEFE+XD1RPlxwUT5cplE+XNZRPVzzUTxcBlI8XBNSPFwaUj1cGlI+XB1SPlwjUj5cMFI+XDpSPlxAUg== +```