1use enumflags2::{bitflags, BitFlags};
2use thiserror::Error;
3use windows::Win32::{
4 Foundation::{GetLastError, POINT, RECT},
5 UI::{
6 Controls::{
7 CreateSyntheticPointerDevice, DestroySyntheticPointerDevice, HSYNTHETICPOINTERDEVICE,
8 POINTER_FEEDBACK_INDIRECT, POINTER_TYPE_INFO,
9 },
10 Input::Pointer::{
11 InitializeTouchInjection, InjectSyntheticPointerInput, POINTER_FLAG_DOWN,
12 POINTER_FLAG_FIRSTBUTTON, POINTER_FLAG_HASTRANSFORM, POINTER_FLAG_INCONTACT,
13 POINTER_FLAG_INRANGE, POINTER_FLAG_NEW, POINTER_FLAG_NONE, POINTER_FLAG_PRIMARY,
14 POINTER_FLAG_UP, POINTER_FLAG_UPDATE, POINTER_INFO, POINTER_PEN_INFO,
15 POINTER_TOUCH_INFO, TOUCH_FEEDBACK_DEFAULT,
16 },
17 WindowsAndMessaging::POINTER_INPUT_TYPE,
18 },
19};
20
21const MAX_POINTERS: u32 = 10;
22const MAX_POINTERS_USIZE: usize = 10;
23
24pub struct SyntheticPointer {
25 pub pointer_type: PointerType,
26 pub pointer_count: u32,
27 pointer_type_info: [POINTER_TYPE_INFO; MAX_POINTERS_USIZE],
28 synthetic_pointer_device: HSYNTHETICPOINTERDEVICE,
29 last_contact: [bool; MAX_POINTERS_USIZE],
30}
31
32impl SyntheticPointer {
33 pub fn new(
36 pointer_type: PointerType,
37 pointer_count: u32,
38 ) -> Result<Self, SyntheticPointerError> {
39 if pointer_count == 0 || pointer_count > MAX_POINTERS {
40 return Err(SyntheticPointerError::InvalidPointerCount {
41 count: pointer_count,
42 });
43 }
44
45 match pointer_type {
46 PointerType::Pointer => return Err(SyntheticPointerError::InvalidPointerType),
47 PointerType::Touchpad => {
48 }
50 _ => {}
51 }
52
53 let pointer_input_type = POINTER_INPUT_TYPE(pointer_type.get_value());
54
55 if let PointerType::Touch(_) = pointer_type {
56 unsafe {
57 if (!InitializeTouchInjection(pointer_count, TOUCH_FEEDBACK_DEFAULT)).into() {
58 return Err(SyntheticPointerError::InputInjectionError(
59 GetLastError().into(),
60 ));
61 }
62 }
63 }
64
65 let device = unsafe {
66 CreateSyntheticPointerDevice(
67 pointer_input_type,
68 pointer_count,
69 POINTER_FEEDBACK_INDIRECT,
70 )
71 }?;
72
73 let mut s = Self {
74 pointer_type,
75 pointer_count,
76 synthetic_pointer_device: device,
77
78 pointer_type_info: [POINTER_TYPE_INFO::default(); MAX_POINTERS_USIZE],
80 last_contact: [false; MAX_POINTERS_USIZE],
81 };
82
83 match pointer_type {
86 PointerType::Touch(properties) => {
87 for i in 0..pointer_count as usize {
88 let mut touch_info = POINTER_TOUCH_INFO {
89 pointerInfo: POINTER_INFO::default(),
90 ..Default::default()
91 };
92
93 touch_info.pointerInfo.pointerType = pointer_input_type;
94 touch_info.pointerInfo.pointerId = i as u32 + 1;
95 touch_info.pointerInfo.pointerFlags = POINTER_FLAG_NEW;
96 touch_info.touchMask = properties.bits();
97
98 s.pointer_type_info[i].r#type = pointer_input_type;
99 s.pointer_type_info[i].Anonymous.touchInfo = touch_info;
100 }
101 }
102 PointerType::Pen(properties) => {
103 let mut pen_info = POINTER_PEN_INFO {
104 pointerInfo: POINTER_INFO::default(),
105 ..Default::default()
106 };
107
108 pen_info.pointerInfo.pointerType = pointer_input_type;
109 pen_info.pointerInfo.pointerFlags = POINTER_FLAG_NEW;
110 pen_info.penMask = properties.bits();
111
112 s.pointer_type_info[0].r#type = pointer_input_type;
113 s.pointer_type_info[0].Anonymous.penInfo = pen_info;
114 }
115
116 _ => {
117 todo!()
118 }
119 }
120
121 s.inject()?;
123
124 Ok(s)
125 }
126
127 pub fn pen_input(&mut self, input: &Option<PenInput>) -> Result<(), SyntheticPointerError> {
131 match self.pointer_type {
132 PointerType::Pen(_) => {
133 }
135 _ => {
136 return Err(SyntheticPointerError::InvalidPointerType);
137 }
138 }
139
140 let union = &mut self.pointer_type_info[0].Anonymous;
141
142 if let Some(data) = input {
144 let mut flags = POINTER_FLAG_INRANGE
145 | POINTER_FLAG_HASTRANSFORM
146 | POINTER_FLAG_PRIMARY
147 | POINTER_FLAG_UPDATE;
148
149 union.penInfo.pointerInfo.ptPixelLocation = POINT {
152 x: data.x,
153 y: data.y,
154 };
155
156 if let Some(tilt_x) = data.tilt_x {
157 union.penInfo.tiltX = tilt_x;
158 }
159
160 if let Some(tilt_y) = data.tilt_y {
161 union.penInfo.tiltY = tilt_y;
162 }
163
164 if let Some(rotation) = data.rotation {
165 union.penInfo.rotation = rotation;
166 }
167
168 union.penInfo.pressure = data.pressure;
169 let contact = data.pressure > 0;
170
171 if contact && !self.last_contact[0] {
172 flags |= POINTER_FLAG_DOWN;
173 } else if !contact && self.last_contact[0] {
174 flags |= POINTER_FLAG_UP;
175 }
176
177 if data.bind_active && contact {
178 flags |= POINTER_FLAG_INCONTACT | POINTER_FLAG_FIRSTBUTTON;
179 }
180
181 union.penInfo.pointerInfo.pointerFlags = flags;
182 self.last_contact[0] = data.pressure > 0;
183 } else {
184 union.penInfo.pointerInfo.pointerFlags = POINTER_FLAG_NONE;
186 self.last_contact[0] = false;
187 }
188
189 Ok(())
190 }
191
192 pub fn touch_input(
197 &mut self,
198 input: &[Option<TouchInput>; MAX_POINTERS_USIZE],
199 ) -> Result<(), SyntheticPointerError> {
200 match self.pointer_type {
201 PointerType::Touch(_) => {
202 }
204 _ => {
205 return Err(SyntheticPointerError::InvalidPointerType);
206 }
207 }
208
209 for (i, pt_info) in self.pointer_type_info[0..self.pointer_count as usize]
210 .iter_mut()
211 .enumerate()
212 {
213 let union = &mut pt_info.Anonymous;
214
215 if let Some(data) = &input[i] {
217 let mut flags =
218 POINTER_FLAG_INRANGE | POINTER_FLAG_HASTRANSFORM | POINTER_FLAG_UPDATE;
219
220 if i == 0 {
222 flags |= POINTER_FLAG_PRIMARY;
223 }
224
225 union.touchInfo.pointerInfo.ptPixelLocation = POINT {
227 x: data.x,
228 y: data.y,
229 };
230
231 if let Some(area) = data.contact_area {
232 union.touchInfo.rcContact = RECT {
233 top: area.top,
234 bottom: area.bottom,
235 left: area.left,
236 right: area.right,
237 };
238 }
239
240 if let Some(orientation) = data.orientation {
241 union.touchInfo.orientation = orientation;
242 }
243
244 union.touchInfo.pressure = data.pressure;
245 let contact = data.pressure > 0;
246
247 if contact && !self.last_contact[i] {
248 flags |= POINTER_FLAG_DOWN;
249 } else if !contact && self.last_contact[i] {
250 flags |= POINTER_FLAG_UP;
251 }
252
253 if data.bind_active && contact {
254 flags |= POINTER_FLAG_INCONTACT | POINTER_FLAG_FIRSTBUTTON;
255 }
256
257 union.touchInfo.pointerInfo.pointerFlags = flags;
258 self.last_contact[i] = data.pressure > 0;
259 } else {
260 union.touchInfo.pointerInfo.pointerFlags = POINTER_FLAG_NONE;
262 self.last_contact[i] = false;
263 }
264 }
265
266 Ok(())
267 }
268
269 pub fn inject(&mut self) -> Result<(), SyntheticPointerError> {
271 unsafe {
272 if (!InjectSyntheticPointerInput(
273 self.synthetic_pointer_device,
274 &self.pointer_type_info[0..self.pointer_count as usize],
275 ))
276 .into()
277 {
278 return Err(SyntheticPointerError::InputInjectionError(
279 GetLastError().into(),
280 ));
281 }
282 }
283 Ok(())
284 }
285}
286
287#[derive(Copy, Clone, Debug, PartialEq)]
288pub struct PenInput {
289 pub x: i32,
291 pub y: i32,
293 pub pressure: u32,
295 pub tilt_x: Option<i32>,
297 pub tilt_y: Option<i32>,
299 pub rotation: Option<u32>,
301 pub bind_active: bool,
303}
304
305#[derive(Copy, Clone, Debug, PartialEq)]
306pub struct TouchInput {
307 pub x: i32,
309 pub y: i32,
311 pub pressure: u32,
313 pub orientation: Option<u32>,
315 pub contact_area: Option<Rectangle>,
318 pub bind_active: bool,
320}
321
322#[derive(Copy, Clone, Debug, PartialEq)]
323pub struct Rectangle {
324 top: i32,
325 bottom: i32,
326 left: i32,
327 right: i32,
328}
329
330#[bitflags]
331#[repr(u32)]
332#[derive(Copy, Clone, Debug, PartialEq)]
333pub enum PenProperties {
334 TiltX = 4,
335 TiltY = 8,
336 Pressure = 1,
337 Rotation = 2,
338}
339
340#[bitflags]
341#[repr(u32)]
342#[derive(Copy, Clone, Debug, PartialEq)]
343pub enum TouchProperties {
344 Pressure = 4,
345 ContactArea = 1,
346 Orientation = 2,
347}
348
349impl Drop for SyntheticPointer {
350 fn drop(&mut self) {
351 unsafe { DestroySyntheticPointerDevice(self.synthetic_pointer_device) };
352 }
353}
354
355#[derive(Debug, PartialEq, Copy, Clone)]
356pub enum PointerType {
357 Pointer,
360 Touch(BitFlags<TouchProperties>),
361 Pen(BitFlags<PenProperties>),
362 Mouse,
363
364 Touchpad,
366}
367
368impl PointerType {
369 pub fn get_value(&self) -> i32 {
370 match self {
371 PointerType::Pointer => 1,
372 PointerType::Touch(_) => 2,
373 PointerType::Pen(_) => 3,
374 PointerType::Mouse => 4,
375 PointerType::Touchpad => 5,
376 }
377 }
378}
379
380#[derive(Error, Debug)]
381pub enum SyntheticPointerError {
382 #[error("The selected pointer type is invalid or not supported on the current OS version.")]
383 InvalidPointerType,
384
385 #[error("The number of pointers must be between 0 and {MAX_POINTERS}, but it was {count}.")]
386 InvalidPointerCount { count: u32 },
387
388 #[error("Failed to inject input.")]
389 InputInjectionError(#[from] windows::core::Error),
390}