summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2015-06-16 13:52:02 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2015-06-16 13:52:02 +1000
commit2b99363a1ff948917a1a81c18d6079fb4a8cd4c2 (patch)
tree79bba625edcd0e82e30fa302475124d8bacee5ed
parent99aa1f5dc3593826e512460a5c914a87a3a7c16a (diff)
parent8025b374d564f4a30b089e5cf6fd65e0c6af8da2 (diff)
Merge branch 'master' into tablet-support
-rw-r--r--doc/scrolling.dox20
-rw-r--r--src/evdev-mt-touchpad-buttons.c19
-rw-r--r--src/evdev-mt-touchpad.c42
-rw-r--r--src/evdev-mt-touchpad.h5
-rw-r--r--src/evdev.c2
-rw-r--r--src/evdev.h2
-rw-r--r--src/filter-private.h3
-rw-r--r--src/filter.c33
-rw-r--r--src/filter.h5
-rw-r--r--src/libinput-util.h6
-rw-r--r--test/Makefile.am10
-rw-r--r--test/litest.c101
-rw-r--r--test/touchpad.c48
-rw-r--r--udev/90-libinput-model-quirks.hwdb37
-rw-r--r--udev/90-libinput-model-quirks.rules6
15 files changed, 282 insertions, 57 deletions
diff --git a/doc/scrolling.dox b/doc/scrolling.dox
index 94aa8158..1ecd0333 100644
--- a/doc/scrolling.dox
+++ b/doc/scrolling.dox
@@ -2,12 +2,24 @@
@page scrolling Scrolling
libinput supports three different types of scrolling methods: @ref
-twofinger_scrolling, @ref edge_scrolling and @ref button_scrolling. Some devices
-support multiple methods, though only one can be enabled at a time. See
+twofinger_scrolling, @ref edge_scrolling and @ref button_scrolling. Some
+devices support multiple methods, though only one can be enabled at a time.
+As a general overview:
+- touchpad devices with physical buttons below the touchpad support edge and
+ two-finger scrolling
+- touchpad devices without physical buttons (@ref clickpad_softbuttons
+ "clickpads") support two-finger scrolling only
+- pointing sticks provide on-button scrolling by default
+- mice and other pointing devices support on-button scrolling but it is not
+ enabled by default
+
+A device may differ from the above based on its capabilities. See
libinput_device_config_scroll_set_method() for documentation on how to
switch methods and libinput_device_config_scroll_get_methods() for
documentation on how to query a device for available scroll methods.
+@section horizontal_scrolling Horizontal scrolling
+
Scroll movements provide vertical and horizontal directions, each
scroll event contains both directions where applicable, see
libinput_event_pointer_get_axis_value(). libinput does not provide separate
@@ -55,6 +67,10 @@ a designated button is held down. For example, Lenovo devices provide a
<a href="http://en.wikipedia.org/wiki/Pointing_stick">pointing stick</a> that emulates
scroll events when the trackstick's middle mouse button is held down.
+@note On-button scrolling is enabled by default for pointing sticks. This
+prevents middle-button dragging; all motion events while the middle button is
+down are converted to scroll events.
+
@image html button-scrolling.svg "Button scrolling"
The button may be changed with
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index 5786ea8b..eb0ddcb0 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -31,7 +31,6 @@
#include "evdev-mt-touchpad.h"
-#define DEFAULT_BUTTON_MOTION_THRESHOLD 0.02 /* 2% of size */
#define DEFAULT_BUTTON_ENTER_TIMEOUT 100 /* ms */
#define DEFAULT_BUTTON_LEAVE_TIMEOUT 300 /* ms */
@@ -709,11 +708,19 @@ tp_init_buttons(struct tp_dispatch *tp,
absinfo_x = device->abs.absinfo_x;
absinfo_y = device->abs.absinfo_y;
- width = abs(absinfo_x->maximum - absinfo_x->minimum);
- height = abs(absinfo_y->maximum - absinfo_y->minimum);
- diagonal = sqrt(width*width + height*height);
-
- tp->buttons.motion_dist = diagonal * DEFAULT_BUTTON_MOTION_THRESHOLD;
+ /* pinned-finger motion threshold, see tp_unpin_finger.
+ The MAGIC for resolution-less touchpads ends up as 2% of the diagonal */
+ if (device->abs.fake_resolution) {
+ const int BUTTON_MOTION_MAGIC = 0.007;
+ width = abs(absinfo_x->maximum - absinfo_x->minimum);
+ height = abs(absinfo_y->maximum - absinfo_y->minimum);
+ diagonal = sqrt(width*width + height*height);
+ tp->buttons.motion_dist.x_scale_coeff = diagonal * BUTTON_MOTION_MAGIC;
+ tp->buttons.motion_dist.y_scale_coeff = diagonal * BUTTON_MOTION_MAGIC;
+ } else {
+ tp->buttons.motion_dist.x_scale_coeff = 1.0/absinfo_x->resolution;
+ tp->buttons.motion_dist.y_scale_coeff = 1.0/absinfo_y->resolution;
+ }
tp->buttons.config_method.get_methods = tp_button_config_click_get_methods;
tp->buttons.config_method.set_method = tp_button_config_click_set_method;
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index e7abe945..4858e86b 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -431,17 +431,15 @@ tp_unpin_finger(struct tp_dispatch *tp, struct tp_touch *t)
return;
xdist = abs(t->point.x - t->pinned.center.x);
+ xdist *= tp->buttons.motion_dist.x_scale_coeff;
ydist = abs(t->point.y - t->pinned.center.y);
+ ydist *= tp->buttons.motion_dist.y_scale_coeff;
- if (xdist * xdist + ydist * ydist >=
- tp->buttons.motion_dist * tp->buttons.motion_dist) {
+ /* 3mm movement -> unpin */
+ if (vector_length(xdist, ydist) >= 3.0) {
t->pinned.is_pinned = false;
return;
}
-
- /* The finger may slowly drift, adjust the center */
- t->pinned.center.x = t->point.x + t->pinned.center.x / 2;
- t->pinned.center.y = t->point.y + t->pinned.center.y / 2;
}
static void
@@ -666,6 +664,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
struct tp_touch *t;
struct tp_touch *first = tp_get_touch(tp, 0);
unsigned int i;
+ bool restart_filter = false;
tp_process_fake_touches(tp, time);
tp_unhover_touches(tp, time);
@@ -692,8 +691,14 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
tp_motion_history_push(t);
tp_unpin_finger(tp, t);
+
+ if (t->state == TOUCH_BEGIN)
+ restart_filter = true;
}
+ if (restart_filter)
+ filter_restart(tp->device->pointer.filter, tp, time);
+
tp_button_handle_state(tp, time);
tp_edge_scroll_handle_state(tp, time);
@@ -1150,7 +1155,7 @@ evdev_tag_touchpad(struct evdev_device *device,
*/
bustype = libevdev_get_id_bustype(device->evdev);
if (bustype == BUS_USB) {
- if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_APPLE)
+ if (device->model == EVDEV_MODEL_APPLE_TOUCHPAD)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
} else if (bustype != BUS_BLUETOOTH)
device->tags |= EVDEV_TAG_INTERNAL_TOUCHPAD;
@@ -1389,7 +1394,6 @@ tp_init_palmdetect(struct tp_dispatch *tp,
struct evdev_device *device)
{
int width, height;
- unsigned int vendor_id;
tp->palm.right_edge = INT_MAX;
tp->palm.left_edge = INT_MIN;
@@ -1400,13 +1404,11 @@ tp_init_palmdetect(struct tp_dispatch *tp,
height = abs(device->abs.absinfo_y->maximum -
device->abs.absinfo_y->minimum);
- vendor_id = evdev_device_get_id_vendor(device);
-
/* Wacom doesn't have internal touchpads,
* Apple touchpads are always big enough to warrant palm detection */
- if (vendor_id == VENDOR_ID_WACOM) {
+ if (device->model == EVDEV_MODEL_WACOM_TOUCHPAD) {
return 0;
- } else if (vendor_id != VENDOR_ID_APPLE) {
+ } else if (device->model != EVDEV_MODEL_APPLE_TOUCHPAD) {
/* We don't know how big the touchpad is */
if (device->abs.absinfo_x->resolution == 1)
return 0;
@@ -1489,10 +1491,18 @@ tp_init(struct tp_dispatch *tp,
EV_ABS,
ABS_MT_DISTANCE);
- tp->hysteresis_margin.x =
- diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
- tp->hysteresis_margin.y =
- diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
+ if (device->abs.fake_resolution) {
+ tp->hysteresis_margin.x =
+ diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
+ tp->hysteresis_margin.y =
+ diagonal / DEFAULT_HYSTERESIS_MARGIN_DENOMINATOR;
+ } else {
+ int res_x = tp->device->abs.absinfo_x->resolution,
+ res_y = tp->device->abs.absinfo_y->resolution;
+
+ tp->hysteresis_margin.x = res_x/2;
+ tp->hysteresis_margin.y = res_y/2;
+ }
if (tp_init_accel(tp, diagonal) != 0)
return -1;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index fef5cb32..bd2d1633 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -223,7 +223,10 @@ struct tp_dispatch {
bool click_pending;
uint32_t state;
uint32_t old_state;
- uint32_t motion_dist; /* for pinned touches */
+ struct {
+ double x_scale_coeff;
+ double y_scale_coeff;
+ } motion_dist; /* for pinned touches */
unsigned int active; /* currently active button, for release event */
bool active_is_topbutton; /* is active a top button? */
diff --git a/src/evdev.c b/src/evdev.c
index 3e66df36..074ee3b1 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1514,6 +1514,8 @@ evdev_read_model(struct evdev_device *device)
{ "LIBINPUT_MODEL_SYSTEM76_GALAGO", EVDEV_MODEL_SYSTEM76_GALAGO },
{ "LIBINPUT_MODEL_SYSTEM76_KUDU", EVDEV_MODEL_SYSTEM76_KUDU },
{ "LIBINPUT_MODEL_CLEVO_W740SU", EVDEV_MODEL_CLEVO_W740SU },
+ { "LIBINPUT_MODEL_APPLE_TOUCHPAD", EVDEV_MODEL_APPLE_TOUCHPAD },
+ { "LIBINPUT_MODEL_WACOM_TOUCHPAD", EVDEV_MODEL_WACOM_TOUCHPAD },
{ NULL, EVDEV_MODEL_DEFAULT },
};
const struct model_map *m = model_map;
diff --git a/src/evdev.h b/src/evdev.h
index 17ae0d95..1600b091 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -104,6 +104,8 @@ enum evdev_device_model {
EVDEV_MODEL_SYSTEM76_GALAGO,
EVDEV_MODEL_SYSTEM76_KUDU,
EVDEV_MODEL_CLEVO_W740SU,
+ EVDEV_MODEL_APPLE_TOUCHPAD,
+ EVDEV_MODEL_WACOM_TOUCHPAD,
};
struct mt_slot {
diff --git a/src/filter-private.h b/src/filter-private.h
index 0e796f1a..8a206d69 100644
--- a/src/filter-private.h
+++ b/src/filter-private.h
@@ -32,6 +32,9 @@ struct motion_filter_interface {
struct motion_filter *filter,
const struct normalized_coords *unaccelerated,
void *data, uint64_t time);
+ void (*restart)(struct motion_filter *filter,
+ void *data,
+ uint64_t time);
void (*destroy)(struct motion_filter *filter);
bool (*set_speed)(struct motion_filter *filter,
double speed);
diff --git a/src/filter.c b/src/filter.c
index c54d866c..ee4ce9e6 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -44,6 +44,13 @@ filter_dispatch(struct motion_filter *filter,
}
void
+filter_restart(struct motion_filter *filter,
+ void *data, uint64_t time)
+{
+ filter->interface->restart(filter, data, time);
+}
+
+void
filter_destroy(struct motion_filter *filter)
{
if (!filter)
@@ -274,6 +281,29 @@ accelerator_filter(struct motion_filter *filter,
}
static void
+accelerator_restart(struct motion_filter *filter,
+ void *data,
+ uint64_t time)
+{
+ struct pointer_accelerator *accel =
+ (struct pointer_accelerator *) filter;
+ unsigned int offset;
+ struct pointer_tracker *tracker;
+
+ for (offset = 1; offset < NUM_POINTER_TRACKERS; offset++) {
+ tracker = tracker_by_offset(accel, offset);
+ tracker->time = 0;
+ tracker->dir = 0;
+ tracker->delta.x = 0;
+ tracker->delta.y = 0;
+ }
+
+ tracker = tracker_by_offset(accel, 0);
+ tracker->time = time;
+ tracker->dir = UNDEFINED_DIRECTION;
+}
+
+static void
accelerator_destroy(struct motion_filter *filter)
{
struct pointer_accelerator *accel =
@@ -309,6 +339,7 @@ accelerator_set_speed(struct motion_filter *filter,
struct motion_filter_interface accelerator_interface = {
accelerator_filter,
+ accelerator_restart,
accelerator_destroy,
accelerator_set_speed,
};
@@ -354,7 +385,7 @@ pointer_accel_profile_linear(struct motion_filter *filter,
const double threshold = accel_filter->threshold; /* units/ms */
const double incline = accel_filter->incline;
- s1 = min(1, speed_in * 5);
+ s1 = min(1, 0.3 + speed_in * 4);
s2 = 1 + (speed_in - threshold) * incline;
return min(max_accel, s2 > 1 ? s2 : s1);
diff --git a/src/filter.h b/src/filter.h
index 16896a4c..03f510d0 100644
--- a/src/filter.h
+++ b/src/filter.h
@@ -37,6 +37,11 @@ struct normalized_coords
filter_dispatch(struct motion_filter *filter,
const struct normalized_coords *unaccelerated,
void *data, uint64_t time);
+
+void
+filter_restart(struct motion_filter *filter,
+ void *data, uint64_t time);
+
void
filter_destroy(struct motion_filter *filter);
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 5db3e3fa..9c00f792 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -308,4 +308,10 @@ int parse_mouse_dpi_property(const char *prop);
int parse_mouse_wheel_click_angle_property(const char *prop);
double parse_trackpoint_accel_property(const char *prop);
+static inline double
+vector_length(double x, double y)
+{
+ return sqrt(x * x + y * y);
+}
+
#endif /* LIBINPUT_UTIL_H */
diff --git a/test/Makefile.am b/test/Makefile.am
index 3f28a0a3..fb8d5de0 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -42,7 +42,9 @@ liblitest_la_SOURCES = \
litest-vmware-virtual-usb-mouse.c \
litest.c
liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la
-liblitest_la_CFLAGS = $(AM_CFLAGS)
+liblitest_la_CFLAGS = $(AM_CFLAGS) \
+ -DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.rules\"" \
+ -DLIBINPUT_UDEV_HWDB_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.hwdb\""
if HAVE_LIBUNWIND
liblitest_la_LIBADD += $(LIBUNWIND_LIBS) -ldl
liblitest_la_CFLAGS += $(LIBUNWIND_CFLAGS)
@@ -119,9 +121,13 @@ test_device_LDADD = $(TEST_LIBS)
test_device_LDFLAGS = -no-install
test_litest_selftest_SOURCES = litest-selftest.c litest.c litest-int.h litest.h
-test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING -DLITEST_NO_MAIN
+test_litest_selftest_CFLAGS = -DLITEST_DISABLE_BACKTRACE_LOGGING -DLITEST_NO_MAIN $(liblitest_la_CFLAGS)
test_litest_selftest_LDADD = $(TEST_LIBS)
test_litest_selftest_LDFLAGS = -no-install
+if HAVE_LIBUNWIND
+test_litest_selftest_LDADD += $(LIBUNWIND_LIBS) -ldl
+test_litest_selftest_CFLAGS += $(LIBUNWIND_CFLAGS)
+endif
# build-test only
test_build_pedantic_c99_SOURCES = build-pedantic.c
diff --git a/test/litest.c b/test/litest.c
index 8c82cc76..db32b9c2 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -40,6 +40,7 @@
#include <unistd.h>
#include "linux/input.h"
#include <sys/ptrace.h>
+#include <sys/sendfile.h>
#include <sys/timerfd.h>
#include <sys/wait.h>
@@ -49,6 +50,9 @@
#define UDEV_RULES_D "/run/udev/rules.d"
#define UDEV_RULE_PREFIX "99-litest-"
+#define UDEV_HWDB_D "/etc/udev/hwdb.d"
+#define UDEV_COMMON_RULE_FILE UDEV_RULES_D "/91-litest-model-quirks.rules"
+#define UDEV_COMMON_HWDB_FILE UDEV_HWDB_D "/91-litest-model-quirks-REMOVEME.hwdb"
static int in_debugger = -1;
static int verbose = 0;
@@ -56,13 +60,15 @@ const char *filter_test = NULL;
const char *filter_device = NULL;
const char *filter_group = NULL;
+static inline void litest_remove_model_quirks(void);
+
/* defined for the litest selftest */
#ifndef LITEST_DISABLE_BACKTRACE_LOGGING
#define litest_log(...) fprintf(stderr, __VA_ARGS__)
#define litest_vlog(format_, args_) vfprintf(stderr, format_, args_)
#else
-#define litest_log(...) /* __VA_ARGS__ */
-#define litest_vlog(...) /* __VA_ARGS__ */
+#define litest_log(...) { /* __VA_ARGS__ */ }
+#define litest_vlog(...) { /* __VA_ARGS__ */ }
#endif
#ifdef HAVE_LIBUNWIND
@@ -382,28 +388,40 @@ struct litest_test_device* devices[] = {
static struct list all_tests;
-static void
-litest_reload_udev_rules(void)
+static inline void
+litest_system(const char *command)
{
- int ret = system("udevadm control --reload-rules");
+ int ret;
+
+ ret = system(command);
+
if (ret == -1) {
- litest_abort_msg("Failed to execute: udevadm");
+ litest_abort_msg("Failed to execute: %s", command);
} else if (WIFEXITED(ret)) {
if (WEXITSTATUS(ret))
- litest_abort_msg("udevadm failed with %d",
+ litest_abort_msg("'%s' failed with %d",
+ command,
WEXITSTATUS(ret));
} else if (WIFSIGNALED(ret)) {
- litest_abort_msg("udevadm terminated with signal %d",
+ litest_abort_msg("'%s' terminated with signal %d",
+ command,
WTERMSIG(ret));
}
}
+static void
+litest_reload_udev_rules(void)
+{
+ litest_system("udevadm control --reload-rules");
+ litest_system("udevadm hwdb --update");
+}
+
static int
litest_udev_rule_filter(const struct dirent *entry)
{
- return strncmp(entry->d_name,
- UDEV_RULE_PREFIX,
- strlen(UDEV_RULE_PREFIX)) == 0;
+ return strneq(entry->d_name,
+ UDEV_RULE_PREFIX,
+ strlen(UDEV_RULE_PREFIX));
}
static void
@@ -438,6 +456,7 @@ litest_drop_udev_rules(void)
}
free(entries);
+ litest_remove_model_quirks();
litest_reload_udev_rules();
}
@@ -881,21 +900,70 @@ merge_events(const int *orig, const int *override)
return events;
}
+static inline void
+litest_copy_file(const char *dest, const char *src, const char *header)
+{
+ int in, out;
+
+ out = open(dest, O_CREAT|O_WRONLY, 0644);
+ litest_assert_int_gt(out, -1);
+
+ if (header)
+ write(out, header, strlen(header));
+
+ in = open(src, O_RDONLY);
+ litest_assert_int_gt(in, -1);
+ /* lazy, just check for error and empty file copy */
+ litest_assert_int_gt(sendfile(out, in, NULL, 4096), 0);
+ close(out);
+ close(in);
+}
+
+static inline void
+litest_install_model_quirks(void)
+{
+ litest_copy_file(UDEV_COMMON_RULE_FILE, LIBINPUT_UDEV_RULES_FILE, NULL);
+ litest_copy_file(UDEV_COMMON_HWDB_FILE,
+ LIBINPUT_UDEV_HWDB_FILE,
+ "#################################################################\n"
+ "# WARNING: REMOVE THIS FILE\n"
+ "# This is the run-time hwdb file for the libinput test suite and\n"
+ "# should be removed on exit. If the test-suite is not currently \n"
+ "# running, remove this file and update your hwdb: \n"
+ "# sudo udevadm hwdb --update\n"
+ "#################################################################\n\n");
+}
+
+static inline void
+litest_remove_model_quirks(void)
+{
+ unlink(UDEV_COMMON_RULE_FILE);
+ unlink(UDEV_COMMON_HWDB_FILE);
+}
+
static char *
litest_init_udev_rules(struct litest_test_device *dev)
{
int rc;
FILE *f;
- char *path;
-
- if (!dev->udev_rule)
- return NULL;
+ char *path = NULL;
rc = mkdir(UDEV_RULES_D, 0755);
if (rc == -1 && errno != EEXIST)
ck_abort_msg("Failed to create udev rules directory (%s)\n",
strerror(errno));
+ rc = mkdir(UDEV_HWDB_D, 0755);
+ if (rc == -1 && errno != EEXIST)
+ ck_abort_msg("Failed to create udev hwdb directory (%s)\n",
+ strerror(errno));
+
+ litest_install_model_quirks();
+
+ /* device-specific udev rules */
+ if (!dev->udev_rule)
+ goto out;
+
rc = xasprintf(&path,
"%s/%s%s.rules",
UDEV_RULES_D,
@@ -911,6 +979,7 @@ litest_init_udev_rules(struct litest_test_device *dev)
litest_assert_int_ge(fputs(dev->udev_rule, f), 0);
fclose(f);
+out:
litest_reload_udev_rules();
return path;
@@ -950,6 +1019,7 @@ litest_create(enum litest_device_type which,
if ((*dev)->create) {
(*dev)->create(d);
if (abs_override || events_override) {
+ litest_remove_model_quirks();
if (udev_file)
unlink(udev_file);
litest_abort_msg("Custom create cannot be overridden");
@@ -1128,6 +1198,7 @@ litest_delete_device(struct litest_device *d)
return;
if (d->udev_rule_file) {
+ litest_remove_model_quirks();
unlink(d->udev_rule_file);
free(d->udev_rule_file);
d->udev_rule_file = NULL;
diff --git a/test/touchpad.c b/test/touchpad.c
index 692698ce..1e5e97bd 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -2153,6 +2153,53 @@ START_TEST(clickpad_click_n_drag)
}
END_TEST
+START_TEST(clickpad_finger_pin)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libevdev *evdev = dev->evdev;
+ const struct input_absinfo *abs;
+
+ abs = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
+ ck_assert_notnull(abs);
+ if (abs->resolution == 0)
+ return;
+
+ litest_drain_events(li);
+
+ /* make sure the movement generates pointer events when
+ not pinned */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1);
+ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1);
+ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_button_click(dev, BTN_LEFT, true);
+ litest_drain_events(li);
+
+ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1);
+ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1);
+ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1);
+
+ litest_assert_empty_queue(li);
+
+ litest_button_click(dev, BTN_LEFT, false);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+
+ /* still pinned after release */
+ litest_touch_move_to(dev, 0, 50, 50, 52, 52, 10, 1);
+ litest_touch_move_to(dev, 0, 52, 52, 48, 48, 10, 1);
+ litest_touch_move_to(dev, 0, 48, 48, 50, 50, 10, 1);
+
+ litest_assert_empty_queue(li);
+
+ /* move to unpin */
+ litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 1);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+}
+END_TEST
+
START_TEST(clickpad_softbutton_left)
{
struct litest_device *dev = litest_current_device();
@@ -5144,6 +5191,7 @@ litest_setup_tests(void)
litest_add("touchpad:click", touchpad_btn_left, LITEST_TOUCHPAD|LITEST_BUTTON, LITEST_CLICKPAD);
litest_add("touchpad:click", clickpad_btn_left, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:click", clickpad_click_n_drag, LITEST_CLICKPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:click", clickpad_finger_pin, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:softbutton", clickpad_softbutton_left, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
litest_add("touchpad:softbutton", clickpad_softbutton_right, LITEST_CLICKPAD, LITEST_APPLE_CLICKPAD);
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 048e5cc6..7442f828 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -16,6 +16,13 @@
# Sort by brand, model
##########################################
+# Apple
+##########################################
+libinput:touchpad:input:b0003v05ACp*
+libinput:touchpad:input:b0005v05ACp*
+ LIBINPUT_MODEL_APPLE_TOUCHPAD=1
+
+##########################################
# Google
##########################################
@@ -23,18 +30,18 @@
# extrapolated from the chromiumos touchad-tests repo
# https://chromium.googlesource.com/chromiumos/platform/touchpad-tests
libinput:name:Cypress APA Trackpad (cyapa):dmi:*pnFalco:pvr*
-libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*Mario*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Butterfly*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Peppy*:
-libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*ZGB*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Parrot*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Leon*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Falco*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Wolf*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*svn*GOOGLE*:pn*Link*:
-libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*Alex*:
-libinput:name:Cypress APA Trackpad (cyapa):dmi:*svn*SAMSUNG*:pn*Lumpy*:
-libinput:name:Atmel maXTouch Touchpad:dmi:*svn*GOOGLE*:pn*Samus*:
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*Mario*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Butterfly*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Peppy*
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*ZGB*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*pn*Parrot*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Leon*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Falco*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*bvn*coreboot*:pn*Wolf*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*svn*GOOGLE*:pn*Link*
+libinput:name:SynPS/2 Synaptics TouchPad:dmi:*pn*Alex*
+libinput:name:Cypress APA Trackpad (cyapa):dmi:*svn*SAMSUNG*:pn*Lumpy*
+libinput:name:Atmel maXTouch Touchpad:dmi:*svn*GOOGLE*:pn*Samus*
LIBINPUT_MODEL_CHROMEBOOK=1
##########################################
@@ -64,3 +71,9 @@ libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnSystem76*pvrgalu1*
# Kudu Professional
libinput:name:SynPS/2 Synaptics TouchPad:dmi:*svnSystem76*pvrkudp1*
LIBINPUT_MODEL_SYSTEM76_KUDU=1
+
+##########################################
+# Wacom
+##########################################
+libinput:touchpad:input:b0003v056Ap*
+ LIBINPUT_MODEL_WACOM_TOUCHPAD=1
diff --git a/udev/90-libinput-model-quirks.rules b/udev/90-libinput-model-quirks.rules
index 4b988748..79b9b36f 100644
--- a/udev/90-libinput-model-quirks.rules
+++ b/udev/90-libinput-model-quirks.rules
@@ -13,8 +13,9 @@ KERNEL!="event*", GOTO="libinput_model_quirks_end"
# hwdb matches:
#
-# libinput:<modalias>
-IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:", \
+# libinput:touchpad:<modalias>
+ENV{ID_INPUT_TOUCHPAD}=="1", \
+ IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:touchpad:", \
GOTO="libinput_model_quirks_end"
# libinput:name:<name>:dmi:<dmi string>
@@ -22,4 +23,5 @@ KERNELS=="input*", \
IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:$attr{[dmi/id]modalias}'", \
GOTO="libinput_model_quirks_end"
+
LABEL="libinput_model_quirks_end"