Skip to content

Commit

Permalink
Multitouch works now.
Browse files Browse the repository at this point in the history
  • Loading branch information
H-M-H committed May 2, 2020
1 parent 3b58c0c commit 6aa2672
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 191 deletions.
164 changes: 100 additions & 64 deletions lib/linux/uinput.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -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;
}
Expand Down
14 changes: 14 additions & 0 deletions lib/linux/uinput_info.md
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion src/input/pointer.rs → src/input/device.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::protocol::PointerEvent;

pub trait PointerDevice {
pub trait InputDevice {
fn send_event(&mut self, event: &PointerEvent);
}
2 changes: 1 addition & 1 deletion src/input/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod pointer;
pub mod device;
pub mod mouse_device;

#[cfg(target_os = "linux")]
Expand Down
4 changes: 2 additions & 2 deletions src/input/mouse_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 6aa2672

Please sign in to comment.