summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2016-01-06 15:26:49 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2016-01-22 16:16:55 +1000
commit7164d6eff5c83b8280d1d55eb33fb173160f9de9 (patch)
tree41081b282e743d25ddb1ee98134dbd86c4a779a3 /src
parent108a191a3ec868c00e5ee72be383b437894b2fc5 (diff)
tablet: hook up relative motion events
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Acked-by: Jason Gerecke <jason.gerecke@wacom.com>
Diffstat (limited to 'src')
-rw-r--r--src/evdev-tablet.c116
-rw-r--r--src/evdev.c13
-rw-r--r--src/evdev.h4
-rw-r--r--src/filter.c94
-rw-r--r--src/filter.h3
-rw-r--r--src/libinput-util.h10
6 files changed, 230 insertions, 10 deletions
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 1870e7e3..ae205501 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -285,19 +285,29 @@ normalize_wheel(struct tablet_dispatch *tablet,
return value * device->scroll.wheel_click_angle;
}
-static inline struct device_coords
-tablet_handle_xy(struct tablet_dispatch *tablet, struct evdev_device *device)
+static inline void
+tablet_handle_xy(struct tablet_dispatch *tablet,
+ struct evdev_device *device,
+ struct device_coords *point_out,
+ struct device_coords *delta_out)
{
struct device_coords point;
+ struct device_coords delta = { 0, 0 };
const struct input_absinfo *absinfo;
+ int value;
if (bit_is_set(tablet->changed_axes, LIBINPUT_TABLET_TOOL_AXIS_X)) {
absinfo = libevdev_get_abs_info(device->evdev, ABS_X);
if (device->left_handed.enabled)
- tablet->axes.point.x = invert_axis(absinfo);
+ value = invert_axis(absinfo);
else
- tablet->axes.point.x = absinfo->value;
+ value = absinfo->value;
+
+ if (!tablet_has_status(tablet,
+ TABLET_TOOL_ENTERING_PROXIMITY))
+ delta.x = value - tablet->axes.point.x;
+ tablet->axes.point.x = value;
}
point.x = tablet->axes.point.x;
@@ -305,15 +315,41 @@ tablet_handle_xy(struct tablet_dispatch *tablet, struct evdev_device *device)
absinfo = libevdev_get_abs_info(device->evdev, ABS_Y);
if (device->left_handed.enabled)
- tablet->axes.point.y = invert_axis(absinfo);
+ value = invert_axis(absinfo);
else
- tablet->axes.point.y = absinfo->value;
+ value = absinfo->value;
+
+ if (!tablet_has_status(tablet,
+ TABLET_TOOL_ENTERING_PROXIMITY))
+ delta.y = value - tablet->axes.point.y;
+ tablet->axes.point.y = value;
}
point.y = tablet->axes.point.y;
evdev_transform_absolute(device, &point);
+ evdev_transform_relative(device, &delta);
+
+ *delta_out = delta;
+ *point_out = point;
+}
+
+static inline struct normalized_coords
+tablet_process_delta(struct tablet_dispatch *tablet,
+ const struct evdev_device *device,
+ const struct device_coords *delta,
+ uint64_t time)
+{
+ struct normalized_coords accel;
+
+ /* The tablet accel code uses mm as input */
+ accel.x = 1.0 * delta->x/device->abs.absinfo_x->resolution;
+ accel.y = 1.0 * delta->y/device->abs.absinfo_y->resolution;
- return point;
+ if (normalized_is_zero(accel))
+ return accel;
+
+ return filter_dispatch(device->pointer.filter,
+ &accel, tablet, time);
}
static inline double
@@ -445,19 +481,22 @@ static bool
tablet_check_notify_axes(struct tablet_dispatch *tablet,
struct evdev_device *device,
struct libinput_tablet_tool *tool,
- struct tablet_axes *axes_out)
+ struct tablet_axes *axes_out,
+ uint64_t time)
{
struct tablet_axes axes = {0};
const char tmp[sizeof(tablet->changed_axes)] = {0};
+ struct device_coords delta;
if (memcmp(tmp, tablet->changed_axes, sizeof(tmp)) == 0)
return false;
- axes.point = tablet_handle_xy(tablet, device);
+ tablet_handle_xy(tablet, device, &axes.point, &delta);
axes.pressure = tablet_handle_pressure(tablet, device, tool);
axes.distance = tablet_handle_distance(tablet, device);
axes.slider = tablet_handle_slider(tablet, device);
axes.tilt = tablet_handle_tilt(tablet, device);
+ axes.delta = tablet_process_delta(tablet, device, &delta, time);
/* We must check ROTATION_Z after TILT_X/Y so that the tilt axes are
* already normalized and set if we have the mouse/lens tool */
@@ -1186,7 +1225,8 @@ tablet_send_axis_proximity_tip_down_events(struct tablet_dispatch *tablet,
} else if (!tablet_check_notify_axes(tablet,
device,
tool,
- &axes)) {
+ &axes,
+ time)) {
goto out;
}
@@ -1463,11 +1503,64 @@ tablet_init_proximity_threshold(struct tablet_dispatch *tablet,
tablet->cursor_proximity_threshold = 42;
}
+static uint32_t
+tablet_accel_config_get_profiles(struct libinput_device *libinput_device)
+{
+ return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
+static enum libinput_config_status
+tablet_accel_config_set_profile(struct libinput_device *libinput_device,
+ enum libinput_config_accel_profile profile)
+{
+ return LIBINPUT_CONFIG_STATUS_UNSUPPORTED;
+}
+
+static enum libinput_config_accel_profile
+tablet_accel_config_get_profile(struct libinput_device *libinput_device)
+{
+ return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
+static enum libinput_config_accel_profile
+tablet_accel_config_get_default_profile(struct libinput_device *libinput_device)
+{
+ return LIBINPUT_CONFIG_ACCEL_PROFILE_NONE;
+}
+
+static int
+tablet_init_accel(struct tablet_dispatch *tablet, struct evdev_device *device)
+{
+ const struct input_absinfo *x, *y;
+ struct motion_filter *filter;
+ int rc;
+
+ x = device->abs.absinfo_x;
+ y = device->abs.absinfo_y;
+
+ filter = create_pointer_accelerator_filter_tablet(x->resolution,
+ y->resolution);
+
+ rc = evdev_device_init_pointer_acceleration(device, filter);
+ if (rc != 0)
+ return rc;
+
+ /* we override the profile hooks for accel configuration with hooks
+ * that don't allow selection of profiles */
+ device->pointer.config.get_profiles = tablet_accel_config_get_profiles;
+ device->pointer.config.set_profile = tablet_accel_config_set_profile;
+ device->pointer.config.get_profile = tablet_accel_config_get_profile;
+ device->pointer.config.get_default_profile = tablet_accel_config_get_default_profile;
+
+ return 0;
+}
+
static int
tablet_init(struct tablet_dispatch *tablet,
struct evdev_device *device)
{
enum libinput_tablet_tool_axis axis;
+ int rc;
tablet->base.interface = &tablet_interface;
tablet->device = device;
@@ -1477,6 +1570,9 @@ tablet_init(struct tablet_dispatch *tablet,
tablet_init_calibration(tablet, device);
tablet_init_proximity_threshold(tablet, device);
+ rc = tablet_init_accel(tablet, device);
+ if (rc != 0)
+ return rc;
for (axis = LIBINPUT_TABLET_TOOL_AXIS_X;
axis <= LIBINPUT_TABLET_TOOL_AXIS_MAX;
diff --git a/src/evdev.c b/src/evdev.c
index 82359237..8f0a6079 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -222,6 +222,19 @@ evdev_transform_absolute(struct evdev_device *device,
matrix_mult_vec(&device->abs.calibration, &point->x, &point->y);
}
+void
+evdev_transform_relative(struct evdev_device *device,
+ struct device_coords *point)
+{
+ struct matrix rel_matrix;
+
+ if (!device->abs.apply_calibration)
+ return;
+
+ matrix_to_relative(&rel_matrix, &device->abs.calibration);
+ matrix_mult_vec(&rel_matrix, &point->x, &point->y);
+}
+
static inline double
scale_axis(const struct input_absinfo *absinfo, double val, double to_range)
{
diff --git a/src/evdev.h b/src/evdev.h
index cf0eda9b..02b51126 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -293,6 +293,10 @@ evdev_transform_absolute(struct evdev_device *device,
struct device_coords *point);
void
+evdev_transform_relative(struct evdev_device *device,
+ struct device_coords *point);
+
+void
evdev_init_calibration(struct evdev_device *device,
struct evdev_dispatch *dispatch);
diff --git a/src/filter.c b/src/filter.c
index 0d0b95d4..4c39b0e2 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -163,6 +163,13 @@ struct pointer_accelerator_flat {
double dpi_factor;
};
+struct tablet_accelerator_flat {
+ struct motion_filter base;
+
+ double factor;
+ int xres, yres;
+};
+
static void
feed_trackers(struct pointer_accelerator *accel,
const struct normalized_coords *delta,
@@ -964,3 +971,90 @@ create_pointer_accelerator_filter_flat(int dpi)
return &filter->base;
}
+
+/* The tablet accel code uses mm as input */
+static struct normalized_coords
+tablet_accelerator_filter_flat(struct motion_filter *filter,
+ const struct normalized_coords *mm,
+ void *data, uint64_t time)
+{
+ struct tablet_accelerator_flat *accel_filter =
+ (struct tablet_accelerator_flat *)filter;
+ struct normalized_coords accelerated;
+
+ /* Tablet input is in mm, output is supposed to be in logical
+ * pixels roughly equivalent to a mouse/touchpad.
+ *
+ * This is a magical constant found by trial and error. On a 96dpi
+ * screen 0.4mm of movement correspond to 1px logical pixel which
+ * is almost identical to the tablet mapped to screen in absolute
+ * mode. Tested on a Intuos5, other tablets may vary.
+ */
+ const double DPI_CONVERSION = 96.0/25.4 * 2.5; /* unitless factor */
+
+ accelerated.x = mm->x * accel_filter->factor * DPI_CONVERSION;
+ accelerated.y = mm->y * accel_filter->factor * DPI_CONVERSION;
+
+ return accelerated;
+}
+
+static bool
+tablet_accelerator_set_speed(struct motion_filter *filter,
+ double speed_adjustment)
+{
+ struct tablet_accelerator_flat *accel_filter =
+ (struct tablet_accelerator_flat *)filter;
+
+ assert(speed_adjustment >= -1.0 && speed_adjustment <= 1.0);
+
+ accel_filter->factor = speed_adjustment + 1.0;
+
+ return true;
+}
+
+static void
+tablet_accelerator_destroy(struct motion_filter *filter)
+{
+ struct tablet_accelerator_flat *accel_filter =
+ (struct tablet_accelerator_flat *)filter;
+
+ free(accel_filter);
+}
+
+struct motion_filter_interface accelerator_interface_tablet = {
+ .type = LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT,
+ .filter = tablet_accelerator_filter_flat,
+ .filter_constant = NULL,
+ .restart = NULL,
+ .destroy = tablet_accelerator_destroy,
+ .set_speed = tablet_accelerator_set_speed,
+};
+
+static struct tablet_accelerator_flat *
+create_tablet_filter_flat(int xres, int yres)
+{
+ struct tablet_accelerator_flat *filter;
+
+ filter = zalloc(sizeof *filter);
+ if (filter == NULL)
+ return NULL;
+
+ filter->xres = xres;
+ filter->yres = yres;
+
+ return filter;
+}
+
+struct motion_filter *
+create_pointer_accelerator_filter_tablet(int xres, int yres)
+{
+ struct tablet_accelerator_flat *filter;
+
+ filter = create_tablet_filter_flat(xres, yres);
+ if (!filter)
+ return NULL;
+
+ filter->base.interface = &accelerator_interface_tablet;
+
+ return &filter->base;
+}
diff --git a/src/filter.h b/src/filter.h
index e1566429..c1b43a5d 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -101,6 +101,9 @@ create_pointer_accelerator_filter_lenovo_x230(int dpi);
struct motion_filter *
create_pointer_accelerator_filter_trackpoint(int dpi);
+struct motion_filter *
+create_pointer_accelerator_filter_tablet(int xres, int yres);
+
/*
* Pointer acceleration profiles.
*/
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 93f7f0e4..6adbbc91 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -270,6 +270,16 @@ matrix_to_farray6(const struct matrix *m, float out[6])
out[5] = m->val[1][2];
}
+static inline void
+matrix_to_relative(struct matrix *dest, const struct matrix *src)
+{
+ matrix_init_identity(dest);
+ dest->val[0][0] = src->val[0][0];
+ dest->val[0][1] = src->val[0][1];
+ dest->val[1][0] = src->val[1][0];
+ dest->val[1][1] = src->val[1][1];
+}
+
/**
* Simple wrapper for asprintf that ensures the passed in-pointer is set
* to NULL upon error.