[PATCH libinput] tablet: always enable the no-proximity-out quirk on HUION tablets

Peter Hutterer peter.hutterer at who-t.net
Wed Sep 20 01:40:57 UTC 2017


And instead disable it when we do get a proximity out.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
Follow-up to
https://lists.freedesktop.org/archives/wayland-devel/2017-September/035006.html
While writing some more documentation for it, I realised it's easier to just
enable this on all HUION tablets and auto-disable it on those that support
real proximity out. Much better than having the user drop a hwdb file and
hope it works.

 doc/device-configuration-via-udev.dox  | 19 --------
 src/evdev-tablet.c                     | 15 +++++-
 src/evdev-tablet.h                     |  3 ++
 test/test-tablet.c                     | 87 ++++++++++++++++++++++++++++++++++
 udev/90-libinput-model-quirks.hwdb     | 13 ++---
 udev/90-libinput-model-quirks.rules.in |  4 ++
 udev/parse_hwdb.py                     |  2 +-
 7 files changed, 112 insertions(+), 31 deletions(-)

diff --git a/doc/device-configuration-via-udev.dox b/doc/device-configuration-via-udev.dox
index 3050cd80..2ebfa321 100644
--- a/doc/device-configuration-via-udev.dox
+++ b/doc/device-configuration-via-udev.dox
@@ -162,23 +162,4 @@ model quirks hwdb for instructions.
 This property must not be used for any other purpose, no specific behavior
 is guaranteed.
 
- at subsection model_specific_configuration_huion_tablets Graphics tablets without BTN_TOOL_PEN proximity events
-
-On graphics tablets, the <b>BTN_TOOL_PEN</b> bit signals that the pen is in
-detectable range and will send events. When the pen leaves the sensor range,
-the bit must be unset to signal that the tablet is out of proximity again.
-Some HUION PenTablet devices are buggy and do not send this event. To a
-caller, it thus looks like the pen is constantly in proximity. This causes
-unexpected behavior in applications that rely on tablet device proximity.
-
-The property <b>LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT</b> may be set
-by a user in a local hwdb file. This property designates the tablet
-to be buggy and that libinput should work around this bug.
-
-Many of the affected tablets cannot be detected automatically by libinput
-because HUION tablets reuse USB IDs.  Local configuration is required to set
-this property. Refer to the libinput model quirks hwdb for instructions.
-
-This property must not be used for any other purpose, no specific behavior
-is guaranteed.
 */
diff --git a/src/evdev-tablet.c b/src/evdev-tablet.c
index 7e9281d1..21501c2b 100644
--- a/src/evdev-tablet.c
+++ b/src/evdev-tablet.c
@@ -1667,12 +1667,14 @@ tablet_proximity_out_quirk_timer_func(uint64_t now, void *data)
 		return;
 	}
 
+	tablet->quirks.proximity_out_in_progress = true;
 	ARRAY_FOR_EACH(events, e) {
 		tablet->base.interface->process(&tablet->base,
 						 tablet->device,
 						 e,
 						 now);
 	}
+	tablet->quirks.proximity_out_in_progress = false;
 
 	tablet->quirks.proximity_out_forced = true;
 }
@@ -1721,10 +1723,19 @@ tablet_proximity_out_quirk_update(struct tablet_dispatch *tablet,
 		}
 		tablet->quirks.last_event_time = time;
 	} else if (e->type == EV_KEY && e->code == BTN_TOOL_PEN) {
-		if (e->value)
+		if (e->value) {
 			tablet_proximity_out_quirk_set_timer(tablet, time);
-		else
+		} else {
+			/* If we get a BTN_TOOL_PEN 0 when *not* injecting
+			 * events it means the tablet will give us the right
+			 * events after all and we can disable our
+			 * timer-based proximity out.
+			 */
+			if (!tablet->quirks.proximity_out_in_progress)
+				tablet->quirks.need_to_force_prox_out = false;
+
 			libinput_timer_cancel(&tablet->quirks.prox_out_timer);
+		}
 	}
 }
 
diff --git a/src/evdev-tablet.h b/src/evdev-tablet.h
index ba05e88c..bf5a3dc1 100644
--- a/src/evdev-tablet.h
+++ b/src/evdev-tablet.h
@@ -89,6 +89,9 @@ struct tablet_dispatch {
 		struct libinput_timer prox_out_timer;
 		bool proximity_out_forced;
 		uint64_t last_event_time;
+
+		/* true while injecting BTN_TOOL_PEN events */
+		bool proximity_out_in_progress;
 	} quirks;
 };
 
diff --git a/test/test-tablet.c b/test/test-tablet.c
index 66b4f79c..92fd45b9 100644
--- a/test/test-tablet.c
+++ b/test/test-tablet.c
@@ -4445,9 +4445,95 @@ START_TEST(huion_static_btn_tool_pen_no_timeout_during_usage)
 }
 END_TEST
 
+START_TEST(huion_static_btn_tool_pen_disable_quirk_on_prox_out)
+{
+	struct litest_device *dev = litest_current_device();
+	struct libinput *li = dev->libinput;
+	bool with_timeout = _i; /* ranged test */
+	int i;
+
+	/* test is run twice, once where the real BTN_TOOL_PEN is triggered
+	 * during proximity out, one where the real BTN_TOOL_PEN is
+	 * triggered after we already triggered the quirk timeout
+	 */
+
+	litest_drain_events(li);
+
+	litest_event(dev, EV_ABS, ABS_X, 20000);
+	litest_event(dev, EV_ABS, ABS_Y, 20000);
+	litest_event(dev, EV_ABS, ABS_PRESSURE, 100);
+	litest_event(dev, EV_KEY, BTN_TOOL_PEN, 1);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	litest_drain_events(li);
+
+	for (i = 0; i < 10; i++) {
+		litest_event(dev, EV_ABS, ABS_X, 20000 + 10 * i);
+		litest_event(dev, EV_ABS, ABS_Y, 20000 - 10 * i);
+		litest_event(dev, EV_SYN, SYN_REPORT, 0);
+		libinput_dispatch(li);
+	}
+	litest_assert_only_typed_events(li,
+					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+
+	/* Wait past the timeout to expect a proximity out */
+	if (with_timeout) {
+		litest_timeout_tablet_proxout();
+		libinput_dispatch(li);
+		litest_assert_tablet_proximity_event(li,
+						     LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+	}
+
+	/* Send a real prox out, expect quirk to be disabled */
+	litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	libinput_dispatch(li);
+
+	if (with_timeout) {
+		/* we got the proximity event above already */
+		litest_assert_empty_queue(li);
+	} else {
+		litest_assert_tablet_proximity_event(li,
+						     LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+	}
+
+	litest_push_event_frame(dev);
+	litest_tablet_proximity_out(dev);
+	litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	litest_pop_event_frame(dev);
+
+	litest_tablet_proximity_in(dev, 50, 50, NULL);
+	libinput_dispatch(li);
+	litest_assert_tablet_proximity_event(li,
+			     LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_IN);
+	libinput_dispatch(li);
+
+	for (i = 0; i < 10; i++) {
+		litest_tablet_motion(dev, 50 + i, 50 + i, NULL);
+		libinput_dispatch(li);
+	}
+
+	litest_assert_only_typed_events(li,
+					LIBINPUT_EVENT_TABLET_TOOL_AXIS);
+
+	litest_push_event_frame(dev);
+	litest_tablet_proximity_out(dev);
+	litest_event(dev, EV_KEY, BTN_TOOL_PEN, 0);
+	litest_event(dev, EV_SYN, SYN_REPORT, 0);
+	litest_pop_event_frame(dev);
+	libinput_dispatch(li);
+
+	litest_assert_tablet_proximity_event(li,
+			     LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
+	litest_assert_empty_queue(li);
+}
+END_TEST
+
 void
 litest_setup_tests_tablet(void)
 {
+	struct range with_timeout = { 0, 2 };
+
 	litest_add("tablet:tool", tool_ref, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
 	litest_add("tablet:tool", tool_user_data, LITEST_TABLET | LITEST_TOOL_SERIAL, LITEST_ANY);
 	litest_add("tablet:tool", tool_capability, LITEST_TABLET, LITEST_ANY);
@@ -4543,4 +4629,5 @@ litest_setup_tests_tablet(void)
 
 	litest_add_for_device("tablet:quirks", huion_static_btn_tool_pen, LITEST_HUION_TABLET);
 	litest_add_for_device("tablet:quirks", huion_static_btn_tool_pen_no_timeout_during_usage, LITEST_HUION_TABLET);
+	litest_add_ranged_for_device("tablet:quirks", huion_static_btn_tool_pen_disable_quirk_on_prox_out, LITEST_HUION_TABLET, &with_timeout);
 }
diff --git a/udev/90-libinput-model-quirks.hwdb b/udev/90-libinput-model-quirks.hwdb
index 867ffa53..6525b800 100644
--- a/udev/90-libinput-model-quirks.hwdb
+++ b/udev/90-libinput-model-quirks.hwdb
@@ -171,15 +171,10 @@ libinput:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnHP:pnHPZBookStudioG3:*
 # matching BTN_TOOL_PEN value 0 event. The device appears as if it was
 # permanently in proximity.
 #
-# If the tablet is affected by this bug, copy the two lines below into a new
-# file
-# /etc/udev/hwdb.d/90-libinput-huion-pentablet-proximity-quirk.hwdb, then run
-# sudo udevadm hwdb --update and reboot.
-#
-# Note that HUION re-uses USB IDs for its devices, not ever HUION tablet is
-# affected by this bug.
-#libinput:name:PenTablet Pen:dmi:*
-# LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT=1
+# HUION re-uses USB IDs for its devices, not every HUION tablet is
+# affected by this bug, libinput will auto-disable this feature
+libinput:tablet:input:b0003v256Cp*
+ LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT=1
 
 ##########################################
 # LENOVO
diff --git a/udev/90-libinput-model-quirks.rules.in b/udev/90-libinput-model-quirks.rules.in
index 08137812..5c2ff42e 100644
--- a/udev/90-libinput-model-quirks.rules.in
+++ b/udev/90-libinput-model-quirks.rules.in
@@ -29,6 +29,10 @@ KERNELS=="*input*", \
 ENV{ID_INPUT_TOUCHPAD}=="1", \
   IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:touchpad:"
 
+# libinput:tablet:<modalias>
+ENV{ID_INPUT_TABLET}=="1", \
+  IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:TABLET:"
+
 # libinput:mouse:<modalias>
 ENV{ID_INPUT_MOUSE}=="1", \
   IMPORT{builtin}="hwdb --subsystem=input --lookup-prefix=libinput:mouse:"
diff --git a/udev/parse_hwdb.py b/udev/parse_hwdb.py
index f6b9ec0a..69eb65b0 100755
--- a/udev/parse_hwdb.py
+++ b/udev/parse_hwdb.py
@@ -59,7 +59,7 @@ REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
 UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
 
 TYPES = {
-    'libinput': ('name', 'touchpad', 'mouse', 'keyboard'),
+    'libinput': ('name', 'touchpad', 'mouse', 'keyboard', 'tablet'),
 }
 
 
-- 
2.13.5



More information about the wayland-devel mailing list