1use std::time::Duration;
6
7use crate::{PointerChange, PointerData, PointerDeviceKind, PointerSignalKind, ViewId};
8
9#[derive(Clone, Copy, Debug, PartialEq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct PointerReport {
17 pub view_id: ViewId,
19
20 pub time_stamp: Duration,
22
23 pub device: i64,
26
27 pub kind: PointerDeviceKind,
29
30 pub position: [f64; 2],
32
33 pub change: ReportedChange,
35
36 pub contact: Contact,
38}
39
40#[derive(Clone, Copy, Debug, PartialEq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43pub enum ReportedChange {
44 Add,
46
47 Remove,
49
50 Hover { buttons: i64 },
52
53 Down { buttons: i64 },
55
56 Move { buttons: i64 },
58
59 Up { buttons: i64 },
61
62 Cancel { buttons: i64 },
64
65 Scroll { delta: [f64; 2] },
68
69 ScrollInertiaCancel,
71
72 Scale { scale: f64 },
74
75 PanZoomStart,
77
78 PanZoomUpdate {
81 pan: [f64; 2],
82 scale: f64,
83 rotation: f64,
84 },
85
86 PanZoomEnd,
88}
89
90#[derive(Clone, Copy, Debug, PartialEq)]
93#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
94pub struct Contact {
95 pub pressure: f64,
96 pub pressure_min: f64,
97 pub pressure_max: f64,
98 pub distance: f64,
99 pub distance_max: f64,
100 pub size: f64,
101 pub radius_major: f64,
102 pub radius_minor: f64,
103 pub radius_min: f64,
104 pub radius_max: f64,
105 pub orientation: f64,
106 pub tilt: f64,
107}
108
109impl Default for Contact {
110 fn default() -> Contact {
111 Contact {
112 pressure: 1.0,
113 pressure_min: 1.0,
114 pressure_max: 1.0,
115 distance: 0.0,
116 distance_max: 0.0,
117 size: 0.0,
118 radius_major: 0.0,
119 radius_minor: 0.0,
120 radius_min: 0.0,
121 radius_max: 0.0,
122 orientation: 0.0,
123 tilt: 0.0,
124 }
125 }
126}
127
128impl From<PointerReport> for PointerData {
129 fn from(report: PointerReport) -> PointerData {
133 let contact = report.contact;
134 let mut data = PointerData {
135 view_id: report.view_id,
136 time_stamp: report.time_stamp,
137 kind: report.kind,
138 device: report.device,
139 physical_x: report.position[0],
140 physical_y: report.position[1],
141 pressure: contact.pressure,
142 pressure_min: contact.pressure_min,
143 pressure_max: contact.pressure_max,
144 distance: contact.distance,
145 distance_max: contact.distance_max,
146 size: contact.size,
147 radius_major: contact.radius_major,
148 radius_minor: contact.radius_minor,
149 radius_min: contact.radius_min,
150 radius_max: contact.radius_max,
151 orientation: contact.orientation,
152 tilt: contact.tilt,
153 ..PointerData::default()
154 };
155 report.change.write_into(&mut data);
156 data
157 }
158}
159
160impl ReportedChange {
161 fn write_into(self, data: &mut PointerData) {
163 let (change, buttons) = match self {
164 ReportedChange::Add => (PointerChange::Add, 0),
165 ReportedChange::Remove => (PointerChange::Remove, 0),
166 ReportedChange::Hover { buttons } => (PointerChange::Hover, buttons),
167 ReportedChange::Down { buttons } => (PointerChange::Down, buttons),
168 ReportedChange::Move { buttons } => (PointerChange::Move, buttons),
169 ReportedChange::Up { buttons } => (PointerChange::Up, buttons),
170 ReportedChange::Cancel { buttons } => (PointerChange::Cancel, buttons),
171 ReportedChange::Scroll { delta } => {
173 data.signal_kind = Some(PointerSignalKind::Scroll);
174 [data.scroll_delta_x, data.scroll_delta_y] = delta;
175 (PointerChange::Hover, 0)
176 }
177 ReportedChange::ScrollInertiaCancel => {
178 data.signal_kind = Some(PointerSignalKind::ScrollInertiaCancel);
179 (PointerChange::Hover, 0)
180 }
181 ReportedChange::Scale { scale } => {
182 data.signal_kind = Some(PointerSignalKind::Scale);
183 data.scale = scale;
184 (PointerChange::Hover, 0)
185 }
186 ReportedChange::PanZoomStart => (PointerChange::PanZoomStart, 0),
187 ReportedChange::PanZoomUpdate {
188 pan,
189 scale,
190 rotation,
191 } => {
192 [data.pan_x, data.pan_y] = pan;
193 data.scale = scale;
194 data.rotation = rotation;
195 (PointerChange::PanZoomUpdate, 0)
196 }
197 ReportedChange::PanZoomEnd => (PointerChange::PanZoomEnd, 0),
198 };
199 data.change = change;
200 data.buttons = buttons;
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 fn report(change: ReportedChange) -> PointerReport {
209 PointerReport {
210 view_id: ViewId(3),
211 time_stamp: Duration::from_millis(5),
212 device: 2,
213 kind: PointerDeviceKind::Mouse,
214 position: [10.0, 20.0],
215 change,
216 contact: Contact::default(),
217 }
218 }
219
220 #[test]
221 fn a_report_is_the_datum_with_what_only_the_converter_knows_left_at_zero() {
222 let data = PointerData::from(report(ReportedChange::Down { buttons: 1 }));
223 assert_eq!(data.change, PointerChange::Down);
224 assert_eq!(data.buttons, 1);
225 assert_eq!([data.physical_x, data.physical_y], [10.0, 20.0]);
226 assert_eq!((data.view_id, data.device), (ViewId(3), 2));
227 assert_eq!(data.embedder_id, 0, "no host numbers its system events");
228 assert_eq!(data.pressure, 1.0, "a mouse detects no pressure");
229 assert_eq!(data.pointer_identifier, 0);
230 assert_eq!([data.physical_delta_x, data.physical_delta_y], [0.0, 0.0]);
231 assert!(!data.synthesized);
232 assert!(data.signal_kind.is_none());
233 }
234
235 #[test]
236 fn a_scroll_is_a_signal_on_a_hover() {
237 let data = PointerData::from(report(ReportedChange::Scroll { delta: [0.0, 40.0] }));
238 assert_eq!(data.change, PointerChange::Hover);
239 assert_eq!(data.signal_kind, Some(PointerSignalKind::Scroll));
240 assert_eq!([data.scroll_delta_x, data.scroll_delta_y], [0.0, 40.0]);
241 }
242
243 #[test]
244 fn a_pan_zoom_update_carries_its_totals() {
245 let data = PointerData::from(report(ReportedChange::PanZoomUpdate {
246 pan: [3.0, 4.0],
247 scale: 1.5,
248 rotation: 0.25,
249 }));
250 assert_eq!(data.change, PointerChange::PanZoomUpdate);
251 assert_eq!([data.pan_x, data.pan_y], [3.0, 4.0]);
252 assert_eq!((data.scale, data.rotation), (1.5, 0.25));
253 assert_eq!([data.pan_delta_x, data.pan_delta_y], [0.0, 0.0]);
254 }
255}