1#![no_std]
2#![doc = include_str!("../README.md")]
3
4use embedded_hal::i2c::{ErrorType, I2c, SevenBitAddress};
5use num_enum::{FromPrimitive, IntoPrimitive};
6
7#[cfg(feature = "event_process")]
8use core::time::Duration;
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13const DEFAULT_FT6X36_ADDRESS: u8 = 0x38;
14const REPORT_SIZE: usize = 0x0f;
15
16#[cfg(feature = "event_process")]
17const MAX_DELTA_TOUCH_EVENT: Duration = Duration::from_millis(200);
18
19#[derive(Copy, Clone, Debug)]
21#[cfg_attr(feature = "defmt", derive(defmt::Format))]
22pub struct Dimension(pub u16, pub u16);
23
24pub struct Ft6x36<I2C> {
30 address: u8,
32 i2c: I2C,
34 info: Option<Ft6x36Info>,
36 #[cfg(feature = "event_process")]
37 events: (Option<TimedRawTouchEvent>, Option<TimedRawTouchEvent>),
39 #[cfg(feature = "event_process")]
40 config: ProcessEventConfig,
42 orientation: Orientation,
44 size: Dimension,
46}
47
48#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50#[derive(Copy, Clone, Debug)]
51#[cfg_attr(feature = "defmt", derive(defmt::Format))]
52pub enum Orientation {
53 Portrait,
54 Landscape,
55 InvertedPortrait,
56 InvertedLandscape,
57}
58
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60#[cfg(feature = "event_process")]
61#[cfg_attr(feature = "defmt", derive(defmt::Format))]
62pub struct ProcessEventConfig {
63 gesture_timing: Duration,
64 max_swipe_delta: u16,
65 min_swipe_delta: u16,
66}
67
68#[cfg(feature = "event_process")]
69impl Default for ProcessEventConfig {
70 fn default() -> Self {
71 ProcessEventConfig {
72 gesture_timing: Duration::from_millis(800),
73 max_swipe_delta: 30,
74 min_swipe_delta: 30,
75 }
76 }
77}
78
79#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
80#[cfg(feature = "event_process")]
81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
82#[derive(Debug, PartialEq, Eq)]
83pub struct TimedRawTouchEvent {
84 time: Duration,
85 event: RawTouchEvent,
86}
87
88#[allow(dead_code)]
89#[derive(Copy, Clone, Debug)]
90#[cfg_attr(feature = "defmt", derive(defmt::Format))]
91pub struct Diagnostics {
92 power_mode: u8,
93 g_mode: u8,
94 lib_version: u16,
95 state: u8,
96 control_mode: u8,
97}
98
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100#[derive(Copy, Clone, Debug, PartialEq, Eq)]
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102pub struct TouchPoint {
103 pub touch_type: TouchType,
104 pub x: u16,
105 pub y: u16,
106}
107
108impl TouchPoint {
109 fn translate_coordinates(self, size: Dimension, orientation: Orientation) -> Self {
110 fn difference_or_zero(o1: u16, o2: u16) -> u16 {
111 if o2 > o1 {
112 0
113 } else {
114 o1 - o2
115 }
116 }
117 let TouchPoint { touch_type, x, y } = self;
118 let (x, y) = match orientation {
119 Orientation::Portrait => (x, y),
120 Orientation::InvertedPortrait => {
121 (difference_or_zero(size.0, x), difference_or_zero(size.1, y))
122 }
123 Orientation::Landscape => (y, difference_or_zero(size.0, x)),
124 Orientation::InvertedLandscape => (difference_or_zero(size.1, y), x),
125 };
126 TouchPoint { x, y, touch_type }
127 }
128}
129
130impl From<&[u8]> for TouchPoint {
131 fn from(data: &[u8]) -> Self {
132 let x: u16 = ((data[0] as u16 & 0x0f) << 8) | (data[1] as u16);
133 let y: u16 = ((data[2] as u16 & 0x0f) << 8) | (data[3] as u16);
134 let touch_type: TouchType = data[0].into();
135
136 Self { touch_type, x, y }
137 }
138}
139
140#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
141#[derive(Clone, Copy, Debug, PartialEq, Eq)]
142#[cfg_attr(feature = "defmt", derive(defmt::Format))]
143pub enum Direction {
144 Up,
145 Down,
146 Left,
147 Right,
148}
149
150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
151#[derive(Clone, Copy, Debug, PartialEq, Eq)]
152#[cfg_attr(feature = "defmt", derive(defmt::Format))]
153pub enum Zoom {
154 ZoomIn(TouchPoint),
155 ZoomOut(TouchPoint),
156}
157
158#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
159#[derive(Clone, Copy, Debug, PartialEq, Eq)]
160#[cfg_attr(feature = "defmt", derive(defmt::Format))]
161pub struct SwipeInfo {
162 pub velocity: u16,
163 pub point: TouchPoint,
164}
165
166#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
167#[derive(Clone, Copy, Debug, PartialEq, Eq)]
168#[cfg_attr(feature = "defmt", derive(defmt::Format))]
169pub enum TouchEvent {
170 TouchOnePoint(TouchPoint),
171 TouchTwoPoint(TouchPoint, TouchPoint),
172 Swipe(Direction, SwipeInfo),
173 Zoom(Zoom),
174}
175
176#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
178#[repr(u8)]
179#[derive(Clone, Copy, Debug, FromPrimitive, IntoPrimitive, PartialEq, Eq)]
180#[cfg_attr(feature = "defmt", derive(defmt::Format))]
181pub enum DeviceMode {
182 #[default]
184 Working = 0b000,
185 Factory = 0b100,
187}
188
189#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
190#[repr(u8)]
191#[derive(Clone, Copy, Debug, IntoPrimitive, PartialEq, Eq)]
192#[cfg_attr(feature = "defmt", derive(defmt::Format))]
193pub enum TouchType {
194 Press = 0b00,
195 Release = 0b01,
196 Contact = 0b10,
197 Invalid = 0b11,
198}
199
200impl From<u8> for TouchType {
201 fn from(data: u8) -> Self {
202 match (data >> 6) & 0b0000_0011 {
203 0b00 => TouchType::Press,
204 0b01 => TouchType::Release,
205 0b10 => TouchType::Contact,
206 _ => TouchType::Invalid,
207 }
208 }
209}
210
211#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
213#[allow(dead_code)]
214#[derive(Copy, Clone, Debug, Eq, PartialEq)]
215#[cfg_attr(feature = "defmt", derive(defmt::Format))]
216pub struct RawTouchEvent {
217 pub device_mode: DeviceMode,
219 pub gesture_id: GestureId,
220 pub p1: Option<TouchPoint>,
221 pub p2: Option<TouchPoint>,
222}
223
224impl From<[u8; REPORT_SIZE]> for RawTouchEvent {
225 fn from(report: [u8; REPORT_SIZE]) -> Self {
226 let (p1, p2) = match report[2] {
227 1 => (Some(TouchPoint::from(&report[3..7])), None),
228 2 => (
229 Some(TouchPoint::from(&report[3..7])),
230 Some(TouchPoint::from(&report[9..13])),
231 ),
232 _ => (None, None),
233 };
234
235 RawTouchEvent {
236 device_mode: report[0].into(),
237 gesture_id: report[1].into(),
238 p1,
239 p2,
240 }
241 }
242}
243
244impl RawTouchEvent {
245 fn translate_orientation(self, size: Dimension, orientation: Orientation) -> Self {
246 let RawTouchEvent {
247 device_mode,
248 gesture_id,
249 p1,
250 p2,
251 } = self;
252 let p1 = p1.map(|p| p.translate_coordinates(size, orientation));
253 let p2 = p2.map(|p| p.translate_coordinates(size, orientation));
254 RawTouchEvent {
255 device_mode,
256 gesture_id,
257 p1,
258 p2,
259 }
260 }
261}
262
263#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
266#[allow(dead_code)]
267#[derive(Debug, Clone, Copy)]
268#[cfg_attr(feature = "defmt", derive(defmt::Format))]
269pub struct GestureParams {
270 minimum_angle: u8,
271 offset_left_right: u8,
272 offset_up_down: u8,
273 dist_left_right: u8,
274 dist_up_down: u8,
275 dist_zoom: u8,
276}
277
278macro_rules! get_offset {
279 ($first:expr, $relative_offset:expr) => {
280 ($relative_offset as u8 - $first as u8) as usize
281 };
282}
283
284#[allow(dead_code)]
286#[repr(u8)]
287#[derive(Debug, Clone, Copy, IntoPrimitive)]
288enum Reg {
289 DeviceMode = 0x00,
290
291 GestId = 0x01,
292 TouchDeviceStatus = 0x02,
293
294 P1XH = 0x03,
295 P1XL = 0x04,
296 P1YH = 0x05,
297 P1YL = 0x06,
298 P1Weight = 0x07,
299 P1Misc = 0x08,
300
301 P2XH = 0x09,
302 P2XL = 0x0A,
303 P2YH = 0x0B,
304 P2YL = 0x0C,
305 P2Weight = 0x0D,
306 P2Misc = 0x0E,
307
308 TouchDetectionThreshold = 0x80,
309 TouchFilterCoeff = 0x85,
310 ControlMode = 0x86,
311 TimeActiveMonitor = 0x87,
312 PeriodActive = 0x88,
313 PeriodMonitor = 0x89,
314
315 GestRadianValue = 0x91,
316 GestOffsetLeftRight = 0x92,
317 GestOffsetUpDown = 0x93,
318 GestDistLeftRight = 0x94,
319 GestDistUpDown = 0x95,
320 GestDistZoom = 0x96,
321
322 LibVersionH = 0xA1,
323 LibVersionL = 0xA2,
324 ChipId = 0xA3,
325
326 GMode = 0xA4,
327 PowerMode = 0xA5,
328 FirmwareId = 0xA6,
329 PanelId = 0xA8,
330 ReleaseCode = 0xAF,
331
332 OperatingMode = 0xBC,
333}
334
335#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
337#[repr(u8)]
338#[derive(Clone, Copy, Debug, IntoPrimitive, FromPrimitive, PartialEq, Eq)]
339#[cfg_attr(feature = "defmt", derive(defmt::Format))]
340pub enum GestureId {
341 #[default]
342 NoGesture = 0x00,
343 MoveUp = 0x10,
344 MoveRight = 0x14,
345 MoveDown = 0x18,
346 MoveLeft = 0x1C,
347 ZoomIn = 0x48,
348 ZoomOut = 0x49,
349}
350
351#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
353#[repr(u8)]
354#[derive(Clone, Copy, Debug, IntoPrimitive, FromPrimitive)]
355#[cfg_attr(feature = "defmt", derive(defmt::Format))]
356pub enum ChipId {
357 #[default]
358 Unknown,
359 Ft6206 = 0x06,
360 Ft6236 = 0x36,
361 Ft6236u = 0x64,
362}
363
364#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
366#[allow(dead_code)]
367#[derive(Clone, Copy, Debug)]
368pub struct Ft6x36Info {
369 chip_id: ChipId,
371 firmware_id: u8,
373 panel_id: u8,
375 release_code: u8,
377}
378
379impl<I2C> Ft6x36<I2C>
380where
381 I2C: I2c<SevenBitAddress>,
382{
383 pub fn new(i2c: I2C, size: Dimension) -> Self {
395 Self {
396 address: DEFAULT_FT6X36_ADDRESS,
397 i2c,
398 info: None,
399 #[cfg(feature = "event_process")]
400 events: (None, None),
401 #[cfg(feature = "event_process")]
402 config: ProcessEventConfig::default(),
403 orientation: Orientation::Portrait,
404 size,
405 }
406 }
407
408 #[cfg(feature = "event_process")]
421 pub fn new_with_config(i2c: I2C, size: Dimension, config: ProcessEventConfig) -> Self {
422 Self {
423 address: DEFAULT_FT6X36_ADDRESS,
424 i2c,
425 info: None,
426 events: (None, None),
427 config,
428 size,
429 orientation: Orientation::Portrait,
430 }
431 }
432
433 pub fn init(&mut self) -> Result<(), <I2C as ErrorType>::Error> {
439 let mut buf: [u8; 13] = [0; 13];
440 self.i2c
441 .write_read(self.address, &[Reg::ChipId.into()], &mut buf)?;
442 let chip_id: ChipId = buf[get_offset!(Reg::ChipId, Reg::ChipId)].into();
443 let firmware_id: u8 = buf[get_offset!(Reg::ChipId, Reg::FirmwareId)];
444 let panel_id: u8 = buf[get_offset!(Reg::ChipId, Reg::PanelId)];
445 let release_code: u8 = buf[get_offset!(Reg::ChipId, Reg::ReleaseCode)];
446 self.info = Some(Ft6x36Info {
447 chip_id,
448 firmware_id,
449 panel_id,
450 release_code,
451 });
452 self.set_control_mode(0)?;
453 Ok(())
454 }
455
456 pub fn set_orientation(&mut self, orientation: Orientation) {
462 self.orientation = orientation;
463 }
464
465 pub fn get_touch_event(&mut self) -> Result<RawTouchEvent, <I2C as ErrorType>::Error> {
471 let mut report: [u8; REPORT_SIZE] = [0; REPORT_SIZE];
472 self.i2c
473 .write_read(self.address, &[Reg::DeviceMode.into()], &mut report)?;
474
475 let event: RawTouchEvent = report.into();
476 Ok(event.translate_orientation(self.size, self.orientation))
477 }
478
479 pub fn get_gesture_params(&mut self) -> Result<GestureParams, <I2C as ErrorType>::Error> {
482 let mut buf: [u8; 6] = [0; 6];
483
484 self.i2c
485 .write_read(self.address, &[Reg::GestRadianValue.into()], &mut buf)?;
486 Ok(GestureParams {
487 minimum_angle: buf[0],
488 offset_left_right: buf[1],
489 offset_up_down: buf[2],
490 dist_left_right: buf[3],
491 dist_up_down: buf[4],
492 dist_zoom: buf[5],
493 })
494 }
495
496 pub fn set_touch_threshold(&mut self, value: u8) -> Result<(), <I2C as ErrorType>::Error> {
502 self.i2c
503 .write(self.address, &[Reg::TouchDetectionThreshold.into(), value])
504 }
505
506 pub fn set_touch_filter_coefficient(
512 &mut self,
513 value: u8,
514 ) -> Result<(), <I2C as ErrorType>::Error> {
515 self.i2c
516 .write(self.address, &[Reg::TouchFilterCoeff.into(), value])
517 }
518
519 pub fn set_control_mode(&mut self, value: u8) -> Result<(), <I2C as ErrorType>::Error> {
529 self.i2c
530 .write(self.address, &[Reg::ControlMode.into(), value])
531 }
532
533 pub fn set_time_active_monitor(&mut self, value: u8) -> Result<(), <I2C as ErrorType>::Error> {
539 self.i2c
540 .write(self.address, &[Reg::TimeActiveMonitor.into(), value])
541 }
542
543 pub fn set_period_active(&mut self, value: u8) -> Result<(), <I2C as ErrorType>::Error> {
549 self.i2c
550 .write(self.address, &[Reg::PeriodActive.into(), value])
551 }
552
553 pub fn set_period_monitor(&mut self, value: u8) -> Result<(), <I2C as ErrorType>::Error> {
559 self.i2c
560 .write(self.address, &[Reg::PeriodMonitor.into(), value])
561 }
562
563 pub fn set_gesture_minimum_angle(
570 &mut self,
571 value: u8,
572 ) -> Result<(), <I2C as ErrorType>::Error> {
573 self.i2c
574 .write(self.address, &[Reg::GestRadianValue.into(), value])
575 }
576
577 pub fn set_gesture_offset_left_right(
584 &mut self,
585 value: u8,
586 ) -> Result<(), <I2C as ErrorType>::Error> {
587 self.i2c
588 .write(self.address, &[Reg::GestOffsetLeftRight.into(), value])
589 }
590
591 pub fn set_gesture_offset_up_down(
598 &mut self,
599 value: u8,
600 ) -> Result<(), <I2C as ErrorType>::Error> {
601 self.i2c
602 .write(self.address, &[Reg::GestOffsetUpDown.into(), value])
603 }
604
605 pub fn set_gesture_distance_up_down(
612 &mut self,
613 value: u8,
614 ) -> Result<(), <I2C as ErrorType>::Error> {
615 self.i2c
616 .write(self.address, &[Reg::GestDistUpDown.into(), value])
617 }
618
619 pub fn set_gesture_distance_left_right(
626 &mut self,
627 value: u8,
628 ) -> Result<(), <I2C as ErrorType>::Error> {
629 self.i2c
630 .write(self.address, &[Reg::GestDistLeftRight.into(), value])
631 }
632
633 pub fn set_gesture_distance_zoom(
639 &mut self,
640 value: u8,
641 ) -> Result<(), <I2C as ErrorType>::Error> {
642 self.i2c
643 .write(self.address, &[Reg::GestDistZoom.into(), value])
644 }
645
646 pub fn get_info(&self) -> Option<Ft6x36Info> {
653 self.info
654 }
655
656 pub fn get_diagnostics(&mut self) -> Result<Diagnostics, <I2C as ErrorType>::Error> {
662 let mut buf: [u8; 1] = [0];
663 self.i2c
664 .write_read(self.address, &[Reg::PowerMode.into()], &mut buf)?;
665 let power_mode = buf[0];
666 self.i2c
667 .write_read(self.address, &[Reg::GMode.into()], &mut buf)?;
668 let g_mode = buf[0];
669 self.i2c
670 .write_read(self.address, &[Reg::OperatingMode.into()], &mut buf)?;
671 let state = buf[0];
672 self.i2c
673 .write_read(self.address, &[Reg::LibVersionH.into()], &mut buf)?;
674 let lib_version_h = buf[0];
675 self.i2c
676 .write_read(self.address, &[Reg::LibVersionL.into()], &mut buf)?;
677 let lib_version_l = buf[0];
678 let lib_version: u16 = (lib_version_h as u16) << 8 | lib_version_l as u16;
679 self.i2c
680 .write_read(self.address, &[Reg::ControlMode.into()], &mut buf)?;
681 let control_mode = buf[0];
682 Ok(Diagnostics {
683 power_mode,
684 g_mode,
685 state,
686 lib_version,
687 control_mode,
688 })
689 }
690
691 #[cfg(feature = "event_process")]
692 pub fn process_event(
693 &mut self,
694 time: core::time::Duration,
695 event: RawTouchEvent,
696 ) -> Option<TouchEvent> {
697 if event.p1.is_none() {
700 match (self.events.0.take(), self.events.1.take()) {
701 (Some(e1), Some(mut e2)) => {
702 if (e2.time - e1.time).le(&self.config.gesture_timing) {
703 (match (e1.event.p1, e2.event.p1) {
704 (Some(e1p1), Some(e2p1)) => process_swipe(e1p1, e2p1, &self.config),
705 _ => None,
706 })
707 .or_else(|| process_touch_points(e2.event.p1.take(), e2.event.p2.take()))
708 } else {
709 process_touch_points(e2.event.p1.take(), e2.event.p2.take())
710 }
711 }
712 (Some(mut e1), None) => {
713 process_touch_points(e1.event.p1.take(), e1.event.p2.take())
714 }
715 (_, _) => None,
716 }
717 } else {
718 if self.events.0.is_some() {
720 match &self.events.1 {
724 Some(old_evt1) => {
725 let time_evt1 = old_evt1.time;
726 let old_evt1 = old_evt1.event;
727 if old_evt1.p2.is_none()
728 || event.p2.is_some()
729 || (time - time_evt1) > MAX_DELTA_TOUCH_EVENT
730 {
731 self.events.1 = Some(TimedRawTouchEvent { time, event })
732 }
733 }
734 None => self.events.1 = Some(TimedRawTouchEvent { time, event }),
735 }
736 } else {
737 self.events.0 = Some(TimedRawTouchEvent { time, event });
738 }
739 None
740 }
741 }
742}
743
744#[cfg(feature = "event_process")]
745fn process_touch_points(
746 mut p1: Option<TouchPoint>,
747 mut p2: Option<TouchPoint>,
748) -> Option<TouchEvent> {
749 match (p1.take(), p2.take()) {
750 (Some(p1), Some(p2)) => Some(TouchEvent::TouchTwoPoint(p1, p2)),
751 (Some(p1), None) => Some(TouchEvent::TouchOnePoint(p1)),
752 _ => None,
753 }
754}
755
756#[cfg(feature = "event_process")]
757fn process_swipe(
758 e1p1: TouchPoint,
759 e2p1: TouchPoint,
760 config: &ProcessEventConfig,
761) -> Option<TouchEvent> {
762 let delta_x = (e1p1.x as i16 - e2p1.x as i16).unsigned_abs();
763 let delta_y = (e1p1.y as i16 - e2p1.y as i16).unsigned_abs();
764 if delta_x < config.max_swipe_delta && delta_y > config.min_swipe_delta {
765 if e1p1.y > e2p1.y {
766 Some(TouchEvent::Swipe(
767 Direction::Down,
768 SwipeInfo {
769 velocity: e1p1.y - e2p1.y,
770 point: e1p1,
771 },
772 ))
773 } else {
774 Some(TouchEvent::Swipe(
775 Direction::Up,
776 SwipeInfo {
777 velocity: e2p1.y - e1p1.y,
778 point: e1p1,
779 },
780 ))
781 }
782 } else if delta_x > config.max_swipe_delta && delta_y < config.min_swipe_delta {
783 if e1p1.x > e2p1.x {
784 Some(TouchEvent::Swipe(
785 Direction::Right,
786 SwipeInfo {
787 velocity: e1p1.x - e2p1.x,
788 point: e1p1,
789 },
790 ))
791 } else {
792 Some(TouchEvent::Swipe(
793 Direction::Left,
794 SwipeInfo {
795 velocity: e2p1.x - e1p1.x,
796 point: e1p1,
797 },
798 ))
799 }
800 } else {
801 None
802 }
803}
804
805#[cfg(test)]
806mod test {
807 use super::*;
808
809 #[test]
810 fn test_raw_event_from_report_ok() {
811 #[allow(clippy::unusual_byte_groupings)]
812 let report: [u8; REPORT_SIZE] = [
813 0x00, 0x00, 0x02, 0b10_00_0000, 0x13, 0b0000_0000, 0x14, 0x00, 0x00, 0b10_00_0000, 0x25, 0b0000_0000, 0x26, 0x00, 0x00, ];
829 let actual: RawTouchEvent = report.into();
830
831 let expected = RawTouchEvent {
832 device_mode: DeviceMode::Working,
833 gesture_id: GestureId::NoGesture,
834 p1: Some(TouchPoint {
835 touch_type: TouchType::Contact,
836 x: 0x13,
837 y: 0x14,
838 }),
839 p2: Some(TouchPoint {
840 touch_type: TouchType::Contact,
841 x: 0x25,
842 y: 0x26,
843 }),
844 };
845
846 assert_eq!(actual, expected);
847 }
848
849 #[test]
850 fn test_raw_event_from_report_ok_high_value() {
851 #[allow(clippy::unusual_byte_groupings)]
852 let report: [u8; REPORT_SIZE] = [
853 0x00, 0x00, 0x02, 0b10_00_0001, 0x13, 0b0000_0010, 0x14, 0x00, 0x00, 0b10_00_0100, 0x25, 0b0000_1000, 0x26, 0x00, 0x00, ];
869 let actual: RawTouchEvent = report.into();
870
871 let expected = RawTouchEvent {
872 device_mode: DeviceMode::Working,
873 gesture_id: GestureId::NoGesture,
874 p1: Some(TouchPoint {
875 touch_type: TouchType::Contact,
876 x: 0x0113,
877 y: 0x0214,
878 }),
879 p2: Some(TouchPoint {
880 touch_type: TouchType::Contact,
881 x: 0x0425,
882 y: 0x0826,
883 }),
884 };
885
886 assert_eq!(actual, expected);
887 }
888
889 #[test]
890 fn test_process_swipe_right_ok() {
891 let p1 = TouchPoint {
892 x: 340,
893 y: 200,
894 touch_type: TouchType::Contact,
895 };
896 let p2 = TouchPoint {
897 x: 25,
898 y: 203,
899 touch_type: TouchType::Contact,
900 };
901 let actual = process_swipe(p1, p2, &ProcessEventConfig::default());
902 assert!(actual.is_some());
903 let actual = actual.unwrap();
904
905 let expected = TouchEvent::Swipe(
906 Direction::Right,
907 SwipeInfo {
908 velocity: 315,
909 point: TouchPoint {
910 x: 340,
911 y: 200,
912 touch_type: TouchType::Contact,
913 },
914 },
915 );
916
917 assert_eq!(actual, expected);
918 }
919
920 #[test]
921 fn test_process_swipe_left_ok() {
922 let p1 = TouchPoint {
923 x: 231,
924 y: 200,
925 touch_type: TouchType::Contact,
926 };
927 let p2 = TouchPoint {
928 x: 334,
929 y: 197,
930 touch_type: TouchType::Contact,
931 };
932 let actual = process_swipe(p1, p2, &ProcessEventConfig::default());
933 assert!(actual.is_some());
934 let actual = actual.unwrap();
935
936 let expected = TouchEvent::Swipe(
937 Direction::Left,
938 SwipeInfo {
939 velocity: 103,
940 point: TouchPoint {
941 x: 231,
942 y: 200,
943 touch_type: TouchType::Contact,
944 },
945 },
946 );
947
948 assert_eq!(actual, expected);
949 }
950
951 #[test]
952 fn test_process_swipe_up_ok() {
953 let p1 = TouchPoint {
954 x: 231,
955 y: 200,
956 touch_type: TouchType::Contact,
957 };
958 let p2 = TouchPoint {
959 x: 234,
960 y: 302,
961 touch_type: TouchType::Contact,
962 };
963 let actual = process_swipe(p1, p2, &ProcessEventConfig::default());
964 assert!(actual.is_some());
965 let actual = actual.unwrap();
966
967 let expected = TouchEvent::Swipe(
968 Direction::Up,
969 SwipeInfo {
970 velocity: 102,
971 point: TouchPoint {
972 x: 231,
973 y: 200,
974 touch_type: TouchType::Contact,
975 },
976 },
977 );
978
979 assert_eq!(actual, expected);
980 }
981
982 #[test]
983 fn test_process_swipe_down_ok() {
984 let p1 = TouchPoint {
985 x: 231,
986 y: 200,
987 touch_type: TouchType::Contact,
988 };
989 let p2 = TouchPoint {
990 x: 225,
991 y: 25,
992 touch_type: TouchType::Contact,
993 };
994 let actual = process_swipe(p1, p2, &ProcessEventConfig::default());
995 assert!(actual.is_some());
996 let actual = actual.unwrap();
997
998 let expected = TouchEvent::Swipe(
999 Direction::Down,
1000 SwipeInfo {
1001 velocity: 175,
1002 point: TouchPoint {
1003 x: 231,
1004 y: 200,
1005 touch_type: TouchType::Contact,
1006 },
1007 },
1008 );
1009
1010 assert_eq!(actual, expected);
1011 }
1012}