summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2015-07-14 13:13:11 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2015-07-14 13:13:11 +1000
commit9e705bf33400a6cc3ccd0fa0fc80c243a7aeb3b4 (patch)
tree7a381c7c2063e978821f7849e604b54d9528e0d9
parentbfce05db05265a7ebac5d050a8ff1beb7e81543d (diff)
parent8658ff159d416b6a567acb2aaf72b27887ad8576 (diff)
Merge branch 'master' into tablet-support
-rw-r--r--configure.ac10
-rw-r--r--doc/device-configuration-via-udev.dox14
-rw-r--r--doc/scrolling.dox6
-rw-r--r--doc/touchpad-tap-state-machine.svg18
-rw-r--r--src/evdev-mt-touchpad-buttons.c94
-rw-r--r--src/evdev-mt-touchpad-edge-scroll.c24
-rw-r--r--src/evdev-mt-touchpad-gestures.c46
-rw-r--r--src/evdev-mt-touchpad-tap.c60
-rw-r--r--src/evdev-mt-touchpad.c139
-rw-r--r--src/evdev-mt-touchpad.h9
-rw-r--r--src/evdev.c79
-rw-r--r--src/libinput-util.c30
-rw-r--r--src/libinput-util.h2
-rw-r--r--test/Makefile.am68
-rw-r--r--test/device.c6
-rw-r--r--test/litest-device-alps-dualpoint.c (renamed from test/litest-alps-dualpoint.c)0
-rw-r--r--test/litest-device-alps-semi-mt.c (renamed from test/litest-alps-semi-mt.c)0
-rw-r--r--test/litest-device-atmel-hover.c (renamed from test/litest-atmel-hover.c)0
-rw-r--r--test/litest-device-bcm5974.c (renamed from test/litest-bcm5974.c)19
-rw-r--r--test/litest-device-elantech-touchpad.c121
-rw-r--r--test/litest-device-generic-singletouch.c (renamed from test/litest-generic-singletouch.c)0
-rw-r--r--test/litest-device-keyboard-razer-blackwidow.c (renamed from test/litest-keyboard-razer-blackwidow.c)0
-rw-r--r--test/litest-device-keyboard.c (renamed from test/litest-keyboard.c)0
-rw-r--r--test/litest-device-logitech-trackball.c (renamed from test/litest-logitech-trackball.c)0
-rw-r--r--test/litest-device-magic-trackpad.c110
-rw-r--r--test/litest-device-mouse-low-dpi.c (renamed from test/litest-mouse-low-dpi.c)0
-rw-r--r--test/litest-device-mouse-roccat.c (renamed from test/litest-mouse-roccat.c)0
-rw-r--r--test/litest-device-mouse.c (renamed from test/litest-mouse.c)0
-rw-r--r--test/litest-device-ms-surface-cover.c (renamed from test/litest-ms-surface-cover.c)0
-rw-r--r--test/litest-device-nexus4-touch-screen.c (renamed from test/litest-nexus4-touch-screen.c)0
-rw-r--r--test/litest-device-protocol-a-touch-screen.c (renamed from test/litest-protocol-a-touch-screen.c)0
-rw-r--r--test/litest-device-qemu-usb-tablet.c (renamed from test/litest-qemu-usb-tablet.c)0
-rw-r--r--test/litest-device-synaptics-hover.c (renamed from test/litest-synaptics-hover.c)0
-rw-r--r--test/litest-device-synaptics-st.c (renamed from test/litest-synaptics-st.c)0
-rw-r--r--test/litest-device-synaptics-t440.c (renamed from test/litest-synaptics-t440.c)19
-rw-r--r--test/litest-device-synaptics-x1-carbon-3rd.c (renamed from test/litest-synaptics-x1-carbon-3rd.c)19
-rw-r--r--test/litest-device-synaptics.c (renamed from test/litest-synaptics.c)19
-rw-r--r--test/litest-device-touch-screen.c (renamed from test/litest-touch-screen.c)0
-rw-r--r--test/litest-device-trackpoint.c (renamed from test/litest-trackpoint.c)0
-rw-r--r--test/litest-device-vmware-virtual-usb-mouse.c (renamed from test/litest-vmware-virtual-usb-mouse.c)0
-rw-r--r--test/litest-device-wacom-bamboo-tablet.c (renamed from test/litest-wacom-bamboo-tablet.c)0
-rw-r--r--test/litest-device-wacom-cintiq-tablet.c (renamed from test/litest-wacom-cintiq-tablet.c)0
-rw-r--r--test/litest-device-wacom-intuos-finger.c (renamed from test/litest-wacom-intuos-finger.c)0
-rw-r--r--test/litest-device-wacom-intuos-tablet.c (renamed from test/litest-wacom-intuos-tablet.c)0
-rw-r--r--test/litest-device-wacom-isdv4-tablet.c (renamed from test/litest-wacom-isdv4-tablet.c)0
-rw-r--r--test/litest-device-wacom-touch.c (renamed from test/litest-wacom-touch.c)0
-rw-r--r--test/litest-device-waltop-tablet.c (renamed from test/litest-waltop-tablet.c)0
-rw-r--r--test/litest-device-wheel-only.c (renamed from test/litest-wheel-only.c)0
-rw-r--r--test/litest-device-xen-virtual-pointer.c (renamed from test/litest-xen-virtual-pointer.c)0
-rw-r--r--test/litest-int.h6
-rw-r--r--test/litest.c28
-rw-r--r--test/litest.h12
-rw-r--r--test/misc.c47
-rw-r--r--test/touchpad.c843
-rw-r--r--test/udev.c5
-rw-r--r--udev/.gitignore2
-rw-r--r--udev/80-libinput-device-groups.rules.in (renamed from udev/80-libinput-device-groups.rules)2
-rw-r--r--udev/90-libinput-model-quirks.hwdb7
-rw-r--r--udev/90-libinput-model-quirks.rules.in (renamed from udev/90-libinput-model-quirks.rules)14
-rw-r--r--udev/Makefile.am22
-rw-r--r--udev/libinput-model-quirks.c116
61 files changed, 1732 insertions, 284 deletions
diff --git a/configure.ac b/configure.ac
index 66d64c87..553c857c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -194,6 +194,12 @@ AM_CONDITIONAL(HAVE_VALGRIND, [test "x$VALGRIND" != "x"])
AM_CONDITIONAL(BUILD_TESTS, [test "x$build_tests" = "xyes"])
AM_CONDITIONAL(BUILD_DOCS, [test "x$build_documentation" = "xyes"])
+# Used by the udev rules so we can use callouts during testing without
+# installing everything first. Default is the empty string so the installed
+# rule will use udev's default path. Override is in udev/Makefile.am
+AC_SUBST(UDEV_TEST_PATH, "")
+AC_PATH_PROG(SED, [sed])
+
AC_CONFIG_FILES([Makefile
doc/Makefile
doc/libinput.doxygen
@@ -202,7 +208,9 @@ AC_CONFIG_FILES([Makefile
src/libinput-version.h
test/Makefile
tools/Makefile
- udev/Makefile])
+ udev/Makefile
+ udev/80-libinput-device-groups.rules
+ udev/90-libinput-model-quirks.rules])
AC_CONFIG_FILES([test/symbols-leak-test],
[chmod +x test/symbols-leak-test])
AC_OUTPUT
diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index e38b93f6..85c5c9c9 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -67,6 +67,10 @@ to normalize them.
<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
model_specific_configuration for details.
</dd>
+<dt>LIBINPUT_ATTR_*</dt>
+<dd><b>This prefix is reserved as private API, do not use.</b>. See @ref
+model_specific_configuration for details.
+</dd>
</dl>
Below is an example udev rule to assign "seat1" to a device from vendor
@@ -103,13 +107,13 @@ ENV{ID_MODEL_ID}=="034b", ENV{ID_INPUT_TOUCHPAD}="", ENV{ID_INPUT_TABLET}="1"
@section model_specific_configuration Model-specific configuration
-libinput reserves the property prefix <b>LIBINPUT_MODEL_</b> for
-model-specific configuration. <b>This prefix is reserved as private API, do
-not use.</b>
+libinput reserves the property prefixes <b>LIBINPUT_MODEL_</b> and
+<b>LIBINPUT_ATTR_*</b> for model-specific configuration. <b>These prefixes
+are reserved as private API, do not use.</b>
-The effect of this property may be to enable or disable certain
+The effect of these properties may be to enable or disable certain
features on a specific device or set of devices, to change configuration
-defaults or any other reason. The effects of setting this property, the
+defaults or any other reason. The effects of setting these properties, the
format of the property and the value of the property are subject to change
at any time.
diff --git a/doc/scrolling.dox b/doc/scrolling.dox
index 1ecd0333..658fe4b6 100644
--- a/doc/scrolling.dox
+++ b/doc/scrolling.dox
@@ -55,10 +55,8 @@ scroll).
Due to the layout of the edges, diagonal scrolling is not possible. The
behavior of edge scrolling using both edges at the same time is undefined.
-Edge scrolling conflicts with @ref clickpad_softbuttons and is
-not usually available on clickpads. See
-http://who-t.blogspot.com.au/2015/03/why-libinput-doesnt-support-edge.html
-for details.
+Edge scrolling overlaps with @ref clickpad_softbuttons. A physical click on
+a clickpad ends scrolling.
@section button_scrolling On-Button scrolling
diff --git a/doc/touchpad-tap-state-machine.svg b/doc/touchpad-tap-state-machine.svg
index 89c34fa0..b1c5995b 100644
--- a/doc/touchpad-tap-state-machine.svg
+++ b/doc/touchpad-tap-state-machine.svg
@@ -1179,5 +1179,23 @@
[Not supported by viewer]</text>
</switch>
</g>
+ <path d="M 2095.54 407 C 2098.34 403.86 2102.32 402.05 2106.52 402 L 2140.49 402 C 2144.69 402.05 2148.67 403.86 2151.47 407 L 2171.45 430 C 2172.01 431.28 2172.01 432.72 2171.45 434 L 2151.47 457 C 2148.67 460.14 2144.69 461.95 2140.49 462 L 2106.52 462 C 2102.32 461.95 2098.34 460.14 2095.54 457 L 2075.56 434 C 2075 432.72 2075 431.28 2075.56 430 L 2095.54 407 Z" fill="#ff99cc" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="2123.25" y="435.75">
+ thumb</text>
+ </g>
+ <path d="M 1801.42 332 L 2068.92 415.05" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2073.93 416.61 L 2066.21 417.88 L 2068.92 415.05 L 2068.28 411.19 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2152.5 488.7 C 2168.62 494.91 2186.38 494.91 2202.5 488.7 C 2218.62 482.5 2236.38 482.5 2252.5 488.7 L 2252.5 541.28 C 2236.38 535.08 2218.62 535.08 2202.5 541.28 C 2186.38 547.49 2168.62 547.49 2152.5 541.28 L 2152.5 488.7 Z" fill="#ffd966" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/>
+ <g fill="#000000" font-family="Helvetica" text-anchor="middle" font-size="12px">
+ <text x="2202.25" y="518.75">
+ TOUCH_DEAD</text>
+ </g>
+ <path d="M 2152.05 462 L 2167.18 477.89" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2170.8 481.69 L 2163.43 479.03 L 2167.18 477.89 L 2168.5 474.21 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2217.81 547.5 L 2324.65 774.24" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2326.89 778.99 L 2320.74 774.15 L 2324.65 774.24 L 2327.07 771.16 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 1959.61 577 L 2084.82 466.22" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
+ <path d="M 2088.75 462.74 L 2085.83 470 L 2084.82 466.22 L 2081.19 464.76 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="none"/>
</g>
</svg>
diff --git a/src/evdev-mt-touchpad-buttons.c b/src/evdev-mt-touchpad-buttons.c
index f0857747..d9c469a4 100644
--- a/src/evdev-mt-touchpad-buttons.c
+++ b/src/evdev-mt-touchpad-buttons.c
@@ -525,20 +525,19 @@ tp_init_softbuttons(struct tp_dispatch *tp,
absinfo_y = device->abs.absinfo_y;
xoffset = absinfo_x->minimum,
- yoffset = absinfo_y->minimum;
+ yoffset = absinfo_y->minimum,
yres = absinfo_y->resolution;
width = device->abs.dimensions.x;
height = device->abs.dimensions.y;
- /* button height: 10mm or 15% of the touchpad height,
+ /* button height: 10mm or 15% orf the touchpad height,
whichever is smaller */
- if (!device->abs.fake_resolution && (height * 0.15/yres) > 10) {
+ if ((height * 0.15)/yres > 10) {
tp->buttons.bottom_area.top_edge =
- absinfo_y->maximum - 10 * yres;
+ absinfo_y->maximum - 10 * yres;
} else {
tp->buttons.bottom_area.top_edge = height * .85 + yoffset;
}
-
tp->buttons.bottom_area.rightbutton_left_edge = width/2 + xoffset;
}
@@ -547,7 +546,7 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
struct evdev_device *device,
double topbutton_size_mult)
{
- int width, height;
+ int width;
const struct input_absinfo *absinfo_x, *absinfo_y;
int xoffset, yoffset;
int yres;
@@ -559,7 +558,6 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
yoffset = absinfo_y->minimum;
yres = absinfo_y->resolution;
width = device->abs.dimensions.x;
- height = device->abs.dimensions.y;
if (tp->buttons.has_topbuttons) {
/* T440s has the top button line 5mm from the top, event
@@ -567,14 +565,8 @@ tp_init_top_softbuttons(struct tp_dispatch *tp,
top - which maps to 15%. We allow the caller to enlarge the
area using a multiplier for the touchpad disabled case. */
double topsize_mm = 10 * topbutton_size_mult;
- double topsize_pct = .15 * topbutton_size_mult;
- if (!device->abs.fake_resolution) {
- tp->buttons.top_area.bottom_edge =
- yoffset + topsize_mm * yres;
- } else {
- tp->buttons.top_area.bottom_edge = height * topsize_pct + yoffset;
- }
+ tp->buttons.top_area.bottom_edge = yoffset + topsize_mm * yres;
tp->buttons.top_area.rightbutton_left_edge = width * .58 + xoffset;
tp->buttons.top_area.leftbutton_right_edge = width * .42 + xoffset;
} else {
@@ -713,8 +705,6 @@ tp_init_buttons(struct tp_dispatch *tp,
{
struct libinput *libinput = tp_libinput_context(tp);
struct tp_touch *t;
- int width, height;
- double diagonal;
const struct input_absinfo *absinfo_x, *absinfo_y;
tp->buttons.is_clickpad = libevdev_has_property(device->evdev,
@@ -738,19 +728,9 @@ tp_init_buttons(struct tp_dispatch *tp,
absinfo_x = device->abs.absinfo_x;
absinfo_y = device->abs.absinfo_y;
- /* 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 double BUTTON_MOTION_MAGIC = 0.007;
- width = device->abs.dimensions.x;
- height = device->abs.dimensions.y;
- 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;
- }
+ /* pinned-finger motion threshold, see tp_unpin_finger. */
+ 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;
@@ -825,33 +805,53 @@ tp_check_clickfinger_distance(struct tp_dispatch *tp,
struct tp_touch *t2)
{
double x, y;
+ int within_distance = 0;
+ int xres, yres;
+ int bottom_threshold;
if (!t1 || !t2)
return 0;
+ if (t1->is_thumb || t2->is_thumb)
+ return 0;
+
x = abs(t1->point.x - t2->point.x);
y = abs(t1->point.y - t2->point.y);
- /* no resolution, so let's assume they're close enough together if
- they're within 30% of the touchpad width or height */
- if (tp->device->abs.fake_resolution) {
- int w, h;
- w = tp->device->abs.dimensions.x;
- h = tp->device->abs.dimensions.y;
+ xres = tp->device->abs.absinfo_x->resolution;
+ yres = tp->device->abs.absinfo_y->resolution;
+ x /= xres;
+ y /= yres;
- return (x < w * 0.3 && y < h * 0.3) ? 1 : 0;
- } else {
- /* maximum spread is 40mm horiz, 20mm vert. Anything wider than that
- * is probably a gesture. The y spread is small so we ignore clicks
- * with thumbs at the bottom of the touchpad while the pointer
- * moving finger is still on the pad */
+ /* maximum horiz spread is 40mm horiz, 30mm vert, anything wider
+ * than that is probably a gesture. */
+ if (x > 40 || y > 30)
+ goto out;
- x /= tp->device->abs.absinfo_x->resolution;
- y /= tp->device->abs.absinfo_y->resolution;
+ within_distance = 1;
- return (x < 40 && y < 20) ? 1 : 0;
- }
+ /* if y spread is <= 20mm, they're definitely together. */
+ if (y <= 20)
+ goto out;
+
+ /* if they're vertically spread between 20-40mm, they're not
+ * together if:
+ * - the touchpad's vertical size is >50mm, anything smaller is
+ * unlikely to have a thumb resting on it
+ * - and one of the touches is in the bottom 20mm of the touchpad
+ * and the other one isn't
+ */
+ if (tp->device->abs.dimensions.y/yres < 50)
+ goto out;
+
+ bottom_threshold = tp->device->abs.absinfo_y->maximum - 20 * yres;
+ if ((t1->point.y > bottom_threshold) !=
+ (t2->point.y > bottom_threshold))
+ within_distance = 0;
+
+out:
+ return within_distance;
}
static uint32_t
@@ -941,6 +941,10 @@ tp_notify_clickpadbutton(struct tp_dispatch *tp,
if (tp->device->suspended)
return 0;
+ /* A button click always terminates edge scrolling, even if we
+ * don't end up sending a button event. */
+ tp_edge_scroll_stop_events(tp, time);
+
/*
* If the user has requested clickfinger replace the button chosen
* by the softbutton code with one based on the number of fingers.
diff --git a/src/evdev-mt-touchpad-edge-scroll.c b/src/evdev-mt-touchpad-edge-scroll.c
index 9a9d3b84..ade55e03 100644
--- a/src/evdev-mt-touchpad-edge-scroll.c
+++ b/src/evdev-mt-touchpad-edge-scroll.c
@@ -34,7 +34,6 @@
#define CASE_RETURN_STRING(a) case a: return #a
-#define DEFAULT_SCROLL_LOCK_TIMEOUT 300 /* ms */
/* Use a reasonably large threshold until locked into scrolling mode, to
avoid accidentally locking in scrolling mode when trying to use the entire
touchpad to move the pointer. The user can wait for the timeout to trigger
@@ -92,6 +91,23 @@ tp_touch_get_edge(struct tp_dispatch *tp, struct tp_touch *t)
return edge;
}
+static inline void
+tp_edge_scroll_set_timer(struct tp_dispatch *tp,
+ struct tp_touch *t)
+{
+ const int DEFAULT_SCROLL_LOCK_TIMEOUT = 300; /* ms */
+ /* if we use software buttons, we disable timeout-based
+ * edge scrolling. A finger resting on the button areas is
+ * likely there to trigger a button event.
+ */
+ if (tp->buttons.click_method ==
+ LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS)
+ return;
+
+ libinput_timer_set(&t->scroll.timer,
+ t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
+}
+
static void
tp_edge_scroll_set_state(struct tp_dispatch *tp,
struct tp_touch *t,
@@ -108,8 +124,7 @@ tp_edge_scroll_set_state(struct tp_dispatch *tp,
case EDGE_SCROLL_TOUCH_STATE_EDGE_NEW:
t->scroll.edge = tp_touch_get_edge(tp, t);
t->scroll.initial = t->point;
- libinput_timer_set(&t->scroll.timer,
- t->millis + DEFAULT_SCROLL_LOCK_TIMEOUT);
+ tp_edge_scroll_set_timer(tp, t);
break;
case EDGE_SCROLL_TOUCH_STATE_EDGE:
break;
@@ -290,8 +305,7 @@ tp_edge_scroll_init(struct tp_dispatch *tp, struct evdev_device *device)
default:
/* For elantech and synaptics, note for lenovo #40 series,
* e.g. the T440s min/max are the absolute edges, not the
- * recommended ones as usual with synaptics. But these are
- * clickpads, so N/A.
+ * recommended ones as usual with synaptics.
*/
edge_width = width * .04;
edge_height = height * .054;
diff --git a/src/evdev-mt-touchpad-gestures.c b/src/evdev-mt-touchpad-gestures.c
index cd853ecf..768d3ec3 100644
--- a/src/evdev-mt-touchpad-gestures.c
+++ b/src/evdev-mt-touchpad-gestures.c
@@ -32,6 +32,20 @@
#define DEFAULT_GESTURE_SWITCH_TIMEOUT 100 /* ms */
#define DEFAULT_GESTURE_2FG_SCROLL_TIMEOUT 1000 /* ms */
+#define CASE_RETURN_STRING(a) case a: return #a
+
+static inline const char*
+gesture_state_to_str(enum tp_gesture_2fg_state state)
+{
+ switch (state) {
+ CASE_RETURN_STRING(GESTURE_2FG_STATE_NONE);
+ CASE_RETURN_STRING(GESTURE_2FG_STATE_UNKNOWN);
+ CASE_RETURN_STRING(GESTURE_2FG_STATE_SCROLL);
+ CASE_RETURN_STRING(GESTURE_2FG_STATE_PINCH);
+ }
+ return NULL;
+}
+
static struct normalized_coords
tp_get_touches_delta(struct tp_dispatch *tp, bool average)
{
@@ -380,6 +394,8 @@ tp_gesture_twofinger_handle_state_pinch(struct tp_dispatch *tp, uint64_t time)
static void
tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time)
{
+ enum tp_gesture_2fg_state oldstate = tp->gesture.twofinger_state;
+
if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_NONE)
tp->gesture.twofinger_state =
tp_gesture_twofinger_handle_state_none(tp, time);
@@ -395,6 +411,11 @@ tp_gesture_post_twofinger(struct tp_dispatch *tp, uint64_t time)
if (tp->gesture.twofinger_state == GESTURE_2FG_STATE_PINCH)
tp->gesture.twofinger_state =
tp_gesture_twofinger_handle_state_pinch(tp, time);
+
+ log_debug(tp_libinput_context(tp),
+ "gesture state: %s → %s\n",
+ gesture_state_to_str(oldstate),
+ gesture_state_to_str(tp->gesture.twofinger_state));
}
static void
@@ -525,11 +546,34 @@ tp_gesture_handle_state(struct tp_dispatch *tp, uint64_t time)
{
unsigned int active_touches = 0;
struct tp_touch *t;
+ uint32_t old_thumb_mask, thumb_mask = 0;
+ int i = 0;
- tp_for_each_touch(tp, t)
+ tp_for_each_touch(tp, t) {
if (tp_touch_active(tp, t))
active_touches++;
+ if (t->is_thumb)
+ thumb_mask |= 1 << i;
+ i++;
+ }
+
+ old_thumb_mask = tp->gesture.thumb_mask;
+ tp->gesture.thumb_mask = thumb_mask;
+
+ /* active touches does not include thumb touches, need to count those
+ * separately, in a bitmask.
+ * then, if the finger count changes and/or the thumb count changes
+ * -> cancel gesture.
+ */
+ if (thumb_mask != old_thumb_mask) {
+ /* if a thumb is detected during a gesture, that gesture is
+ * cancelled and the user effectively needs to restart. we
+ * could be smarter, but the complexity isn't worth it */
+ tp_gesture_cancel(tp, time);
+ return;
+ }
+
if (active_touches != tp->gesture.finger_count) {
/* If all fingers are lifted immediately end the gesture */
if (active_touches == 0) {
diff --git a/src/evdev-mt-touchpad-tap.c b/src/evdev-mt-touchpad-tap.c
index 7f241de5..9bbf6b88 100644
--- a/src/evdev-mt-touchpad-tap.c
+++ b/src/evdev-mt-touchpad-tap.c
@@ -47,6 +47,7 @@ enum tap_event {
TAP_EVENT_RELEASE,
TAP_EVENT_BUTTON,
TAP_EVENT_TIMEOUT,
+ TAP_EVENT_THUMB,
};
/*****************************************
@@ -93,6 +94,7 @@ tap_event_to_str(enum tap_event event)
CASE_RETURN_STRING(TAP_EVENT_RELEASE);
CASE_RETURN_STRING(TAP_EVENT_TIMEOUT);
CASE_RETURN_STRING(TAP_EVENT_BUTTON);
+ CASE_RETURN_STRING(TAP_EVENT_THUMB);
}
return NULL;
}
@@ -166,6 +168,10 @@ tp_tap_idle_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ log_bug_libinput(libinput,
+ "invalid tap event, no fingers down, no thumb\n");
+ break;
}
}
@@ -193,6 +199,12 @@ tp_tap_touch_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ tp->tap.state = TAP_STATE_IDLE;
+ t->tap.is_thumb = true;
+ t->tap.state = TAP_TOUCH_STATE_DEAD;
+ tp_tap_clear_timer(tp);
+ break;
}
}
@@ -216,6 +228,11 @@ tp_tap_hold_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ tp->tap.state = TAP_STATE_IDLE;
+ t->tap.is_thumb = true;
+ t->tap.state = TAP_TOUCH_STATE_DEAD;
+ break;
}
}
@@ -244,6 +261,8 @@ tp_tap_tapped_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -275,6 +294,8 @@ tp_tap_touch2_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -299,6 +320,8 @@ tp_tap_touch2_hold_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -328,6 +351,8 @@ tp_tap_touch3_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -351,6 +376,8 @@ tp_tap_touch3_hold_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_BUTTON:
tp->tap.state = TAP_STATE_DEAD;
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -375,6 +402,8 @@ tp_tap_dragging_or_doubletap_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -408,6 +437,8 @@ tp_tap_dragging_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -433,6 +464,8 @@ tp_tap_dragging_wait_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -459,6 +492,8 @@ tp_tap_dragging_tap_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -484,6 +519,8 @@ tp_tap_dragging2_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_DEAD;
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -518,6 +555,8 @@ tp_tap_multitap_handle_event(struct tp_dispatch *tp,
tp->tap.state = TAP_STATE_IDLE;
tp_tap_clear_timer(tp);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -556,6 +595,8 @@ tp_tap_multitap_down_handle_event(struct tp_dispatch *tp,
tp_tap_notify(tp, time, 1, LIBINPUT_BUTTON_STATE_RELEASED);
tp_tap_clear_timer(tp);
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -576,6 +617,8 @@ tp_tap_dead_handle_event(struct tp_dispatch *tp,
case TAP_EVENT_TIMEOUT:
case TAP_EVENT_BUTTON:
break;
+ case TAP_EVENT_THUMB:
+ break;
}
}
@@ -691,7 +734,20 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
tp->queued & TOUCHPAD_EVENT_BUTTON_PRESS)
t->tap.state = TAP_TOUCH_STATE_DEAD;
+ /* If a touch was considered thumb for tapping once, we
+ * ignore it for the rest of lifetime */
+ if (t->tap.is_thumb)
+ continue;
+
if (t->state == TOUCH_BEGIN) {
+ /* The simple version: if a touch is a thumb on
+ * begin we ignore it. All other thumb touches
+ * follow the normal tap state for now */
+ if (t->is_thumb) {
+ t->tap.is_thumb = true;
+ continue;
+ }
+
t->tap.state = TAP_TOUCH_STATE_TOUCH;
t->tap.initial = t->point;
tp_tap_handle_event(tp, t, TAP_EVENT_TOUCH, time);
@@ -718,6 +774,10 @@ tp_tap_handle_state(struct tp_dispatch *tp, uint64_t time)
}
tp_tap_handle_event(tp, t, TAP_EVENT_MOTION, time);
+ } else if (tp->tap.state != TAP_STATE_IDLE &&
+ t->is_thumb &&
+ !t->tap.is_thumb) {
+ tp_tap_handle_event(tp, t, TAP_EVENT_THUMB, time);
}
}
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index f13873b5..ce0203af 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -212,6 +212,8 @@ tp_begin_touch(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
t->millis = time;
tp->nfingers_down++;
t->palm.time = time;
+ t->is_thumb = false;
+ t->tap.is_thumb = false;
assert(tp->nfingers_down >= 1);
}
@@ -314,6 +316,9 @@ tp_process_absolute(struct tp_dispatch *tp,
else
tp_end_sequence(tp, t, time);
break;
+ case ABS_MT_PRESSURE:
+ t->pressure = e->value;
+ break;
}
}
@@ -461,6 +466,7 @@ tp_touch_active(struct tp_dispatch *tp, struct tp_touch *t)
return (t->state == TOUCH_BEGIN || t->state == TOUCH_UPDATE) &&
t->palm.state == PALM_NONE &&
!t->pinned.is_pinned &&
+ !t->is_thumb &&
tp_button_touch_active(tp, t) &&
tp_edge_scroll_touch_active(tp, t);
}
@@ -496,8 +502,7 @@ tp_palm_detect_dwt(struct tp_dispatch *tp, struct tp_touch *t, uint64_t time)
return 1;
} else if (!tp->dwt.keyboard_active &&
t->state == TOUCH_UPDATE &&
- t->palm.state == PALM_TYPING)
- {
+ t->palm.state == PALM_TYPING) {
/* If a touch has started before the first or after the last
key press, release it on timeout. Benefit: a palm rested
while typing on the touchpad will be ignored, but a touch
@@ -604,6 +609,33 @@ out:
}
static void
+tp_thumb_detect(struct tp_dispatch *tp, struct tp_touch *t)
+{
+ /* once a thumb, always a thumb */
+ if (!tp->thumb.detect_thumbs || t->is_thumb)
+ return;
+
+ /* Note: a thumb at the edge of the touchpad won't trigger the
+ * threshold, the surface areas is usually too small.
+ */
+ if (t->pressure < tp->thumb.threshold)
+ return;
+
+ t->is_thumb = true;
+
+ /* now what? we marked it as thumb, so:
+ *
+ * - pointer motion must ignore this touch
+ * - clickfinger must ignore this touch for finger count
+ * - software buttons are unaffected
+ * - edge scrolling unaffected
+ * - gestures: cancel
+ * - tapping: honour thumb on begin, ignore it otherwise for now,
+ * this gets a tad complicated otherwise
+ */
+}
+
+static void
tp_unhover_abs_distance(struct tp_dispatch *tp, uint64_t time)
{
struct tp_touch *t;
@@ -721,6 +753,7 @@ tp_process_state(struct tp_dispatch *tp, uint64_t time)
if (!t->dirty)
continue;
+ tp_thumb_detect(tp, t);
tp_palm_detect(tp, t, time);
tp_motion_hysteresis(tp, t);
@@ -1319,17 +1352,8 @@ tp_init_accel(struct tp_dispatch *tp, double diagonal)
* and y resolution, so that a circle on the
* touchpad does not turn into an elipse on the screen.
*/
- if (!tp->device->abs.fake_resolution) {
- tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
- tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
- } else {
- /*
- * For touchpads where the driver does not provide resolution, fall
- * back to scaling motion events based on the diagonal size in units.
- */
- tp->accel.x_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
- tp->accel.y_scale_coeff = DEFAULT_ACCEL_NUMERATOR / diagonal;
- }
+ tp->accel.x_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_x;
+ tp->accel.y_scale_coeff = (DEFAULT_MOUSE_DPI/25.4) / res_y;
switch (tp->device->model) {
case EVDEV_MODEL_LENOVO_X230:
@@ -1351,14 +1375,11 @@ tp_scroll_config_scroll_method_get_methods(struct libinput_device *device)
{
struct evdev_device *evdev = (struct evdev_device*)device;
struct tp_dispatch *tp = (struct tp_dispatch*)evdev->dispatch;
- uint32_t methods = LIBINPUT_CONFIG_SCROLL_NO_SCROLL;
+ uint32_t methods = LIBINPUT_CONFIG_SCROLL_EDGE;
if (tp->ntouches >= 2)
methods |= LIBINPUT_CONFIG_SCROLL_2FG;
- if (!tp->buttons.is_clickpad)
- methods |= LIBINPUT_CONFIG_SCROLL_EDGE;
-
return methods;
}
@@ -1482,6 +1503,30 @@ tp_init_sendevents(struct tp_dispatch *tp,
}
static int
+tp_init_thumb(struct tp_dispatch *tp)
+{
+ struct evdev_device *device = tp->device;
+ const struct input_absinfo *abs;
+
+ abs = libevdev_get_abs_info(device->evdev, ABS_MT_PRESSURE);
+ if (!abs)
+ return 0;
+
+ if (abs->maximum - abs->minimum < 255)
+ return 0;
+
+ /* The touchpads we looked at so far have a clear thumb threshold of
+ * ~100, you don't reach that with a normal finger interaction.
+ * Note: "thumb" means massive touch that should not interact, not
+ * "using the tip of my thumb for a pinch gestures".
+ */
+ tp->thumb.threshold = 100;
+ tp->thumb.detect_thumbs = true;
+
+ return 0;
+}
+
+static int
tp_sanity_check(struct tp_dispatch *tp,
struct evdev_device *device)
{
@@ -1506,11 +1551,49 @@ error:
}
static int
+tp_init_default_resolution(struct tp_dispatch *tp,
+ struct evdev_device *device)
+{
+ const int touchpad_width_mm = 69, /* 1 under palm detection */
+ touchpad_height_mm = 50;
+ int xres, yres;
+
+ if (!device->abs.fake_resolution)
+ return 0 ;
+
+ /* we only get here if
+ * - the touchpad provides no resolution
+ * - the udev hwdb didn't override the resoluion
+ * - no ATTR_SIZE_HINT is set
+ *
+ * The majority of touchpads that triggers all these conditions
+ * are old ones, so let's assume a small touchpad size and assume
+ * that.
+ */
+ log_info(tp_libinput_context(tp),
+ "%s: no resolution or size hints, assuming a size of %dx%dmm\n",
+ device->devname,
+ touchpad_width_mm,
+ touchpad_height_mm);
+
+ xres = device->abs.dimensions.x/touchpad_width_mm;
+ yres = device->abs.dimensions.y/touchpad_height_mm;
+ libevdev_set_abs_resolution(device->evdev, ABS_X, xres);
+ libevdev_set_abs_resolution(device->evdev, ABS_Y, yres);
+ libevdev_set_abs_resolution(device->evdev, ABS_MT_POSITION_X, xres);
+ libevdev_set_abs_resolution(device->evdev, ABS_MT_POSITION_Y, yres);
+ device->abs.fake_resolution = 0;
+
+ return 0;
+}
+
+static int
tp_init(struct tp_dispatch *tp,
struct evdev_device *device)
{
int width, height;
double diagonal;
+ int res_x, res_y;
tp->base.interface = &tp_interface;
tp->device = device;
@@ -1518,9 +1601,14 @@ tp_init(struct tp_dispatch *tp,
if (tp_sanity_check(tp, device) != 0)
return -1;
+ if (tp_init_default_resolution(tp, device) != 0)
+ return -1;
+
if (tp_init_slots(tp, device) != 0)
return -1;
+ res_x = tp->device->abs.absinfo_x->resolution;
+ res_y = tp->device->abs.absinfo_y->resolution;
width = device->abs.dimensions.x;
height = device->abs.dimensions.y;
diagonal = sqrt(width*width + height*height);
@@ -1529,18 +1617,8 @@ tp_init(struct tp_dispatch *tp,
EV_ABS,
ABS_MT_DISTANCE);
- 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;
- }
+ tp->hysteresis_margin.x = res_x/2;
+ tp->hysteresis_margin.y = res_y/2;
if (tp_init_accel(tp, diagonal) != 0)
return -1;
@@ -1563,6 +1641,9 @@ tp_init(struct tp_dispatch *tp,
if (tp_init_gesture(tp) != 0)
return -1;
+ if (tp_init_thumb(tp) != 0)
+ return -1;
+
device->seat_caps |= EVDEV_DEVICE_POINTER;
return 0;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index df8be94f..eda17a99 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -141,9 +141,11 @@ struct tp_touch {
enum touch_state state;
bool has_ended; /* TRACKING_ID == -1 */
bool dirty;
+ bool is_thumb;
struct device_coords point;
uint64_t millis;
int distance; /* distance == 0 means touch */
+ int pressure;
struct {
struct device_coords samples[TOUCHPAD_HISTORY_LENGTH];
@@ -173,6 +175,7 @@ struct tp_touch {
struct {
enum tp_tap_touch_state state;
struct device_coords initial;
+ bool is_thumb;
} tap;
struct {
@@ -234,6 +237,7 @@ struct tp_dispatch {
double prev_scale;
double angle;
struct device_float_coords center;
+ uint32_t thumb_mask;
} gesture;
struct {
@@ -317,6 +321,11 @@ struct tp_dispatch {
uint64_t keyboard_last_press_time;
} dwt;
+
+ struct {
+ bool detect_thumbs;
+ int threshold;
+ } thumb;
};
#define tp_for_each_touch(_tp, _t) \
diff --git a/src/evdev.c b/src/evdev.c
index b5cf3332..40fc7d57 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1552,19 +1552,35 @@ evdev_read_model(struct evdev_device *device)
return m->model;
}
-/* Return 1 if the given resolutions have been set, or 0 otherwise */
+static inline int
+evdev_read_attr_size_prop(struct evdev_device *device,
+ size_t *size_x,
+ size_t *size_y)
+{
+ struct udev_device *udev;
+ const char *size_prop;
+
+ udev = device->udev_device;
+ size_prop = udev_device_get_property_value(udev,
+ "LIBINPUT_ATTR_SIZE_HINT");
+ if (!size_prop)
+ return false;
+
+ return parse_dimension_property(size_prop, size_x, size_y);
+}
+
+/* Return 1 if the device is set to the fake resolution or 0 otherwise */
static inline int
evdev_fix_abs_resolution(struct evdev_device *device,
unsigned int xcode,
- unsigned int ycode,
- int xresolution,
- int yresolution)
+ unsigned int ycode)
{
struct libinput *libinput = device->base.seat->libinput;
struct libevdev *evdev = device->evdev;
const struct input_absinfo *absx, *absy;
- struct input_absinfo fixed;
- int rc = 0;
+ size_t widthmm = 0, heightmm = 0;
+ int xres = EVDEV_FAKE_RESOLUTION,
+ yres = EVDEV_FAKE_RESOLUTION;
if (!(xcode == ABS_X && ycode == ABS_Y) &&
!(xcode == ABS_MT_POSITION_X && ycode == ABS_MT_POSITION_Y)) {
@@ -1574,37 +1590,28 @@ evdev_fix_abs_resolution(struct evdev_device *device,
return 0;
}
- if (xresolution == 0 || yresolution == 0 ||
- (xresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution) ||
- (yresolution == EVDEV_FAKE_RESOLUTION && xresolution != yresolution)) {
- log_bug_libinput(libinput,
- "Invalid x/y resolutions %d/%d\n",
- xresolution, yresolution);
- return 0;
- }
-
absx = libevdev_get_abs_info(evdev, xcode);
absy = libevdev_get_abs_info(evdev, ycode);
- if (absx->resolution == 0 || absx->resolution == EVDEV_FAKE_RESOLUTION) {
- fixed = *absx;
- fixed.resolution = xresolution;
- /* libevdev_set_abs_info() changes the absinfo we already
- have a pointer to, no need to fetch it again */
- libevdev_set_abs_info(evdev, xcode, &fixed);
- rc = 1;
- }
+ if (absx->resolution != 0 || absy->resolution != 0)
+ return 0;
- if (absy->resolution == 0 || absy->resolution == EVDEV_FAKE_RESOLUTION) {
- fixed = *absy;
- fixed.resolution = yresolution;
- /* libevdev_set_abs_info() changes the absinfo we already
- have a pointer to, no need to fetch it again */
- libevdev_set_abs_info(evdev, ycode, &fixed);
- rc = 1;
+ /* Note: we *do not* override resolutions if provided by the kernel.
+ * If a device needs this, add it to 60-evdev.hwdb. The libinput
+ * property is only for general size hints where we can make
+ * educated guesses but don't know better.
+ */
+ if (evdev_read_attr_size_prop(device, &widthmm, &heightmm)) {
+ xres = (absx->maximum - absx->minimum)/widthmm;
+ yres = (absy->maximum - absy->minimum)/heightmm;
}
- return rc;
+ /* libevdev_set_abs_resolution() changes the absinfo we already
+ have a pointer to, no need to fetch it again */
+ libevdev_set_abs_resolution(evdev, xcode, xres);
+ libevdev_set_abs_resolution(evdev, ycode, yres);
+
+ return xres == EVDEV_FAKE_RESOLUTION;
}
static enum evdev_device_udev_tags
@@ -1775,9 +1782,7 @@ evdev_configure_mt_device(struct evdev_device *device)
if (evdev_fix_abs_resolution(device,
ABS_MT_POSITION_X,
- ABS_MT_POSITION_Y,
- EVDEV_FAKE_RESOLUTION,
- EVDEV_FAKE_RESOLUTION))
+ ABS_MT_POSITION_Y))
device->abs.fake_resolution = 1;
device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_MT_POSITION_X);
@@ -1902,11 +1907,7 @@ evdev_configure_device(struct evdev_device *device)
evdev_fix_android_mt(device);
if (libevdev_has_event_code(evdev, EV_ABS, ABS_X)) {
- if (evdev_fix_abs_resolution(device,
- ABS_X,
- ABS_Y,
- EVDEV_FAKE_RESOLUTION,
- EVDEV_FAKE_RESOLUTION))
+ if (evdev_fix_abs_resolution(device, ABS_X, ABS_Y))
device->abs.fake_resolution = 1;
device->abs.absinfo_x = libevdev_get_abs_info(evdev, ABS_X);
device->abs.absinfo_y = libevdev_get_abs_info(evdev, ABS_Y);
diff --git a/src/libinput-util.c b/src/libinput-util.c
index 3a9c8db5..a383fa17 100644
--- a/src/libinput-util.c
+++ b/src/libinput-util.c
@@ -234,3 +234,33 @@ parse_trackpoint_accel_property(const char *prop)
return accel;
}
+
+/**
+ * Parses a simple dimension string in the form of "10x40". The two
+ * numbers must be positive integers in decimal notation.
+ * On success, the two numbers are stored in w and h. On failure, w and h
+ * are unmodified.
+ *
+ * @param prop The value of the property
+ * @param w Returns the first component of the dimension
+ * @param h Returns the second component of the dimension
+ * @return true on success, false otherwise
+ */
+bool
+parse_dimension_property(const char *prop, size_t *w, size_t *h)
+{
+ int x, y;
+
+ if (!prop)
+ return false;
+
+ if (sscanf(prop, "%dx%d", &x, &y) != 2)
+ return false;
+
+ if (x < 0 || y < 0)
+ return false;
+
+ *w = (size_t)x;
+ *h = (size_t)y;
+ return true;
+}
diff --git a/src/libinput-util.h b/src/libinput-util.h
index 0ad550f1..32409a6e 100644
--- a/src/libinput-util.h
+++ b/src/libinput-util.h
@@ -28,6 +28,7 @@
#include <unistd.h>
#include <math.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
@@ -321,6 +322,7 @@ enum ratelimit_state ratelimit_test(struct ratelimit *r);
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);
+bool parse_dimension_property(const char *prop, size_t *width, size_t *height);
static inline double
vector_length(double x, double y)
diff --git a/test/Makefile.am b/test/Makefile.am
index e0b46496..902e5ce2 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -13,42 +13,44 @@ noinst_LTLIBRARIES = liblitest.la
liblitest_la_SOURCES = \
litest.h \
litest-int.h \
- litest-alps-semi-mt.c \
- litest-alps-dualpoint.c \
- litest-atmel-hover.c \
- litest-bcm5974.c \
- litest-generic-singletouch.c \
- litest-keyboard.c \
- litest-keyboard-razer-blackwidow.c \
- litest-logitech-trackball.c \
- litest-nexus4-touch-screen.c \
- litest-mouse.c \
- litest-mouse-roccat.c \
- litest-mouse-low-dpi.c \
- litest-ms-surface-cover.c \
- litest-protocol-a-touch-screen.c \
- litest-qemu-usb-tablet.c \
- litest-synaptics.c \
- litest-synaptics-hover.c \
- litest-synaptics-st.c \
- litest-synaptics-t440.c \
- litest-synaptics-x1-carbon-3rd.c \
- litest-trackpoint.c \
- litest-touch-screen.c \
- litest-wacom-bamboo-tablet.c \
- litest-wacom-cintiq-tablet.c \
- litest-wacom-intuos-tablet.c \
- litest-wacom-isdv4-tablet.c \
- litest-wacom-touch.c \
- litest-wacom-intuos-finger.c \
- litest-waltop-tablet.c \
- litest-wheel-only.c \
- litest-xen-virtual-pointer.c \
- litest-vmware-virtual-usb-mouse.c \
+ litest-device-alps-semi-mt.c \
+ litest-device-alps-dualpoint.c \
+ litest-device-atmel-hover.c \
+ litest-device-bcm5974.c \
+ litest-device-elantech-touchpad.c \
+ litest-device-generic-singletouch.c \
+ litest-device-keyboard.c \
+ litest-device-keyboard-razer-blackwidow.c \
+ litest-device-logitech-trackball.c \
+ litest-device-nexus4-touch-screen.c \
+ litest-device-magic-trackpad.c \
+ litest-device-mouse.c \
+ litest-device-mouse-roccat.c \
+ litest-device-mouse-low-dpi.c \
+ litest-device-ms-surface-cover.c \
+ litest-device-protocol-a-touch-screen.c \
+ litest-device-qemu-usb-tablet.c \
+ litest-device-synaptics.c \
+ litest-device-synaptics-hover.c \
+ litest-device-synaptics-st.c \
+ litest-device-synaptics-t440.c \
+ litest-device-synaptics-x1-carbon-3rd.c \
+ litest-device-trackpoint.c \
+ litest-device-touch-screen.c \
+ litest-device-wacom-bamboo-tablet.c \
+ litest-device-wacom-cintiq-tablet.c \
+ litest-device-wacom-intuos-tablet.c \
+ litest-device-wacom-isdv4-tablet.c \
+ litest-device-wacom-touch.c \
+ litest-device-wacom-intuos-finger.c \
+ litest-device-waltop-tablet.c \
+ litest-device-wheel-only.c \
+ litest-device-xen-virtual-pointer.c \
+ litest-device-vmware-virtual-usb-mouse.c \
litest.c
liblitest_la_LIBADD = $(top_builddir)/src/libinput-util.la
liblitest_la_CFLAGS = $(AM_CFLAGS) \
- -DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.rules\"" \
+ -DLIBINPUT_UDEV_RULES_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks-litest.rules\"" \
-DLIBINPUT_UDEV_HWDB_FILE="\"$(abs_top_srcdir)/udev/90-libinput-model-quirks.hwdb\""
if HAVE_LIBUNWIND
liblitest_la_LIBADD += $(LIBUNWIND_LIBS) -ldl
diff --git a/test/device.c b/test/device.c
index 25fccd1f..f2651366 100644
--- a/test/device.c
+++ b/test/device.c
@@ -70,7 +70,8 @@ START_TEST(device_sendevents_config_touchpad)
expected = LIBINPUT_CONFIG_SEND_EVENTS_DISABLED;
/* The wacom devices in the test suite are external */
- if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM)
+ if (libevdev_get_id_vendor(dev->evdev) != VENDOR_ID_WACOM &&
+ libevdev_get_id_bustype(dev->evdev) != BUS_BLUETOOTH)
expected |=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE;
@@ -89,7 +90,8 @@ START_TEST(device_sendevents_config_touchpad_superset)
uint32_t modes;
/* The wacom devices in the test suite are external */
- if (libevdev_get_id_vendor(dev->evdev) == 0x56a) /* wacom */
+ if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM ||
+ libevdev_get_id_bustype(dev->evdev) == BUS_BLUETOOTH)
return;
device = dev->libinput_device;
diff --git a/test/litest-alps-dualpoint.c b/test/litest-device-alps-dualpoint.c
index 8e42f9a8..8e42f9a8 100644
--- a/test/litest-alps-dualpoint.c
+++ b/test/litest-device-alps-dualpoint.c
diff --git a/test/litest-alps-semi-mt.c b/test/litest-device-alps-semi-mt.c
index 720eaeb5..720eaeb5 100644
--- a/test/litest-alps-semi-mt.c
+++ b/test/litest-device-alps-semi-mt.c
diff --git a/test/litest-atmel-hover.c b/test/litest-device-atmel-hover.c
index 1691549f..1691549f 100644
--- a/test/litest-atmel-hover.c
+++ b/test/litest-device-atmel-hover.c
diff --git a/test/litest-bcm5974.c b/test/litest-device-bcm5974.c
index f84d1d00..cbf2a74c 100644
--- a/test/litest-bcm5974.c
+++ b/test/litest-device-bcm5974.c
@@ -37,11 +37,12 @@ static void litest_bcm5974_setup(void)
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
@@ -50,15 +51,31 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
+static int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+ switch (evcode) {
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ *value = 30;
+ return 0;
+ }
+ return 1;
+}
+
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
+
+ .get_axis_default = get_axis_default,
};
static struct input_absinfo absinfo[] = {
diff --git a/test/litest-device-elantech-touchpad.c b/test/litest-device-elantech-touchpad.c
new file mode 100644
index 00000000..abf58d1c
--- /dev/null
+++ b/test/litest-device-elantech-touchpad.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void
+litest_elantech_touchpad_setup(void)
+{
+ struct litest_device *d = litest_create_device(LITEST_ELANTECH_TOUCHPAD);
+ litest_set_current_device(d);
+}
+
+static struct input_event down[] = {
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+ { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+ switch (evcode) {
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ *value = 30;
+ return 0;
+ }
+ return 1;
+}
+
+static struct litest_device_interface interface = {
+ .touch_down_events = down,
+ .touch_move_events = move,
+
+ .get_axis_default = get_axis_default,
+};
+
+static struct input_id input_id = {
+ .bustype = 0x11,
+ .vendor = 0x2,
+ .product = 0xe,
+};
+
+static int events[] = {
+ EV_KEY, BTN_LEFT,
+ EV_KEY, BTN_RIGHT,
+ EV_KEY, BTN_TOOL_FINGER,
+ EV_KEY, BTN_TOUCH,
+ EV_KEY, BTN_TOOL_DOUBLETAP,
+ EV_KEY, BTN_TOOL_TRIPLETAP,
+ EV_KEY, BTN_TOOL_QUADTAP,
+ INPUT_PROP_MAX, INPUT_PROP_POINTER,
+ -1, -1,
+};
+
+static struct input_absinfo absinfo[] = {
+ { ABS_X, 0, 1280, 0, 0, 0 },
+ { ABS_Y, 0, 704, 0, 0, 0 },
+ { ABS_PRESSURE, 0, 255, 0, 0, 0 },
+ { ABS_TOOL_WIDTH, 0, 15, 0, 0, 0 },
+ { ABS_MT_SLOT, 0, 1, 0, 0, 0 },
+ { ABS_MT_POSITION_X, 0, 1280, 0, 0, 0 },
+ { ABS_MT_POSITION_Y, 0, 704, 0, 0, 0 },
+ { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
+ { .value = -1 }
+};
+
+struct litest_test_device litest_elantech_touchpad_device = {
+ .type = LITEST_ELANTECH_TOUCHPAD,
+ .features = LITEST_TOUCHPAD | LITEST_BUTTON,
+ .shortname = "elantech",
+ .setup = litest_elantech_touchpad_setup,
+ .interface = &interface,
+
+ .name = "ETPS/2 Elantech Touchpad",
+ .id = &input_id,
+ .events = events,
+ .absinfo = absinfo,
+};
diff --git a/test/litest-generic-singletouch.c b/test/litest-device-generic-singletouch.c
index a10e0b18..a10e0b18 100644
--- a/test/litest-generic-singletouch.c
+++ b/test/litest-device-generic-singletouch.c
diff --git a/test/litest-keyboard-razer-blackwidow.c b/test/litest-device-keyboard-razer-blackwidow.c
index 7e9823a5..7e9823a5 100644
--- a/test/litest-keyboard-razer-blackwidow.c
+++ b/test/litest-device-keyboard-razer-blackwidow.c
diff --git a/test/litest-keyboard.c b/test/litest-device-keyboard.c
index e8b9c136..e8b9c136 100644
--- a/test/litest-keyboard.c
+++ b/test/litest-device-keyboard.c
diff --git a/test/litest-logitech-trackball.c b/test/litest-device-logitech-trackball.c
index c3b59870..c3b59870 100644
--- a/test/litest-logitech-trackball.c
+++ b/test/litest-device-logitech-trackball.c
diff --git a/test/litest-device-magic-trackpad.c b/test/litest-device-magic-trackpad.c
new file mode 100644
index 00000000..588d6f5a
--- /dev/null
+++ b/test/litest-device-magic-trackpad.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "litest.h"
+#include "litest-int.h"
+
+static void litest_magicpad_setup(void)
+{
+ struct litest_device *d = litest_create_device(LITEST_MAGIC_TRACKPAD);
+ litest_set_current_device(d);
+}
+
+static struct input_event down[] = {
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 272 },
+ { .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 400 },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static struct input_event move[] = {
+ { .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_TOUCH_MAJOR, .value = 272 },
+ { .type = EV_ABS, .code = ABS_MT_TOUCH_MINOR, .value = 400 },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
+ { .type = -1, .code = -1 },
+};
+
+static struct litest_device_interface interface = {
+ .touch_down_events = down,
+ .touch_move_events = move,
+};
+
+static struct input_absinfo absinfo[] = {
+ { ABS_X, -2909, 3167, 4, 0, 46 },
+ { ABS_Y, -2456, 2565, 4, 0, 45 },
+ { ABS_MT_SLOT, 0, 15, 0, 0, 0 },
+ { ABS_MT_POSITION_X, -2909, 3167, 4, 0, 46 },
+ { ABS_MT_POSITION_Y, -2456, 2565, 4, 0, 45 },
+ { ABS_MT_ORIENTATION, -31, 32, 1, 0, 0 },
+ { ABS_MT_TOUCH_MAJOR, 0, 1020, 4, 0, 0 },
+ { ABS_MT_TOUCH_MINOR, 0, 1020, 4, 0, 0 },
+ { ABS_MT_TRACKING_ID, 0, 65535, 0, 0, 0 },
+ { .value = -1 },
+};
+
+static struct input_id input_id = {
+ .bustype = 0x5,
+ .vendor = 0x5ac,
+ .product = 0x30e,
+};
+
+static int events[] = {
+ EV_KEY, BTN_LEFT,
+ EV_KEY, BTN_TOOL_FINGER,
+ EV_KEY, BTN_TOOL_QUINTTAP,
+ EV_KEY, BTN_TOUCH,
+ EV_KEY, BTN_TOOL_DOUBLETAP,
+ EV_KEY, BTN_TOOL_TRIPLETAP,
+ EV_KEY, BTN_TOOL_QUADTAP,
+ INPUT_PROP_MAX, INPUT_PROP_BUTTONPAD,
+ -1, -1
+};
+
+struct litest_test_device litest_magicpad_device = {
+ .type = LITEST_MAGIC_TRACKPAD,
+ .features = LITEST_TOUCHPAD | LITEST_CLICKPAD |
+ LITEST_BUTTON | LITEST_APPLE_CLICKPAD,
+ .shortname = "magic trackpad",
+ .setup = litest_magicpad_setup,
+ .interface = &interface,
+
+ .name = "Apple Wireless Trackpad",
+ .id = &input_id,
+ .events = events,
+ .absinfo = absinfo,
+};
diff --git a/test/litest-mouse-low-dpi.c b/test/litest-device-mouse-low-dpi.c
index dccf40fa..dccf40fa 100644
--- a/test/litest-mouse-low-dpi.c
+++ b/test/litest-device-mouse-low-dpi.c
diff --git a/test/litest-mouse-roccat.c b/test/litest-device-mouse-roccat.c
index 013374e0..013374e0 100644
--- a/test/litest-mouse-roccat.c
+++ b/test/litest-device-mouse-roccat.c
diff --git a/test/litest-mouse.c b/test/litest-device-mouse.c
index bae98632..bae98632 100644
--- a/test/litest-mouse.c
+++ b/test/litest-device-mouse.c
diff --git a/test/litest-ms-surface-cover.c b/test/litest-device-ms-surface-cover.c
index fdd96818..fdd96818 100644
--- a/test/litest-ms-surface-cover.c
+++ b/test/litest-device-ms-surface-cover.c
diff --git a/test/litest-nexus4-touch-screen.c b/test/litest-device-nexus4-touch-screen.c
index d1930053..d1930053 100644
--- a/test/litest-nexus4-touch-screen.c
+++ b/test/litest-device-nexus4-touch-screen.c
diff --git a/test/litest-protocol-a-touch-screen.c b/test/litest-device-protocol-a-touch-screen.c
index e3b67c4c..e3b67c4c 100644
--- a/test/litest-protocol-a-touch-screen.c
+++ b/test/litest-device-protocol-a-touch-screen.c
diff --git a/test/litest-qemu-usb-tablet.c b/test/litest-device-qemu-usb-tablet.c
index b9a6523d..b9a6523d 100644
--- a/test/litest-qemu-usb-tablet.c
+++ b/test/litest-device-qemu-usb-tablet.c
diff --git a/test/litest-synaptics-hover.c b/test/litest-device-synaptics-hover.c
index 2cc9b725..2cc9b725 100644
--- a/test/litest-synaptics-hover.c
+++ b/test/litest-device-synaptics-hover.c
diff --git a/test/litest-synaptics-st.c b/test/litest-device-synaptics-st.c
index d2bd1aee..d2bd1aee 100644
--- a/test/litest-synaptics-st.c
+++ b/test/litest-device-synaptics-st.c
diff --git a/test/litest-synaptics-t440.c b/test/litest-device-synaptics-t440.c
index 4247a0ce..fa561858 100644
--- a/test/litest-synaptics-t440.c
+++ b/test/litest-device-synaptics-t440.c
@@ -38,11 +38,12 @@ litest_synaptics_t440_setup(void)
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
@@ -51,15 +52,31 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
+static int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+ switch (evcode) {
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ *value = 30;
+ return 0;
+ }
+ return 1;
+}
+
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
+
+ .get_axis_default = get_axis_default,
};
static struct input_id input_id = {
diff --git a/test/litest-synaptics-x1-carbon-3rd.c b/test/litest-device-synaptics-x1-carbon-3rd.c
index bb50f4a1..2005c8c4 100644
--- a/test/litest-synaptics-x1-carbon-3rd.c
+++ b/test/litest-device-synaptics-x1-carbon-3rd.c
@@ -38,11 +38,12 @@ litest_synaptics_carbon3rd_setup(void)
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
@@ -51,15 +52,31 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
+static int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+ switch (evcode) {
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ *value = 30;
+ return 0;
+ }
+ return 1;
+}
+
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
+
+ .get_axis_default = get_axis_default,
};
static struct input_id input_id = {
diff --git a/test/litest-synaptics.c b/test/litest-device-synaptics.c
index c35ad3d5..4dcdebfd 100644
--- a/test/litest-synaptics.c
+++ b/test/litest-device-synaptics.c
@@ -38,11 +38,12 @@ litest_synaptics_clickpad_setup(void)
static struct input_event down[] = {
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
- { .type = EV_ABS, .code = ABS_PRESSURE, .value = 30 },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
@@ -51,15 +52,31 @@ static struct input_event move[] = {
{ .type = EV_ABS, .code = ABS_MT_SLOT, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_X, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = LITEST_AUTO_ASSIGN },
+ { .type = EV_ABS, .code = ABS_MT_PRESSURE, .value = LITEST_AUTO_ASSIGN },
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
{ .type = -1, .code = -1 },
};
+static int
+get_axis_default(struct litest_device *d, unsigned int evcode, int32_t *value)
+{
+ switch (evcode) {
+ case ABS_PRESSURE:
+ case ABS_MT_PRESSURE:
+ *value = 30;
+ return 0;
+ }
+ return 1;
+}
+
static struct litest_device_interface interface = {
.touch_down_events = down,
.touch_move_events = move,
+
+ .get_axis_default = get_axis_default,
};
static struct input_id input_id = {
diff --git a/test/litest-touch-screen.c b/test/litest-device-touch-screen.c
index e91458a2..e91458a2 100644
--- a/test/litest-touch-screen.c
+++ b/test/litest-device-touch-screen.c
diff --git a/test/litest-trackpoint.c b/test/litest-device-trackpoint.c
index 5d722495..5d722495 100644
--- a/test/litest-trackpoint.c
+++ b/test/litest-device-trackpoint.c
diff --git a/test/litest-vmware-virtual-usb-mouse.c b/test/litest-device-vmware-virtual-usb-mouse.c
index c92c566a..c92c566a 100644
--- a/test/litest-vmware-virtual-usb-mouse.c
+++ b/test/litest-device-vmware-virtual-usb-mouse.c
diff --git a/test/litest-wacom-bamboo-tablet.c b/test/litest-device-wacom-bamboo-tablet.c
index d21d4be0..d21d4be0 100644
--- a/test/litest-wacom-bamboo-tablet.c
+++ b/test/litest-device-wacom-bamboo-tablet.c
diff --git a/test/litest-wacom-cintiq-tablet.c b/test/litest-device-wacom-cintiq-tablet.c
index 0217f560..0217f560 100644
--- a/test/litest-wacom-cintiq-tablet.c
+++ b/test/litest-device-wacom-cintiq-tablet.c
diff --git a/test/litest-wacom-intuos-finger.c b/test/litest-device-wacom-intuos-finger.c
index acd6928e..acd6928e 100644
--- a/test/litest-wacom-intuos-finger.c
+++ b/test/litest-device-wacom-intuos-finger.c
diff --git a/test/litest-wacom-intuos-tablet.c b/test/litest-device-wacom-intuos-tablet.c
index e0e1d44b..e0e1d44b 100644
--- a/test/litest-wacom-intuos-tablet.c
+++ b/test/litest-device-wacom-intuos-tablet.c
diff --git a/test/litest-wacom-isdv4-tablet.c b/test/litest-device-wacom-isdv4-tablet.c
index c9d40e77..c9d40e77 100644
--- a/test/litest-wacom-isdv4-tablet.c
+++ b/test/litest-device-wacom-isdv4-tablet.c
diff --git a/test/litest-wacom-touch.c b/test/litest-device-wacom-touch.c
index e7da39c9..e7da39c9 100644
--- a/test/litest-wacom-touch.c
+++ b/test/litest-device-wacom-touch.c
diff --git a/test/litest-waltop-tablet.c b/test/litest-device-waltop-tablet.c
index 93ec739d..93ec739d 100644
--- a/test/litest-waltop-tablet.c
+++ b/test/litest-device-waltop-tablet.c
diff --git a/test/litest-wheel-only.c b/test/litest-device-wheel-only.c
index c5b9fb0c..c5b9fb0c 100644
--- a/test/litest-wheel-only.c
+++ b/test/litest-device-wheel-only.c
diff --git a/test/litest-xen-virtual-pointer.c b/test/litest-device-xen-virtual-pointer.c
index b4457c2b..b4457c2b 100644
--- a/test/litest-xen-virtual-pointer.c
+++ b/test/litest-device-xen-virtual-pointer.c
diff --git a/test/litest-int.h b/test/litest-int.h
index e6fcaabc..42c5474b 100644
--- a/test/litest-int.h
+++ b/test/litest-int.h
@@ -80,6 +80,12 @@ struct litest_device_interface {
void (*touch_up)(struct litest_device *d, unsigned int slot);
/**
+ * Default value for the given EV_ABS axis.
+ * @return 0 on success, nonzero otherwise
+ */
+ int (*get_axis_default)(struct litest_device *d, unsigned int code, int32_t *value);
+
+ /**
* Set of of events to execute on touch down, terminated by a .type
* and .code value of -1. If the event value is LITEST_AUTO_ASSIGN,
* it will be automatically assigned by the framework (valid for x,
diff --git a/test/litest.c b/test/litest.c
index 9e236456..c46ef6e4 100644
--- a/test/litest.c
+++ b/test/litest.c
@@ -360,6 +360,8 @@ extern struct litest_test_device litest_alps_dualpoint_device;
extern struct litest_test_device litest_mouse_low_dpi_device;
extern struct litest_test_device litest_generic_multitouch_screen_device;
extern struct litest_test_device litest_nexus4_device;
+extern struct litest_test_device litest_magicpad_device;
+extern struct litest_test_device litest_elantech_touchpad_device;
extern struct litest_test_device litest_waltop_tablet_device;
struct litest_test_device* devices[] = {
@@ -394,6 +396,8 @@ struct litest_test_device* devices[] = {
&litest_mouse_low_dpi_device,
&litest_generic_multitouch_screen_device,
&litest_nexus4_device,
+ &litest_magicpad_device,
+ &litest_elantech_touchpad_device,
&litest_waltop_tablet_device,
NULL,
};
@@ -1222,19 +1226,22 @@ litest_event(struct litest_device *d, unsigned int type,
litest_assert_int_eq(ret, 0);
}
-static int32_t
+static bool
axis_replacement_value(struct axis_replacement *axes,
- int32_t evcode)
+ int32_t evcode,
+ int32_t *value)
{
struct axis_replacement *axis = axes;
while (axis->evcode != -1) {
- if (axis->evcode == evcode)
- return axis->value;
+ if (axis->evcode == evcode) {
+ *value = axis->value;
+ return true;
+ }
axis++;
}
- return -1;
+ return false;
}
int
@@ -1269,8 +1276,13 @@ litest_auto_assign_value(struct litest_device *d,
value = touching ? 0 : 1;
break;
default:
- if (axes)
- value = axis_replacement_value(axes, ev->code);
+ value = -1;
+ if (!axes)
+ break;
+
+ if (!axis_replacement_value(axes, ev->code, &value) &&
+ d->interface->get_axis_default)
+ d->interface->get_axis_default(d, ev->code, &value);
break;
}
@@ -1466,7 +1478,7 @@ auto_assign_tablet_value(struct litest_device *d,
value = litest_scale(d, ABS_Y, y);
break;
default:
- value = axis_replacement_value(axes, ev->code);
+ axis_replacement_value(axes, ev->code, &value);
break;
}
diff --git a/test/litest.h b/test/litest.h
index dfc193a6..b552fd92 100644
--- a/test/litest.h
+++ b/test/litest.h
@@ -140,11 +140,13 @@ enum litest_device_type {
LITEST_MOUSE_LOW_DPI = -26,
LITEST_GENERIC_MULTITOUCH_SCREEN = -27,
LITEST_NEXUS4_TOUCH_SCREEN = -28,
- LITEST_WACOM_BAMBOO = -29,
- LITEST_WACOM_CINTIQ = -30,
- LITEST_WACOM_INTUOS = -31,
- LITEST_WACOM_ISDV4 = -32,
- LITEST_WALTOP = -33,
+ LITEST_MAGIC_TRACKPAD = -29,
+ LITEST_ELANTECH_TOUCHPAD = -30,
+ LITEST_WACOM_BAMBOO = -31,
+ LITEST_WACOM_CINTIQ = -32,
+ LITEST_WACOM_INTUOS = -33,
+ LITEST_WACOM_ISDV4 = -34,
+ LITEST_WALTOP = -35,
};
enum litest_device_feature {
diff --git a/test/misc.c b/test/misc.c
index b4b16bc0..09c30f3b 100644
--- a/test/misc.c
+++ b/test/misc.c
@@ -673,6 +673,52 @@ START_TEST(trackpoint_accel_parser)
}
END_TEST
+struct parser_test_dimension {
+ char *tag;
+ bool success;
+ int x, y;
+};
+
+START_TEST(dimension_prop_parser)
+{
+ struct parser_test_dimension tests[] = {
+ { "10x10", true, 10, 10 },
+ { "1x20", true, 1, 20 },
+ { "1x8000", true, 1, 8000 },
+ { "238492x428210", true, 238492, 428210 },
+ { "0x0", true, 0, 0 },
+ { "-10x10", false, 0, 0 },
+ { "-1", false, 0, 0 },
+ { "1x-99", false, 0, 0 },
+ { "0", false, 0, 0 },
+ { "100", false, 0, 0 },
+ { "", false, 0, 0 },
+ { "abd", false, 0, 0 },
+ { "xabd", false, 0, 0 },
+ { "0xaf", false, 0, 0 },
+ { "0x0x", true, 0, 0 },
+ { "x10", false, 0, 0 },
+ { NULL, false, 0, 0 }
+ };
+ int i;
+ size_t x, y;
+ bool success;
+
+ for (i = 0; tests[i].tag != NULL; i++) {
+ x = y = 0xad;
+ success = parse_dimension_property(tests[i].tag, &x, &y);
+ ck_assert(success == tests[i].success);
+ if (success) {
+ ck_assert_int_eq(x, tests[i].x);
+ ck_assert_int_eq(y, tests[i].y);
+ } else {
+ ck_assert_int_eq(x, 0xad);
+ ck_assert_int_eq(y, 0xad);
+ }
+ }
+}
+END_TEST
+
void
litest_setup_tests(void)
{
@@ -693,4 +739,5 @@ litest_setup_tests(void)
litest_add_no_device("misc:parser", dpi_parser);
litest_add_no_device("misc:parser", wheel_click_parser);
litest_add_no_device("misc:parser", trackpoint_accel_parser);
+ litest_add_no_device("misc:parser", dimension_prop_parser);
}
diff --git a/test/touchpad.c b/test/touchpad.c
index 1f11cfa6..12bceea3 100644
--- a/test/touchpad.c
+++ b/test/touchpad.c
@@ -32,6 +32,43 @@
#include "libinput-util.h"
#include "litest.h"
+static void
+enable_edge_scroll(struct litest_device *dev)
+{
+ enum libinput_config_status status, expected;
+ struct libinput_device *device = dev->libinput_device;
+
+ status = libinput_device_config_scroll_set_method(device,
+ LIBINPUT_CONFIG_SCROLL_EDGE);
+
+ expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
+ litest_assert_int_eq(status, expected);
+}
+
+static void
+enable_clickfinger(struct litest_device *dev)
+{
+ enum libinput_config_status status, expected;
+ struct libinput_device *device = dev->libinput_device;
+
+ status = libinput_device_config_click_set_method(device,
+ LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
+ expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
+ litest_assert_int_eq(status, expected);
+}
+
+static void
+enable_buttonareas(struct litest_device *dev)
+{
+ enum libinput_config_status status, expected;
+ struct libinput_device *device = dev->libinput_device;
+
+ status = libinput_device_config_click_set_method(device,
+ LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
+ expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
+ litest_assert_int_eq(status, expected);
+}
+
START_TEST(touchpad_1fg_motion)
{
struct litest_device *dev = litest_current_device();
@@ -179,11 +216,8 @@ START_TEST(touchpad_1fg_clickfinger)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
- enum libinput_config_status status;
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
@@ -207,11 +241,8 @@ START_TEST(touchpad_1fg_clickfinger_no_touch)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
- enum libinput_config_status status;
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
@@ -233,11 +264,8 @@ START_TEST(touchpad_2fg_clickfinger)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
- enum libinput_config_status status;
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
@@ -263,9 +291,16 @@ START_TEST(touchpad_2fg_clickfinger_distance)
{
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
+ double w, h;
+ bool small_touchpad = false;
+ unsigned int expected_button;
+
+ if (libinput_device_get_size(dev->libinput_device, &w, &h) == 0 &&
+ h < 50.0)
+ small_touchpad = true;
+
+ enable_clickfinger(dev);
- libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 50);
@@ -295,28 +330,99 @@ START_TEST(touchpad_2fg_clickfinger_distance)
litest_touch_up(dev, 0);
litest_touch_up(dev, 1);
+ /* if the touchpad is small enough, we expect all fingers to count
+ * for clickfinger */
+ if (small_touchpad)
+ expected_button = BTN_RIGHT;
+ else
+ expected_button = BTN_LEFT;
+
+ litest_assert_button_event(li,
+ expected_button,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ litest_assert_button_event(li,
+ expected_button,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+}
+END_TEST
+
+START_TEST(touchpad_2fg_clickfinger_bottom)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ /* this test is run for the T440s touchpad only, makes getting the
+ * mm correct easier */
+
+ libinput_device_config_click_set_method(dev->libinput_device,
+ LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
+ litest_drain_events(li);
+
+ /* one above, one below the magic line, vert spread ca 27mm */
+ litest_touch_down(dev, 0, 40, 60);
+ litest_touch_down(dev, 1, 60, 100);
+ litest_event(dev, EV_KEY, BTN_LEFT, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_event(dev, EV_KEY, BTN_LEFT, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_touch_up(dev, 0);
+ litest_touch_up(dev, 1);
+
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
litest_assert_button_event(li,
BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
+
+ litest_assert_empty_queue(li);
+
+ /* both below the magic line */
+ litest_touch_down(dev, 0, 40, 100);
+ litest_touch_down(dev, 1, 60, 95);
+ litest_event(dev, EV_KEY, BTN_LEFT, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_event(dev, EV_KEY, BTN_LEFT, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_touch_up(dev, 0);
+ litest_touch_up(dev, 1);
+
+ litest_assert_button_event(li,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ litest_assert_button_event(li,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+
+ /* one above, one below the magic line, vert spread 17mm */
+ litest_touch_down(dev, 0, 50, 75);
+ litest_touch_down(dev, 1, 55, 100);
+ litest_event(dev, EV_KEY, BTN_LEFT, 1);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_event(dev, EV_KEY, BTN_LEFT, 0);
+ litest_event(dev, EV_SYN, SYN_REPORT, 0);
+ litest_touch_up(dev, 0);
+ litest_touch_up(dev, 1);
+
+ litest_assert_button_event(li,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ litest_assert_button_event(li,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_RELEASED);
}
END_TEST
START_TEST(touchpad_clickfinger_to_area_method)
{
struct litest_device *dev = litest_current_device();
- enum libinput_config_status status;
struct libinput *li = dev->libinput;
litest_drain_events(li);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_buttonareas(dev);
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -329,14 +435,12 @@ START_TEST(touchpad_clickfinger_to_area_method)
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_RELEASED);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -355,25 +459,20 @@ END_TEST
START_TEST(touchpad_clickfinger_to_area_method_while_down)
{
struct litest_device *dev = litest_current_device();
- enum libinput_config_status status;
struct libinput *li = dev->libinput;
litest_drain_events(li);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_buttonareas(dev);
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
libinput_dispatch(li);
litest_assert_button_event(li, BTN_RIGHT,
LIBINPUT_BUTTON_STATE_PRESSED);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
@@ -386,7 +485,7 @@ START_TEST(touchpad_clickfinger_to_area_method_while_down)
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -405,17 +504,14 @@ END_TEST
START_TEST(touchpad_area_to_clickfinger_method)
{
struct litest_device *dev = litest_current_device();
- enum libinput_config_status status;
struct libinput *li = dev->libinput;
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -428,11 +524,9 @@ START_TEST(touchpad_area_to_clickfinger_method)
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_buttonareas(dev);
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -451,25 +545,20 @@ END_TEST
START_TEST(touchpad_area_to_clickfinger_method_while_down)
{
struct litest_device *dev = litest_current_device();
- enum libinput_config_status status;
struct libinput *li = dev->libinput;
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_clickfinger(dev);
litest_drain_events(li);
/* use bottom right corner to catch accidental softbutton right */
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_PRESSED);
- status = libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
- ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ enable_buttonareas(dev);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
@@ -479,7 +568,7 @@ START_TEST(touchpad_area_to_clickfinger_method_while_down)
litest_assert_button_event(li, BTN_LEFT,
LIBINPUT_BUTTON_STATE_RELEASED);
- litest_touch_down(dev, 0, 90, 90);
+ litest_touch_down(dev, 0, 95, 95);
litest_event(dev, EV_KEY, BTN_LEFT, 1);
litest_event(dev, EV_SYN, SYN_REPORT, 0);
litest_event(dev, EV_KEY, BTN_LEFT, 0);
@@ -521,8 +610,7 @@ START_TEST(clickpad_btn_left)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
- libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
+ enable_buttonareas(dev);
litest_drain_events(li);
@@ -597,9 +685,9 @@ START_TEST(clickpad_finger_pin)
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_touch_move_to(dev, 0, 50, 50, 51, 51, 10, 1);
+ litest_touch_move_to(dev, 0, 51, 51, 49, 49, 10, 1);
+ litest_touch_move_to(dev, 0, 49, 49, 50, 50, 10, 1);
litest_assert_empty_queue(li);
@@ -607,9 +695,9 @@ START_TEST(clickpad_finger_pin)
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_touch_move_to(dev, 0, 50, 50, 51, 51, 10, 1);
+ litest_touch_move_to(dev, 0, 51, 51, 49, 49, 10, 1);
+ litest_touch_move_to(dev, 0, 49, 49, 50, 50, 10, 1);
litest_assert_empty_queue(li);
@@ -1124,8 +1212,8 @@ START_TEST(clickpad_topsoftbuttons_clickfinger)
struct litest_device *dev = litest_current_device();
struct libinput *li = dev->libinput;
- libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
+ enable_clickfinger(dev);
+
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 5);
@@ -1169,10 +1257,9 @@ START_TEST(clickpad_topsoftbuttons_clickfinger_dev_disabled)
struct litest_device *trackpoint = litest_add_device(li,
LITEST_TRACKPOINT);
- libinput_device_config_click_set_method(dev->libinput_device,
- LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
libinput_device_config_send_events_set_mode(dev->libinput_device,
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
+ enable_clickfinger(dev);
litest_drain_events(li);
litest_touch_down(dev, 0, 90, 5);
@@ -1278,7 +1365,7 @@ START_TEST(touchpad_2fg_scroll_slow_distance)
litest_touch_down(dev, 0, 49, 50);
litest_touch_down(dev, 1, 51, 50);
- litest_touch_move_two_touches(dev, 49, 50, 51, 50, 0, y_move, 70, 10);
+ litest_touch_move_two_touches(dev, 49, 50, 51, 50, 0, y_move, 100, 10);
litest_touch_up(dev, 1);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@@ -1442,19 +1529,6 @@ START_TEST(touchpad_scroll_natural)
}
END_TEST
-static void
-enable_edge_scroll(struct litest_device *dev)
-{
- enum libinput_config_status status, expected;
- struct libinput_device *device = dev->libinput_device;
-
- status = libinput_device_config_scroll_set_method(device,
- LIBINPUT_CONFIG_SCROLL_EDGE);
-
- expected = LIBINPUT_CONFIG_STATUS_SUCCESS;
- litest_assert_int_eq(status, expected);
-}
-
START_TEST(touchpad_edge_scroll)
{
struct litest_device *dev = litest_current_device();
@@ -1497,6 +1571,42 @@ START_TEST(touchpad_edge_scroll)
}
END_TEST
+START_TEST(touchpad_scroll_defaults)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput_device *device = dev->libinput_device;
+ struct libevdev *evdev = dev->evdev;
+ enum libinput_config_scroll_method method, expected;
+ enum libinput_config_status status;
+
+ method = libinput_device_config_scroll_get_methods(device);
+ ck_assert(method & LIBINPUT_CONFIG_SCROLL_EDGE);
+ if (libevdev_get_num_slots(evdev) > 1)
+ ck_assert(method & LIBINPUT_CONFIG_SCROLL_2FG);
+
+ if (libevdev_get_num_slots(evdev) > 1)
+ expected = LIBINPUT_CONFIG_SCROLL_2FG;
+ else
+ expected = LIBINPUT_CONFIG_SCROLL_EDGE;
+
+ method = libinput_device_config_scroll_get_method(device);
+ ck_assert_int_eq(method, expected);
+ method = libinput_device_config_scroll_get_default_method(device);
+ ck_assert_int_eq(method, expected);
+
+ status = libinput_device_config_scroll_set_method(device,
+ LIBINPUT_CONFIG_SCROLL_EDGE);
+ ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ status = libinput_device_config_scroll_set_method(device,
+ LIBINPUT_CONFIG_SCROLL_2FG);
+
+ if (libevdev_get_num_slots(evdev) > 1)
+ ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
+ else
+ ck_assert_int_eq(status, LIBINPUT_CONFIG_STATUS_UNSUPPORTED);
+}
+END_TEST
+
START_TEST(touchpad_edge_scroll_timeout)
{
struct litest_device *dev = litest_current_device();
@@ -1524,7 +1634,7 @@ START_TEST(touchpad_edge_scroll_timeout)
litest_timeout_edgescroll();
libinput_dispatch(li);
- litest_touch_move_to(dev, 0, 99, 20, 99, 20 + y_movement, 60, 10);
+ litest_touch_move_to(dev, 0, 99, 20, 99, 20 + y_movement, 100, 10);
litest_touch_up(dev, 0);
libinput_dispatch(li);
@@ -1646,6 +1756,152 @@ START_TEST(touchpad_edge_scroll_no_2fg)
}
END_TEST
+START_TEST(touchpad_edge_scroll_into_buttonareas)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ enable_buttonareas(dev);
+ enable_edge_scroll(dev);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 40);
+ litest_touch_move_to(dev, 0, 99, 40, 99, 95, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+ /* in the button zone now, make sure we still get events */
+ litest_touch_move_to(dev, 0, 99, 95, 99, 100, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ /* and out of the zone again */
+ litest_touch_move_to(dev, 0, 99, 100, 99, 70, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ /* still out of the zone */
+ litest_touch_move_to(dev, 0, 99, 70, 99, 50, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+}
+END_TEST
+
+START_TEST(touchpad_edge_scroll_within_buttonareas)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+
+ enable_buttonareas(dev);
+ enable_edge_scroll(dev);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 20, 99);
+
+ /* within left button */
+ litest_touch_move_to(dev, 0, 20, 99, 40, 99, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ /* over to right button */
+ litest_touch_move_to(dev, 0, 40, 99, 60, 99, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ /* within right button */
+ litest_touch_move_to(dev, 0, 60, 99, 80, 99, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+}
+END_TEST
+
+START_TEST(touchpad_edge_scroll_buttonareas_click_stops_scroll)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ double val;
+
+ enable_buttonareas(dev);
+ enable_edge_scroll(dev);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 20, 95);
+ litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10, 5);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ litest_button_click(dev, BTN_LEFT, true);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ ptrev = litest_is_axis_event(event,
+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
+ LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
+ val = libinput_event_pointer_get_axis_value(ptrev,
+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
+ ck_assert(val == 0.0);
+ libinput_event_destroy(event);
+
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+
+ libinput_event_destroy(event);
+
+ /* within button areas -> no movement */
+ litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10, 0);
+ litest_assert_empty_queue(li);
+
+ litest_button_click(dev, BTN_LEFT, false);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+
+ litest_touch_up(dev, 0);
+}
+END_TEST
+
+START_TEST(touchpad_edge_scroll_clickfinger_click_stops_scroll)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ double val;
+
+ enable_clickfinger(dev);
+ enable_edge_scroll(dev);
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 20, 95);
+ litest_touch_move_to(dev, 0, 20, 95, 70, 95, 10, 5);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ litest_button_click(dev, BTN_LEFT, true);
+ libinput_dispatch(li);
+
+ event = libinput_get_event(li);
+ ptrev = litest_is_axis_event(event,
+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL,
+ LIBINPUT_POINTER_AXIS_SOURCE_FINGER);
+ val = libinput_event_pointer_get_axis_value(ptrev,
+ LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
+ ck_assert(val == 0.0);
+ libinput_event_destroy(event);
+
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_LEFT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+
+ libinput_event_destroy(event);
+
+ /* clickfinger releases pointer -> expect movement */
+ litest_touch_move_to(dev, 0, 70, 95, 90, 95, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_empty_queue(li);
+
+ litest_button_click(dev, BTN_LEFT, false);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+
+ litest_touch_up(dev, 0);
+}
+END_TEST
+
static int
touchpad_has_palm_detect_size(struct litest_device *dev)
{
@@ -2447,8 +2703,7 @@ START_TEST(touchpad_semi_mt_hover_down_up)
y -= 100;
}
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
litest_event(dev, EV_ABS, ABS_MT_SLOT, 0);
litest_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
@@ -2587,8 +2842,7 @@ START_TEST(touchpad_hover_down)
libinput_dispatch(li);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
/* go back to hover */
litest_hover_move_to(dev, 0, 50, 50, 70, 70, 10, 10);
@@ -2631,8 +2885,7 @@ START_TEST(touchpad_hover_down_hover_down)
litest_touch_move_to(dev, 0, 50, 50, 70, 70, 10, 10);
litest_touch_up(dev, 0);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
}
END_TEST
@@ -2666,8 +2919,7 @@ START_TEST(touchpad_hover_down_up)
litest_touch_up(dev, 0);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
}
END_TEST
@@ -2721,8 +2973,7 @@ START_TEST(touchpad_hover_2fg_1fg_down)
litest_touch_up(dev, 1);
litest_pop_event_frame(dev);;
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_MOTION);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
}
END_TEST
@@ -2806,8 +3057,7 @@ START_TEST(touchpad_trackpoint_mb_scroll)
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
litest_button_click(touchpad, BTN_2, false);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_AXIS);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
litest_delete_device(trackpoint);
}
@@ -2936,8 +3186,7 @@ START_TEST(touchpad_trackpoint_buttons_2fg_scroll)
litest_touch_move_to(touchpad, 0, 40, 30, 40, 70, 10, 0);
litest_touch_move_to(touchpad, 1, 60, 30, 60, 70, 10, 0);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_AXIS);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
while ((e = libinput_get_event(li))) {
ck_assert_int_eq(libinput_event_get_type(e),
@@ -2962,8 +3211,7 @@ START_TEST(touchpad_trackpoint_buttons_2fg_scroll)
*/
litest_touch_move_to(touchpad, 0, 40, 70, 40, 60, 10, 0);
litest_touch_move_to(touchpad, 1, 60, 70, 60, 60, 10, 0);
- litest_assert_only_typed_events(li,
- LIBINPUT_EVENT_POINTER_AXIS);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
litest_touch_move_to(touchpad, 0, 40, 60, 40, 30, 10, 0);
litest_touch_move_to(touchpad, 1, 60, 60, 60, 30, 10, 0);
@@ -3063,6 +3311,8 @@ has_disable_while_typing(struct litest_device *device)
{
if (libevdev_get_id_vendor(device->evdev) == VENDOR_ID_WACOM)
return false;
+ if (libevdev_get_id_bustype(device->evdev) == BUS_BLUETOOTH)
+ return false;
return true;
}
@@ -3477,6 +3727,384 @@ START_TEST(touchpad_dwt_edge_scroll_interrupt)
}
END_TEST
+static int
+has_thumb_detect(struct litest_device *dev)
+{
+ return libevdev_has_event_code(dev->evdev, EV_ABS, ABS_MT_PRESSURE);
+}
+
+START_TEST(touchpad_thumb_begin_no_motion)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+
+ litest_drain_events(li);
+
+ litest_touch_down_extended(dev, 0, 50, 50, axes);
+ litest_touch_move_to(dev, 0, 50, 50, 80, 50, 10, 0);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_update_no_motion)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ litest_disable_tap(dev->libinput_device);
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_move_to(dev, 0, 50, 50, 60, 50, 10, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_touch_move_extended(dev, 0, 65, 50, axes);
+ litest_touch_move_to(dev, 0, 65, 50, 80, 50, 10, 0);
+ litest_touch_up(dev, 0);
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_clickfinger)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+
+ libinput_device_config_click_set_method(dev->libinput_device,
+ LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER);
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_down(dev, 1, 60, 50);
+ litest_touch_move_extended(dev, 0, 55, 50, axes);
+ litest_button_click(dev, BTN_LEFT, true);
+
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_LEFT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
+
+ litest_assert_empty_queue(li);
+
+ litest_button_click(dev, BTN_LEFT, false);
+ litest_touch_up(dev, 0);
+ litest_touch_up(dev, 1);
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_down(dev, 1, 60, 50);
+ litest_touch_move_extended(dev, 1, 65, 50, axes);
+ litest_button_click(dev, BTN_LEFT, true);
+
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_LEFT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_btnarea)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_disable_tap(dev->libinput_device);
+
+ libinput_device_config_click_set_method(dev->libinput_device,
+ LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS);
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 90, 95);
+ litest_touch_move_extended(dev, 0, 95, 95, axes);
+ litest_button_click(dev, BTN_LEFT, true);
+
+ /* button areas work as usual with a thumb */
+
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_RIGHT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
+
+ litest_assert_empty_queue(li);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_edgescroll)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ enable_edge_scroll(dev);
+ litest_disable_tap(dev->libinput_device);
+
+ litest_drain_events(li);
+
+ litest_touch_down(dev, 0, 99, 30);
+ litest_touch_move_to(dev, 0, 99, 30, 99, 50, 10, 0);
+ litest_drain_events(li);
+
+ litest_touch_move_extended(dev, 0, 99, 55, axes);
+ libinput_dispatch(li);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+
+ litest_touch_move_to(dev, 0, 99, 55, 99, 70, 10, 0);
+
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_tap_begin)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_enable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ /* touch down is a thumb */
+ litest_touch_down_extended(dev, 0, 50, 50, axes);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+
+ litest_assert_empty_queue(li);
+
+ /* make sure normal tap still works */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_tap_touch)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_enable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ /* event after touch down is thumb */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_move_extended(dev, 0, 51, 50, axes);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_empty_queue(li);
+
+ /* make sure normal tap still works */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_tap_hold)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_enable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ /* event in state HOLD is thumb */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_timeout_tap();
+ libinput_dispatch(li);
+ litest_touch_move_extended(dev, 0, 51, 50, axes);
+ litest_touch_up(dev, 0);
+ litest_assert_empty_queue(li);
+
+ /* make sure normal tap still works */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_tap_hold_2ndfg)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_enable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ /* event in state HOLD is thumb */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_timeout_tap();
+ libinput_dispatch(li);
+ litest_touch_move_extended(dev, 0, 51, 50, axes);
+
+ litest_assert_empty_queue(li);
+
+ /* one finger is a thumb, now get second finger down */
+ litest_touch_down(dev, 1, 60, 50);
+ litest_assert_empty_queue(li);
+
+ /* release thumb */
+ litest_touch_up(dev, 0);
+ litest_assert_empty_queue(li);
+
+ /* timeout -> into HOLD, no event on release */
+ litest_timeout_tap();
+ libinput_dispatch(li);
+ litest_touch_up(dev, 1);
+ litest_assert_empty_queue(li);
+
+ /* make sure normal tap still works */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+}
+END_TEST
+
+START_TEST(touchpad_thumb_tap_hold_2ndfg_tap)
+{
+ struct litest_device *dev = litest_current_device();
+ struct libinput *li = dev->libinput;
+ struct libinput_event *event;
+ struct libinput_event_pointer *ptrev;
+ struct axis_replacement axes[] = {
+ { ABS_MT_PRESSURE, 100 },
+ { -1, 0 }
+ };
+
+ if (!has_thumb_detect(dev))
+ return;
+
+ litest_enable_tap(dev->libinput_device);
+ litest_drain_events(li);
+
+ /* event in state HOLD is thumb */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_timeout_tap();
+ libinput_dispatch(li);
+ litest_touch_move_extended(dev, 0, 51, 50, axes);
+
+ litest_assert_empty_queue(li);
+
+ /* one finger is a thumb, now get second finger down */
+ litest_touch_down(dev, 1, 60, 50);
+ litest_assert_empty_queue(li);
+
+ /* release thumb */
+ litest_touch_up(dev, 0);
+ litest_assert_empty_queue(li);
+
+ /* release second finger, within timeout, ergo event */
+ litest_touch_up(dev, 1);
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_LEFT,
+ LIBINPUT_BUTTON_STATE_PRESSED);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
+
+ litest_timeout_tap();
+ libinput_dispatch(li);
+ event = libinput_get_event(li);
+ ptrev = litest_is_button_event(event,
+ BTN_LEFT,
+ LIBINPUT_BUTTON_STATE_RELEASED);
+ libinput_event_destroy(libinput_event_pointer_get_base_event(ptrev));
+
+ /* make sure normal tap still works */
+ litest_touch_down(dev, 0, 50, 50);
+ litest_touch_up(dev, 0);
+ litest_timeout_tap();
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_BUTTON);
+}
+END_TEST
+
void
litest_setup_tests(void)
{
@@ -3489,6 +4117,7 @@ litest_setup_tests(void)
litest_add("touchpad:clickfinger", touchpad_1fg_clickfinger_no_touch, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger", touchpad_2fg_clickfinger_distance, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add_for_device("touchpad:clickfinger", touchpad_2fg_clickfinger_bottom, LITEST_SYNAPTICS_TOPBUTTONPAD);
litest_add("touchpad:clickfinger", touchpad_clickfinger_to_area_method, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:clickfinger",
touchpad_clickfinger_to_area_method_while_down, LITEST_CLICKPAD, LITEST_ANY);
@@ -3529,12 +4158,17 @@ litest_setup_tests(void)
litest_add("touchpad:scroll", touchpad_scroll_natural_defaults, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_scroll_natural_enable_config, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:scroll", touchpad_scroll_natural, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
- litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD);
- litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_CLICKPAD);
- litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD, LITEST_CLICKPAD);
- litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD, LITEST_CLICKPAD);
- litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD, LITEST_CLICKPAD);
- litest_add("touchpad:scroll", touchpad_edge_scroll_no_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH|LITEST_CLICKPAD);
+ litest_add("touchpad:scroll", touchpad_scroll_defaults, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_no_edge_after_motion, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_timeout, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_source, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_no_2fg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_into_buttonareas, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_within_buttonareas, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_buttonareas_click_stops_scroll, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add("touchpad:scroll", touchpad_edge_scroll_clickfinger_click_stops_scroll, LITEST_CLICKPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_at_edge, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:palm", touchpad_palm_detect_at_bottom_corners, LITEST_TOUCHPAD, LITEST_CLICKPAD);
@@ -3589,4 +4223,15 @@ litest_setup_tests(void)
litest_add("touchpad:dwt", touchpad_dwt_click, LITEST_TOUCHPAD, LITEST_ANY);
litest_add("touchpad:dwt", touchpad_dwt_edge_scroll, LITEST_TOUCHPAD, LITEST_CLICKPAD);
litest_add("touchpad:dwt", touchpad_dwt_edge_scroll_interrupt, LITEST_TOUCHPAD, LITEST_CLICKPAD);
+
+ litest_add("touchpad:thumb", touchpad_thumb_begin_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_update_no_motion, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_clickfinger, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_btnarea, LITEST_CLICKPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_edgescroll, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_tap_begin, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_tap_touch, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_tap_hold, LITEST_TOUCHPAD, LITEST_ANY);
+ litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
+ litest_add("touchpad:thumb", touchpad_thumb_tap_hold_2ndfg_tap, LITEST_TOUCHPAD, LITEST_SINGLE_TOUCH);
}
diff --git a/test/udev.c b/test/udev.c
index b077311a..30ae1180 100644
--- a/test/udev.c
+++ b/test/udev.c
@@ -413,8 +413,11 @@ START_TEST(udev_device_sysname)
libinput_dispatch(li);
while ((ev = libinput_get_event(li))) {
- if (libinput_event_get_type(ev) != LIBINPUT_EVENT_DEVICE_ADDED)
+ if (libinput_event_get_type(ev) !=
+ LIBINPUT_EVENT_DEVICE_ADDED) {
+ libinput_event_destroy(ev);
continue;
+ }
device = libinput_event_get_device(ev);
sysname = libinput_device_get_sysname(device);
diff --git a/udev/.gitignore b/udev/.gitignore
index d8e1456b..2fdaedcf 100644
--- a/udev/.gitignore
+++ b/udev/.gitignore
@@ -1 +1,3 @@
libinput-device-group
+libinput-model-quirks
+*.rules
diff --git a/udev/80-libinput-device-groups.rules b/udev/80-libinput-device-groups.rules.in
index f826bec6..c2af0ce7 100644
--- a/udev/80-libinput-device-groups.rules
+++ b/udev/80-libinput-device-groups.rules.in
@@ -2,7 +2,7 @@ ACTION!="add|change", GOTO="libinput_device_group_end"
KERNEL!="event[0-9]*", GOTO="libinput_device_group_end"
ATTRS{phys}=="?*", \
- PROGRAM="libinput-device-group %S%p", \
+ PROGRAM="@UDEV_TEST_PATH@libinput-device-group %S%p", \
ENV{LIBINPUT_DEVICE_GROUP}="%c"
LABEL="libinput_device_group_end"
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index cf57e9c9..730b115a 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -11,7 +11,7 @@
# Match string formats:
# libinput:<modalias>
# libinput:name:<name>:dmi:<dmi string>
-
+# libinput:name:<name>:fwversion:<version>
#
# Sort by brand, model
@@ -22,12 +22,17 @@ libinput:name:*AlpsPS/2 ALPS DualPoint TouchPad:dmi:*
libinput:name:*AlpsPS/2 ALPS GlidePoint:dmi:*
LIBINPUT_MODEL_ALPS_TOUCHPAD=1
+libinput:name:*AlpsPS/2 ALPS DualPoint TouchPad:fwversion:8
+libinput:name:*AlpsPS/2 ALPS GlidePoint:fwversion:8
+ LIBINPUT_ATTR_SIZE_HINT=100x55
+
##########################################
# Apple
##########################################
libinput:touchpad:input:b0003v05ACp*
libinput:touchpad:input:b0005v05ACp*
LIBINPUT_MODEL_APPLE_TOUCHPAD=1
+ LIBINPUT_ATTR_SIZE_HINT=104x75
##########################################
# Google
diff --git a/udev/90-libinput-model-quirks.rules b/udev/90-libinput-model-quirks.rules.in
index 43674f55..d8341558 100644
--- a/udev/90-libinput-model-quirks.rules
+++ b/udev/90-libinput-model-quirks.rules.in
@@ -11,6 +11,20 @@
ACTION!="add|change", GOTO="libinput_model_quirks_end"
KERNEL!="event*", GOTO="libinput_model_quirks_end"
+# Touchpad firmware detection, two-stage process.
+# First, run the program and import the LIBINPUT_MODEL_FIRMWARE_VERSION
+# environment (if any)
+KERNELS=="*input*", \
+ ENV{ID_INPUT_TOUCHPAD}=="1", \
+ IMPORT{program}="@UDEV_TEST_PATH@libinput-model-quirks %S%p"
+
+# Second, match on anything with that env set and import from the hwdb
+KERNELS=="*input*", \
+ ENV{ID_INPUT_TOUCHPAD}=="1", \
+ ENV{LIBINPUT_MODEL_FIRMWARE_VERSION}!="", \
+ IMPORT{builtin}="hwdb 'libinput:name:$attr{name}:fwversion:$env{LIBINPUT_MODEL_FIRMWARE_VERSION}'"
+# End of touchpad firmware detection
+
# Matches below are exclusive, if one matches we skip the rest
# hwdb matches:
#
diff --git a/udev/Makefile.am b/udev/Makefile.am
index 7d19809d..e850e09c 100644
--- a/udev/Makefile.am
+++ b/udev/Makefile.am
@@ -1,10 +1,22 @@
udevdir=$(UDEV_DIR)
-udev_PROGRAMS = libinput-device-group
+udev_PROGRAMS = libinput-device-group \
+ libinput-model-quirks
+
+litest_rules = 80-libinput-device-groups-litest.rules \
+ 90-libinput-model-quirks-litest.rules
+udev_SCRIPTS = $(litest_rules)
libinput_device_group_SOURCES = libinput-device-group.c
libinput_device_group_CFLAGS = $(LIBUDEV_CFLAGS) $(GCC_CFLAGS)
libinput_device_group_LDADD = $(LIBUDEV_LIBS)
+libinput_model_quirks_SOURCES = libinput-model-quirks.c
+libinput_model_quirks_CFLAGS = \
+ -I$(top_srcdir)/src \
+ $(LIBUDEV_CFLAGS) \
+ $(GCC_CFLAGS)
+libinput_model_quirks_LDADD = $(LIBUDEV_LIBS)
+
udev_rulesdir=$(UDEV_DIR)/rules.d
dist_udev_rules_DATA = \
80-libinput-device-groups.rules \
@@ -13,3 +25,11 @@ dist_udev_rules_DATA = \
udev_hwdbdir=$(UDEV_DIR)/hwdb.d
dist_udev_hwdb_DATA = \
90-libinput-model-quirks.hwdb
+
+%-litest.rules: %.rules.in
+ $(SED) -e "s|\@UDEV_TEST_PATH\@|$(abs_builddir)/|" < $^ > $@
+
+CLEANFILES = $(litest_rules)
+DISTCLEANFILES = \
+ 80-libinput-device-groups.rules \
+ 90-libinput-model-quirks.rules
diff --git a/udev/libinput-model-quirks.c b/udev/libinput-model-quirks.c
new file mode 100644
index 00000000..fc3dbe85
--- /dev/null
+++ b/udev/libinput-model-quirks.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2015 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libudev.h>
+#include <linux/input.h>
+
+#include "libinput-util.h"
+
+static inline const char *
+prop_value(struct udev_device *device,
+ const char *prop_name)
+{
+ struct udev_device *parent;
+ const char *prop_value = NULL;
+
+ parent = device;
+ while (parent && !prop_value) {
+ prop_value = udev_device_get_property_value(parent, prop_name);
+ parent = udev_device_get_parent(parent);
+ }
+
+ return prop_value;
+}
+
+static void
+handle_touchpad_alps(struct udev_device *device)
+{
+ const char *product;
+ int bus, vid, pid, version;
+
+ product = prop_value(device, "PRODUCT");
+ if (!product)
+ return;
+
+ if (sscanf(product, "%x/%x/%x/%x", &bus, &vid, &pid, &version) != 4)
+ return;
+
+ /* ALPS' firmware version is the PID */
+ if (pid)
+ printf("LIBINPUT_MODEL_FIRMWARE_VERSION=%d\n", pid);
+}
+
+static void
+handle_touchpad(struct udev_device *device)
+{
+ const char *name = NULL;
+
+ name = prop_value(device, "NAME");
+ if (!name)
+ return;
+
+ if (strstr(name, "AlpsPS/2 ALPS") != NULL)
+ handle_touchpad_alps(device);
+}
+
+int main(int argc, char **argv)
+{
+ int rc = 1;
+ struct udev *udev = NULL;
+ struct udev_device *device = NULL;
+ const char *syspath;
+
+ if (argc != 2)
+ return 1;
+
+ syspath = argv[1];
+
+ udev = udev_new();
+ if (!udev)
+ goto out;
+
+ device = udev_device_new_from_syspath(udev, syspath);
+ if (!device)
+ goto out;
+
+ if (udev_device_get_property_value(device, "ID_INPUT_TOUCHPAD"))
+ handle_touchpad(device);
+
+ rc = 0;
+
+out:
+ if (device)
+ udev_device_unref(device);
+ if (udev)
+ udev_unref(udev);
+
+ return rc;
+}