Commit 77890ecc authored by Peter Hutterer's avatar Peter Hutterer

tablet: always enable the no-proximity-out quirk on HUION tablets

And instead disable it when we do get a proximity out.
Signed-off-by: Peter Hutterer's avatarPeter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Benjamin Tissoires's avatarBenjamin Tissoires <benjamin.tissoires@gmail.com>
parent 0c6b5c04
......@@ -162,23 +162,4 @@ model quirks hwdb for instructions.
This property must not be used for any other purpose, no specific behavior
is guaranteed.
@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.
*/
......@@ -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);
}
}
}
......
......@@ -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;
};
......
......@@ -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);
}
......@@ -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
......
......@@ -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:"
......
......@@ -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'),
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment