diff --git a/lib/linux/uinput.c b/lib/linux/uinput.c index f4346c41..d20bda4c 100644 --- a/lib/linux/uinput.c +++ b/lib/linux/uinput.c @@ -13,10 +13,14 @@ #include "error.h" -void setup_abs(int fd, int code, int minimum, int maximum, Error* err) +#define ABS_MAXVAL 65535 + +void setup_abs(int fd, int code, int minimum, int maximum, int resolution, Error* err) { - struct uinput_abs_setup abs_setup; + if (ioctl(fd, UI_SET_ABSBIT, code) < 0) + ERROR(err, 1, "error: ioctl UI_SET_ABSBIT, code %#x", code); + struct uinput_abs_setup abs_setup; memset(&abs_setup, 0, sizeof(abs_setup)); abs_setup.code = code; abs_setup.absinfo.value = 0; @@ -25,9 +29,9 @@ void setup_abs(int fd, int code, int minimum, int maximum, Error* err) abs_setup.absinfo.fuzz = 0; abs_setup.absinfo.flat = 0; // units/mm - abs_setup.absinfo.resolution = 12; + abs_setup.absinfo.resolution = resolution; if (ioctl(fd, UI_ABS_SETUP, &abs_setup) < 0) - ERROR(err, 1, "error: UI_ABS_SETUP, code: %x", code); + ERROR(err, 1, "error: UI_ABS_SETUP, code: %#x", code); } void setup(int fd, const char* name, int product, Error* err) @@ -37,53 +41,78 @@ void setup(int fd, const char* name, int product, Error* err) memset(&setup, 0, sizeof(setup)); strncpy(setup.name, name, UINPUT_MAX_NAME_SIZE - 1); setup.id.bustype = BUS_VIRTUAL; - setup.id.vendor = 0x1; + setup.id.vendor = 0x01; setup.id.product = product; - setup.id.version = 1; + setup.id.version = 0x01; setup.ff_effects_max = 0; if (ioctl(fd, UI_DEV_SETUP, &setup) < 0) ERROR(err, 1, "error: UI_DEV_SETUP"); } -void init_pointer(int fd, Error* err) + +void init_mouse(int fd, Error* err) { // enable synchronization if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_SYN"); - // enable 1 button + // enable buttons if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_KEY"); if (ioctl(fd, UI_SET_KEYBIT, BTN_LEFT) < 0) - ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); - if (ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH) < 0) - ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); + ERROR(err, 1, "error: ioctl UI_SET_KEYBIT BTN_STYLUS"); + + // setup sending timestamps + if (ioctl(fd, UI_SET_EVBIT, EV_MSC) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_MSC"); + if (ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP) < 0) + ERROR(err, 1, "error: ioctl UI_SET_MSCBIT MSC_TIMESTAMP"); + + if (ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_ABS"); + + setup_abs(fd, ABS_X, 0, ABS_MAXVAL, 0, err); + OK_OR_ABORT(err); + setup_abs(fd, ABS_Y, 0, ABS_MAXVAL, 0, err); + OK_OR_ABORT(err); + + setup(fd, "Weylus Mouse", 1, err); + OK_OR_ABORT(err); + + if (ioctl(fd, UI_DEV_CREATE) < 0) + ERROR(err, 1, "error: ioctl"); +} + +void init_stylus(int fd, Error* err) +{ + // enable synchronization + if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_SYN"); + + // enable buttons + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_KEY"); if (ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_PEN) < 0) - ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); - if (ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS) < 0) - ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); - if (ioctl(fd, UI_SET_KEYBIT, BTN_STYLUS2) < 0) - ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); + ERROR(err, 1, "error: ioctl UI_SET_KEYBIT BTN_TOOL_PEN"); + + // setup sending timestamps + if (ioctl(fd, UI_SET_EVBIT, EV_MSC) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_MSC"); + if (ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP) < 0) + ERROR(err, 1, "error: ioctl UI_SET_MSCBIT MSC_TIMESTAMP"); - // enable 2 main axes + pressure (absolute positioning) if (ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_ABS"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_X) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_X"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_Y"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_PRESSURE) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_PRESSURE"); - setup_abs(fd, ABS_X, 0, UINT16_MAX, err); + setup_abs(fd, ABS_X, 0, ABS_MAXVAL, 12, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_Y, 0, UINT16_MAX, err); + setup_abs(fd, ABS_Y, 0, ABS_MAXVAL, 12, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_PRESSURE, 0, UINT16_MAX, err); + setup_abs(fd, ABS_PRESSURE, 0, ABS_MAXVAL, 12, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_TILT_X, -90, 90, err); + setup_abs(fd, ABS_TILT_X, -90, 90, 12, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_TILT_Y, -90, 90, err); + setup_abs(fd, ABS_TILT_Y, -90, 90, 12, err); OK_OR_ABORT(err); setup(fd, "Weylus", 1, err); @@ -93,12 +122,15 @@ void init_pointer(int fd, Error* err) ERROR(err, 1, "error: ioctl"); } -void init_multitouch(int fd, Error* err) +void init_touch(int fd, Error* err) { // enable synchronization if (ioctl(fd, UI_SET_EVBIT, EV_SYN) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_SYN"); + if (ioctl(fd, UI_SET_PROPBIT, INPUT_PROP_DIRECT) < 0) + ERROR(err, 1, "error: ioctl UI_SET_PROPBIT INPUT_PROP_DIRECT"); + if (ioctl(fd, UI_SET_EVBIT, EV_KEY) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_KEY"); if (ioctl(fd, UI_SET_KEYBIT, BTN_TOUCH) < 0) @@ -114,78 +146,82 @@ void init_multitouch(int fd, Error* err) if (ioctl(fd, UI_SET_KEYBIT, BTN_TOOL_QUINTTAP) < 0) ERROR(err, 1, "error: ioctl UI_SET_KEYBIT"); + // setup sending timestamps + if (ioctl(fd, UI_SET_EVBIT, EV_MSC) < 0) + ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_MSC"); + if (ioctl(fd, UI_SET_MSCBIT, MSC_TIMESTAMP) < 0) + ERROR(err, 1, "error: ioctl UI_SET_MSCBIT MSC_TIMESTAMP"); + if (ioctl(fd, UI_SET_EVBIT, EV_ABS) < 0) ERROR(err, 1, "error: ioctl UI_SET_EVBIT EV_ABS"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_X) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_X"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_Y) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_Y"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_SLOT) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_SLOT"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_TRACKING_ID) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_TRACKING_ID"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_X) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_POSITION_X"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_POSITION_Y) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_POSITION_Y"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_PRESSURE) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_PRESSURE"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MAJOR) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_TOUCH_MAJOR"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_TOUCH_MINOR) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_TOUCH_MINOR"); - if (ioctl(fd, UI_SET_ABSBIT, ABS_MT_ORIENTATION) < 0) - ERROR(err, 1, "error: ioctl UI_SETEVBIT ABS_MT_ORIENTATION"); + setup_abs(fd, ABS_X, 0, ABS_MAXVAL, 200, err); + OK_OR_ABORT(err); + setup_abs(fd, ABS_Y, 0, ABS_MAXVAL, 200, err); + OK_OR_ABORT(err); // 5 fingers 5 multitouch slots. - setup_abs(fd, ABS_MT_SLOT, 0, 4, err); + setup_abs(fd, ABS_MT_SLOT, 0, 4, 0, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_TRACKING_ID, 0, 4, err); + setup_abs(fd, ABS_MT_TRACKING_ID, 0, 4, 0, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_POSITION_X, 0, UINT16_MAX, err); + setup_abs(fd, ABS_MT_POSITION_X, 0, ABS_MAXVAL, 200, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_POSITION_Y, 0, UINT16_MAX, err); + setup_abs(fd, ABS_MT_POSITION_Y, 0, ABS_MAXVAL, 200, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_PRESSURE, 0, UINT16_MAX, err); + setup_abs(fd, ABS_MT_PRESSURE, 0, ABS_MAXVAL, 0, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_TOUCH_MAJOR, 0, UINT16_MAX, err); + setup_abs(fd, ABS_MT_TOUCH_MAJOR, 0, ABS_MAXVAL, 12, err); OK_OR_ABORT(err); - setup_abs(fd, ABS_MT_TOUCH_MINOR, 0, UINT16_MAX, err); + setup_abs(fd, ABS_MT_TOUCH_MINOR, 0, ABS_MAXVAL, 12, err); OK_OR_ABORT(err); // PointerEvent only gives partial orientation of the touch ellipse - setup_abs(fd, ABS_MT_ORIENTATION, 0, 1, err); + setup_abs(fd, ABS_MT_ORIENTATION, 0, 1, 0, err); OK_OR_ABORT(err); - setup(fd, "WeylusMultiTouch", 2, err); + setup(fd, "Weylus Touch", 2, err); OK_OR_ABORT(err); if (ioctl(fd, UI_DEV_CREATE) < 0) ERROR(err, 1, "error: ioctl"); } -int init_uinput_pointer(Error* err) +int init_uinput_stylus(Error* err) +{ + int device; + + if ((device = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0) + fill_error(err, 1, "error: failed to open /dev/uinput"); + else + { + init_stylus(device, err); + } + return device; +} + + +int init_uinput_mouse(Error* err) { int device; if ((device = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0) - fill_error(err, 1, "error: open"); + fill_error(err, 1, "error: failed to open /dev/uinput"); else { - init_pointer(device, err); + init_mouse(device, err); } return device; } -int init_uinput_multitouch(Error* err) +int init_uinput_touch(Error* err) { int device; if ((device = open("/dev/uinput", O_WRONLY | O_NONBLOCK)) < 0) - fill_error(err, 1, "error: open"); + fill_error(err, 1, "error: failed to open /dev/uinput"); else { - init_multitouch(device, err); + init_touch(device, err); } return device; } diff --git a/lib/linux/uinput_info.md b/lib/linux/uinput_info.md new file mode 100644 index 00000000..48b97c0a --- /dev/null +++ b/lib/linux/uinput_info.md @@ -0,0 +1,14 @@ +# Some References on how to develop things using uinput + +- uinput: https://www.kernel.org/doc/html/latest/input/uinput.html +- event codes: https://www.kernel.org/doc/html/latest/input/event-codes.html +- multi-touch protocol: https://www.kernel.org/doc/html/latest/input/multi-touch-protocol.html + +## Other projects using uinput +- https://github.com/rfc2822/GfxTablet +- https://github.com/bsteinsbo/rpi_touch_driver + +## Debugging +- libinput debug-events +- evtest + diff --git a/src/input/pointer.rs b/src/input/device.rs similarity index 77% rename from src/input/pointer.rs rename to src/input/device.rs index 01f51053..568b8120 100644 --- a/src/input/pointer.rs +++ b/src/input/device.rs @@ -1,5 +1,5 @@ use crate::protocol::PointerEvent; -pub trait PointerDevice { +pub trait InputDevice { fn send_event(&mut self, event: &PointerEvent); } diff --git a/src/input/mod.rs b/src/input/mod.rs index 2d73dd48..a0cf21db 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1,4 +1,4 @@ -pub mod pointer; +pub mod device; pub mod mouse_device; #[cfg(target_os = "linux")] diff --git a/src/input/mouse_device.rs b/src/input/mouse_device.rs index faec52cd..8ce7a27b 100644 --- a/src/input/mouse_device.rs +++ b/src/input/mouse_device.rs @@ -3,7 +3,7 @@ use autopilot::screen::size as screen_size; use tracing::warn; -use crate::input::pointer::PointerDevice; +use crate::input::device::InputDevice; use crate::protocol::Button; use crate::protocol::PointerEvent; use crate::protocol::PointerEventType; @@ -33,7 +33,7 @@ impl Mouse { } } -impl PointerDevice for Mouse { +impl InputDevice for Mouse { fn send_event(&mut self, event: &PointerEvent) { if !event.is_primary { return; diff --git a/src/input/uinput_device.rs b/src/input/uinput_device.rs index 4a0f4373..1203d9c9 100644 --- a/src/input/uinput_device.rs +++ b/src/input/uinput_device.rs @@ -1,6 +1,7 @@ use std::os::raw::c_int; -use crate::input::pointer::PointerDevice; +use crate::input::device::InputDevice; +use crate::protocol::Button; use crate::protocol::PointerEvent; use crate::protocol::PointerEventType; use crate::protocol::PointerType; @@ -11,20 +12,22 @@ use crate::cerror::CError; use tracing::warn; extern "C" { - fn init_uinput_pointer(err: *mut CError) -> c_int; -// fn init_uinput_multitouch(err: *mut CError) -> c_int; + fn init_uinput_stylus(err: *mut CError) -> c_int; + fn init_uinput_mouse(err: *mut CError) -> c_int; + fn init_uinput_touch(err: *mut CError) -> c_int; fn destroy_uinput_device(fd: c_int); fn send_uinput_event(device: c_int, typ: c_int, code: c_int, value: c_int, err: *mut CError); } -/*struct MultiTouch { +struct MultiTouch { id: i64, -}*/ +} pub struct GraphicTablet { - pointer_fd: c_int, -// multitouch_fd: c_int, -// multi_touches: [Option; 5], + stylus_fd: c_int, + mouse_fd: c_int, + touch_fd: c_int, + touches: [Option; 5], winfo: WindowInfo, x: f64, y: f64, @@ -35,18 +38,26 @@ pub struct GraphicTablet { impl GraphicTablet { pub fn new(winfo: WindowInfo) -> Result { let mut err = CError::new(); - let pointer_fd = unsafe { init_uinput_pointer(&mut err) }; + let stylus_fd = unsafe { init_uinput_stylus(&mut err) }; + if err.is_err() { + return Err(err); + } + let mouse_fd = unsafe { init_uinput_mouse(&mut err) }; if err.is_err() { + unsafe { destroy_uinput_device(stylus_fd) }; return Err(err); } - /*let multitouch_fd = unsafe { init_uinput_multitouch(&mut err) }; + let touch_fd = unsafe { init_uinput_touch(&mut err) }; if err.is_err() { + unsafe { destroy_uinput_device(stylus_fd) }; + unsafe { destroy_uinput_device(mouse_fd) }; return Err(err); - }*/ + } let tblt = Self { - pointer_fd: pointer_fd, -// multitouch_fd: 0, // multitouch_fd, -// multi_touches: Default::default(), + stylus_fd: stylus_fd, + mouse_fd: mouse_fd, + touch_fd: touch_fd, + touches: Default::default(), winfo: winfo, x: 0.0, y: 0.0, @@ -57,25 +68,25 @@ impl GraphicTablet { } fn transform_x(&self, x: f64) -> i32 { - let x = (x * self.width + self.x) * 65535.0; + let x = (x * self.width + self.x) * ABS_MAX; x as i32 } fn transform_y(&self, y: f64) -> i32 { - let y = (y * self.height + self.y) * 65535.0; + let y = (y * self.height + self.y) * ABS_MAX; y as i32 } fn transform_pressure(&self, p: f64) -> i32 { - (p * 65535.0) as i32 + (p * ABS_MAX) as i32 } - /*fn transform_touch_size(&self, s: f64) -> i32 { - (s * 65535.0) as i32 + fn transform_touch_size(&self, s: f64) -> i32 { + (s * ABS_MAX) as i32 } fn find_slot(&self, id: i64) -> Option { - self.multi_touches + self.touches .iter() .enumerate() .find_map(|(slot, mt)| match mt { @@ -88,34 +99,25 @@ impl GraphicTablet { } _ => None, }) - }*/ - - fn send(&self, typ: c_int, code: c_int, value: c_int) { - let mut err = CError::new(); - unsafe { - send_uinput_event(self.pointer_fd, typ, code, value, &mut err); - } - if err.is_err() { - warn!("{}", err); - } } - /*fn send_touch(&self, typ: c_int, code: c_int, value: c_int) { + fn send(&self, fd: c_int, typ: c_int, code: c_int, value: c_int) { let mut err = CError::new(); unsafe { - send_uinput_event(self.multitouch_fd, typ, code, value, &mut err); + send_uinput_event(fd, typ, code, value, &mut err); } if err.is_err() { warn!("{}", err); } - }*/ + } } impl Drop for GraphicTablet { fn drop(&mut self) { unsafe { - destroy_uinput_device(self.pointer_fd); - // destroy_uinput_device(self.multitouch_fd); + destroy_uinput_device(self.stylus_fd); + destroy_uinput_device(self.mouse_fd); + destroy_uinput_device(self.touch_fd); }; } } @@ -125,21 +127,21 @@ const ET_SYNC: c_int = 0x00; const ET_KEY: c_int = 0x01; //const ET_RELATIVE: c_int = 0x02; const ET_ABSOLUTE: c_int = 0x03; +const ET_MSC: c_int = 0x04; // Event Codes -const EC_SYNC_REPORT: c_int = 1; -//const EC_SYNC_MT_REPORT: c_int = 2; +const EC_SYNC_REPORT: c_int = 0; const EC_KEY_MOUSE_LEFT: c_int = 0x110; +const EC_KEY_MOUSE_RIGHT: c_int = 0x111; +const EC_KEY_MOUSE_MIDDLE: c_int = 0x112; const EC_KEY_TOOL_PEN: c_int = 0x140; -//const EC_KEY_TOUCH: c_int = 0x14a; -//const EC_KEY_STYLUS: c_int = 0x14b; -//const EC_KEY_TOOL_FINGER: c_int = 0x145; -//const EC_KEY_TOOL_DOUBLETAP: c_int = 0x14d; -//const EC_KEY_TOOL_TRIPLETAP: c_int = 0x14e; -//const EC_KEY_TOOL_QUADTAP: c_int = 0x14f; /* Four fingers on trackpad */ -//const EC_KEY_TOOL_QUINTTAP: c_int = 0x148; /* Five fingers on trackpad */ - +const EC_KEY_TOUCH: c_int = 0x14a; +const EC_KEY_TOOL_FINGER: c_int = 0x145; +const EC_KEY_TOOL_DOUBLETAP: c_int = 0x14d; +const EC_KEY_TOOL_TRIPLETAP: c_int = 0x14e; +const EC_KEY_TOOL_QUADTAP: c_int = 0x14f; /* Four fingers on trackpad */ +const EC_KEY_TOOL_QUINTTAP: c_int = 0x148; /* Five fingers on trackpad */ //const EC_RELATIVE_X: c_int = 0x00; //const EC_RELATIVE_Y: c_int = 0x01; @@ -148,7 +150,7 @@ const EC_ABSOLUTE_Y: c_int = 0x01; const EC_ABSOLUTE_PRESSURE: c_int = 0x18; const EC_ABSOLUTE_TILT_X: c_int = 0x1a; const EC_ABSOLUTE_TILT_Y: c_int = 0x1b; -/*const EC_ABS_MT_SLOT: c_int = 0x2f; /* MT slot being modified */ +const EC_ABS_MT_SLOT: c_int = 0x2f; /* MT slot being modified */ const EC_ABS_MT_TOUCH_MAJOR: c_int = 0x30; /* Major axis of touching ellipse */ const EC_ABS_MT_TOUCH_MINOR: c_int = 0x31; /* Minor axis (omit if circular) */ const EC_ABS_MT_ORIENTATION: c_int = 0x34; /* Ellipse orientation */ @@ -157,10 +159,14 @@ const EC_ABS_MT_POSITION_Y: c_int = 0x36; /* Center Y touch position */ const EC_ABS_MT_TRACKING_ID: c_int = 0x39; /* Unique ID of initiated contact */ const EC_ABS_MT_PRESSURE: c_int = 0x3a; /* Pressure on contact area */ -// Maximum for Absolute Values -const ABS_MAX: c_int = 65535;*/ +const EC_MSC_TIMESTAMP: c_int = 0x05; -impl PointerDevice for GraphicTablet { +// This is choosen somewhat arbitrarily +// describes maximum value for ABS_X, ABS_Y, ABS_... +// This corresponds to PointerEvent values of 1.0 +const ABS_MAX: f64 = 65535.0; + +impl InputDevice for GraphicTablet { fn send_event(&mut self, event: &PointerEvent) { if let Err(err) = self.winfo.activate() { warn!("Failed to activate window, sending no input ({})", err); @@ -177,7 +183,7 @@ impl PointerDevice for GraphicTablet { self.width = geometry.width; self.height = geometry.height; match event.pointer_type { - /*PointerType::Touch => { + PointerType::Touch => { match event.event_type { PointerEventType::DOWN | PointerEventType::MOVE => { let slot: usize; @@ -187,14 +193,17 @@ impl PointerDevice for GraphicTablet { } else { // this event is not assigned to a slot, lets try to do so now // find the first unused slot - if let Some(s) = self.multi_touches.iter().enumerate().find_map( - |(slot, mt)| match mt { - None => Some(slot), - Some(_) => None, - }, - ) { + if let Some(s) = + self.touches + .iter() + .enumerate() + .find_map(|(slot, mt)| match mt { + None => Some(slot), + Some(_) => None, + }) + { slot = s; - self.multi_touches[slot] = Some(MultiTouch { + self.touches[slot] = Some(MultiTouch { id: event.pointer_id, }) } else { @@ -202,19 +211,33 @@ impl PointerDevice for GraphicTablet { return; } }; - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_SLOT, slot as i32); - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_TRACKING_ID, slot as i32); - self.send_touch( + self.send(self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_SLOT, slot as i32); + self.send( + self.touch_fd, ET_ABSOLUTE, - EC_ABS_MT_POSITION_X, - self.transform_x(event.x), + EC_ABS_MT_TRACKING_ID, + slot as i32, ); - self.send_touch( - ET_ABSOLUTE, - EC_ABS_MT_POSITION_Y, - self.transform_y(event.y), - ); - self.send_touch( + + if let PointerEventType::DOWN = event.event_type { + self.send(self.touch_fd, ET_KEY, EC_KEY_TOUCH, 1); + match slot { + 1 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_FINGER, 0), + 2 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_DOUBLETAP, 0), + 3 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_TRIPLETAP, 0), + 4 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUADTAP, 0), + _ => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUINTTAP, 0), + } + match slot { + 1 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_DOUBLETAP, 1), + 2 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_TRIPLETAP, 1), + 3 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUADTAP, 1), + 4 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUINTTAP, 1), + _ => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_FINGER, 1), + } + } + self.send( + self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_PRESSURE, self.transform_pressure(event.pressure), @@ -230,74 +253,169 @@ impl PointerDevice for GraphicTablet { minor = self.transform_touch_size(event.height); 1 }; - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_TOUCH_MAJOR, major); - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_TOUCH_MINOR, minor); - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_ORIENTATION, orientation); - self.send_touch(ET_ABSOLUTE, EC_ABSOLUTE_X, self.transform_x(event.x)); - self.send_touch(ET_ABSOLUTE, EC_ABSOLUTE_Y, self.transform_x(event.y)); - self.send_touch(ET_KEY, EC_KEY_TOUCH, 1); - self.send_touch(ET_KEY, EC_KEY_TOOL_FINGER, 1); - self.send_touch(ET_SYNC, EC_SYNC_REPORT, 1); - for (i, mt) in self.multi_touches.iter().enumerate() { - info!( - "slot: {} id: {}", - i, - if let Some(mt) = mt { - mt.id.to_string() - } else { - "".to_string() - } - ); - } + self.send(self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_TOUCH_MAJOR, major); + self.send(self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_TOUCH_MINOR, minor); + self.send( + self.touch_fd, + ET_ABSOLUTE, + EC_ABS_MT_ORIENTATION, + orientation, + ); + self.send( + self.touch_fd, + ET_ABSOLUTE, + EC_ABS_MT_POSITION_X, + self.transform_x(event.x), + ); + self.send( + self.touch_fd, + ET_ABSOLUTE, + EC_ABS_MT_POSITION_Y, + self.transform_y(event.y), + ); + self.send( + self.touch_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_X, + self.transform_x(event.x), + ); + self.send( + self.touch_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_Y, + self.transform_y(event.y), + ); + self.send( + self.touch_fd, + ET_MSC, + EC_MSC_TIMESTAMP, + event.timestamp as i32, + ); + self.send(self.touch_fd, ET_SYNC, EC_SYNC_REPORT, 0); } PointerEventType::CANCEL | PointerEventType::UP => { // remove from slot if let Some(slot) = self.find_slot(event.pointer_id) { - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_SLOT, slot as i32); - self.send_touch(ET_ABSOLUTE, EC_ABS_MT_TRACKING_ID, -1); - self.multi_touches[slot] = None; + self.send(self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_SLOT, slot as i32); + self.send(self.touch_fd, ET_ABSOLUTE, EC_ABS_MT_TRACKING_ID, -1); + self.send(self.touch_fd, ET_KEY, EC_KEY_TOUCH, 0); + self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_FINGER, 0); + match slot { + 1 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_DOUBLETAP, 0), + 2 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_TRIPLETAP, 0), + 3 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUADTAP, 0), + 4 => self.send(self.touch_fd, ET_KEY, EC_KEY_TOOL_QUINTTAP, 0), + _ => (), + } + self.send( + self.touch_fd, + ET_MSC, + EC_MSC_TIMESTAMP, + event.timestamp as i32, + ); + self.send(self.touch_fd, ET_SYNC, EC_SYNC_REPORT, 0); + self.touches[slot] = None; } } }; - }*/ + } PointerType::Pen => { - self.send(ET_ABSOLUTE, EC_ABSOLUTE_X, self.transform_x(event.x)); - self.send(ET_ABSOLUTE, EC_ABSOLUTE_Y, self.transform_y(event.y)); - self.send( - ET_ABSOLUTE, - EC_ABSOLUTE_PRESSURE, - self.transform_pressure(event.pressure), - ); - self.send(ET_ABSOLUTE, EC_ABSOLUTE_TILT_X, event.tilt_x); - self.send(ET_ABSOLUTE, EC_ABSOLUTE_TILT_Y, event.tilt_y); match event.event_type { - PointerEventType::DOWN => { - self.send(ET_KEY, EC_KEY_TOOL_PEN, 1); + PointerEventType::DOWN | PointerEventType::MOVE => { + if let PointerEventType::DOWN = event.event_type { + self.send(self.stylus_fd, ET_KEY, EC_KEY_TOOL_PEN, 1); + } + self.send( + self.stylus_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_X, + self.transform_x(event.x), + ); + self.send( + self.stylus_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_Y, + self.transform_y(event.y), + ); + self.send( + self.stylus_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_PRESSURE, + self.transform_pressure(event.pressure), + ); + self.send( + self.stylus_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_TILT_X, + event.tilt_x, + ); + self.send( + self.stylus_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_TILT_Y, + event.tilt_y, + ); } PointerEventType::UP | PointerEventType::CANCEL => { - self.send(ET_KEY, EC_KEY_TOOL_PEN, 0); + self.send(self.stylus_fd, ET_KEY, EC_KEY_TOOL_PEN, 0); } - PointerEventType::MOVE => (), - } - self.send(ET_SYNC, EC_SYNC_REPORT, 1); - } - PointerType::Mouse | PointerType::Unknown | PointerType::Touch => { - if !event.is_primary { - return; } - self.send(ET_ABSOLUTE, EC_ABSOLUTE_X, self.transform_x(event.x)); - self.send(ET_ABSOLUTE, EC_ABSOLUTE_Y, self.transform_y(event.y)); self.send( - ET_ABSOLUTE, - EC_ABSOLUTE_PRESSURE, - self.transform_pressure(0.5), + self.stylus_fd, + ET_MSC, + EC_MSC_TIMESTAMP, + event.timestamp as i32, ); + self.send(self.stylus_fd, ET_SYNC, EC_SYNC_REPORT, 0); + } + PointerType::Mouse | PointerType::Unknown => { match event.event_type { - PointerEventType::DOWN => self.send(ET_KEY, EC_KEY_MOUSE_LEFT, 1), - PointerEventType::MOVE => (), - _ => self.send(ET_KEY, EC_KEY_MOUSE_LEFT, 0), + PointerEventType::DOWN | PointerEventType::MOVE => { + if let PointerEventType::DOWN = event.event_type { + match event.button { + Button::PRIMARY => { + self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_LEFT, 1) + } + Button::SECONDARY => { + self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_RIGHT, 1) + } + Button::AUXILARY => { + self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_MIDDLE, 1) + } + _ => (), + } + } + self.send( + self.mouse_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_X, + self.transform_x(event.x), + ); + self.send( + self.mouse_fd, + ET_ABSOLUTE, + EC_ABSOLUTE_Y, + self.transform_y(event.y), + ); + } + PointerEventType::UP | PointerEventType::CANCEL => match event.button { + Button::PRIMARY => self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_LEFT, 0), + Button::SECONDARY => { + self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_RIGHT, 0) + } + Button::AUXILARY => { + self.send(self.mouse_fd, ET_KEY, EC_KEY_MOUSE_MIDDLE, 0) + } + _ => (), + }, } - self.send(ET_SYNC, EC_SYNC_REPORT, 1); + self.send( + self.mouse_fd, + ET_MSC, + EC_MSC_TIMESTAMP, + event.timestamp as i32, + ); + self.send(self.mouse_fd, ET_SYNC, EC_SYNC_REPORT, 0); } } } diff --git a/src/protocol.rs b/src/protocol.rs index 135dffca..df2be792 100644 --- a/src/protocol.rs +++ b/src/protocol.rs @@ -52,6 +52,7 @@ fn from_str<'de, D: Deserializer<'de>>(deserializer: D) -> Result { +pub struct PointerStreamHandler { device: T, } -impl PointerStreamHandler { +impl PointerStreamHandler { pub fn new(device: T) -> Self { PointerStreamHandler { device: device } } } -impl StreamHandler for PointerStreamHandler { +impl StreamHandler for PointerStreamHandler { fn process(&mut self, _: WsWriter, message: &OwnedMessage) { match message { OwnedMessage::Text(s) => { diff --git a/ts/lib.ts b/ts/lib.ts index 7bf22647..9f51052c 100644 --- a/ts/lib.ts +++ b/ts/lib.ts @@ -15,6 +15,7 @@ class ClientConfig { class PEvent { event_type: string; pointer_id: number; + timestamp: number; is_primary: boolean; pointer_type: string; button: number; @@ -35,6 +36,7 @@ class PEvent { let diag_len = Math.sqrt(canvas.width * canvas.width + canvas.height * canvas.height) this.event_type = eventType.toString(); this.pointer_id = event.pointerId; + this.timestamp = Math.round(event.timeStamp * 1000); this.is_primary = event.isPrimary; this.pointer_type = event.pointerType; this.button = event.button < 0 ? 0 : 1 << event.button;