1 use {Event, Input, Motion}; 2 3 /// Stores the touch state. 4 #[derive(Copy, Clone, Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] 5 pub enum Touch { 6 /// The start of touch, for example 7 /// a finger pressed down on a touch screen. 8 Start, 9 /// The move of touch, for example 10 /// a finger moving while touching a touch screen. 11 Move, 12 /// The end of touch, for example 13 /// taking a finger away from a touch screen. 14 End, 15 /// The cancel of touch, for example 16 /// the window loses focus. 17 Cancel, 18 } 19 20 /// Touch arguments 21 /// 22 /// The `id` might be reused for different touches that do not overlap in time. 23 /// 24 /// - Coordinates are normalized to support both touch screens and trackpads 25 /// - Supports both 2D and 3D touch 26 /// - The pressure direction vector should have maximum length 1 27 /// 28 /// For 2D touch the pressure is pointed in the z direction. 29 /// Use `.pressure()` to get the pressure magnitude. 30 #[derive(Copy, Clone, Deserialize, Serialize, PartialEq, PartialOrd, Debug)] 31 pub struct TouchArgs { 32 /// A unique identifier for touch device. 33 pub device: i64, 34 /// A unique identifier for touch event. 35 pub id: i64, 36 /// The touch position, normalized 0..1. 37 pub position_3d: [f64; 3], 38 /// The touch pressure vector, normalized 0..1. 39 pub pressure_3d: [f64; 3], 40 /// Whether the touch is in 3D. 41 pub is_3d: bool, 42 /// The touch state. 43 pub touch: Touch, 44 } 45 46 impl TouchArgs { 47 /// Creates arguments for 2D touch. new(device: i64, id: i64, position: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs48 pub fn new(device: i64, id: i64, position: [f64; 2], pressure: f64, touch: Touch) -> TouchArgs { 49 TouchArgs { 50 device: device, 51 id: id, 52 position_3d: [position[0], position[1], 0.0], 53 pressure_3d: [0.0, 0.0, pressure], 54 is_3d: false, 55 touch: touch, 56 } 57 } 58 59 /// Creates arguments for 3D touch. 60 /// 61 /// The pressure direction vector should have maximum length 1. new_3d(device: i64, id: i64, position_3d: [f64; 3], pressure_3d: [f64; 3], touch: Touch) -> TouchArgs62 pub fn new_3d(device: i64, 63 id: i64, 64 position_3d: [f64; 3], 65 pressure_3d: [f64; 3], 66 touch: Touch) 67 -> TouchArgs { 68 TouchArgs { 69 device: device, 70 id: id, 71 position_3d, 72 pressure_3d, 73 is_3d: true, 74 touch: touch, 75 } 76 } 77 78 /// The position of the touch in 2D. position(&self) -> [f64; 2]79 pub fn position(&self) -> [f64; 2] { 80 [self.position_3d[0], self.position_3d[1]] 81 } 82 83 /// The position of the touch in 3D. position_3d(&self) -> [f64; 3]84 pub fn position_3d(&self) -> [f64; 3] {self.position_3d} 85 86 /// The pressure magnitude, normalized 0..1. pressure(&self) -> f6487 pub fn pressure(&self) -> f64 { 88 let px = self.pressure_3d[0]; 89 let py = self.pressure_3d[1]; 90 let pz = self.pressure_3d[2]; 91 (px * px + py * py + pz * pz).sqrt() 92 } 93 94 /// The pressure vector in 3D. pressure_3d(&self) -> [f64; 3]95 pub fn pressure_3d(&self) -> [f64; 3] {self.pressure_3d} 96 } 97 98 /// When a touch is started, moved, ended or cancelled. 99 pub trait TouchEvent: Sized { 100 /// Creates a touch event. 101 /// 102 /// Preserves time stamp from original input event, if any. from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>103 fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>; 104 /// Calls closure if this is a touch event. touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U105 fn touch<U, F>(&self, f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U; 106 /// Returns touch arguments. touch_args(&self) -> Option<TouchArgs>107 fn touch_args(&self) -> Option<TouchArgs> { 108 self.touch(|args| args.clone()) 109 } 110 } 111 112 impl TouchEvent for Event { from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self>113 fn from_touch_args(args: &TouchArgs, old_event: &Self) -> Option<Self> { 114 let timestamp = if let Event::Input(_, x) = old_event {*x} else {None}; 115 Some(Event::Input(Input::Move(Motion::Touch(*args)), timestamp)) 116 } 117 touch<U, F>(&self, mut f: F) -> Option<U> where F: FnMut(&TouchArgs) -> U118 fn touch<U, F>(&self, mut f: F) -> Option<U> 119 where F: FnMut(&TouchArgs) -> U 120 { 121 match *self { 122 Event::Input(Input::Move(Motion::Touch(ref args)), _) => Some(f(args)), 123 _ => None, 124 } 125 } 126 } 127 128 #[cfg(test)] 129 mod tests { 130 use super::*; 131 132 #[test] test_input_touch()133 fn test_input_touch() { 134 let pos = [0.0; 2]; 135 let e: Event = TouchArgs::new(0, 0, pos, 1.0, Touch::Start).into(); 136 let a: Option<Event> = 137 TouchEvent::from_touch_args(&TouchArgs::new(0, 0, pos, 1.0, Touch::Start), &e); 138 let b: Option<Event> = a.clone() 139 .unwrap() 140 .touch(|t| { 141 TouchEvent::from_touch_args(&TouchArgs::new(t.device, 142 t.id, 143 t.position(), 144 t.pressure(), 145 Touch::Start), 146 a.as_ref().unwrap()) 147 }) 148 .unwrap(); 149 assert_eq!(a, b); 150 } 151 152 #[test] test_input_touch_3d()153 fn test_input_touch_3d() { 154 use super::super::Event; 155 156 let pos = [0.0; 3]; 157 let pressure = [0.0, 0.0, 1.0]; 158 let e: Event = TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start).into(); 159 let a: Option<Event> = 160 TouchEvent::from_touch_args(&TouchArgs::new_3d(0, 0, pos, pressure, Touch::Start), &e); 161 let b: Option<Event> = a.clone() 162 .unwrap() 163 .touch(|t| { 164 TouchEvent::from_touch_args(&TouchArgs::new_3d(t.device, 165 t.id, 166 t.position_3d(), 167 t.pressure_3d(), 168 Touch::Start), 169 a.as_ref().unwrap()) 170 }) 171 .unwrap(); 172 assert_eq!(a, b); 173 } 174 } 175