mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-05-08 11:19:14 +02:00
tablet: add a quirk for the HUION PenTablet that doesn't send proximity out events
Could be fixed in the kernel, but these tablets are effectively abandoned and fixing them is a one-by-one issue. Let's put the infrastructure in place to have this fixed once for this type of device and move on. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net> Yay-by: Benjamin Tissoires <benjamin.tissoires@gmail.com>
This commit is contained in:
parent
34f28a329b
commit
1962c6f2db
10 changed files with 312 additions and 4 deletions
|
|
@ -162,4 +162,23 @@ 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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@
|
|||
#include <libwacom/libwacom.h>
|
||||
#endif
|
||||
|
||||
/* The tablet sends events every ~2ms , 50ms should be plenty enough to
|
||||
detect out-of-range */
|
||||
#define FORCED_PROXOUT_TIMEOUT ms2us(50)
|
||||
|
||||
#define tablet_set_status(tablet_,s_) (tablet_)->status |= (s_)
|
||||
#define tablet_unset_status(tablet_,s_) (tablet_)->status &= ~(s_)
|
||||
#define tablet_has_status(tablet_,s_) (!!((tablet_)->status & (s_)))
|
||||
|
|
@ -1633,6 +1637,97 @@ tablet_reset_state(struct tablet_dispatch *tablet)
|
|||
sizeof(tablet->button_state));
|
||||
}
|
||||
|
||||
static inline void
|
||||
tablet_proximity_out_quirk_set_timer(struct tablet_dispatch *tablet,
|
||||
uint64_t time)
|
||||
{
|
||||
libinput_timer_set(&tablet->quirks.prox_out_timer,
|
||||
time + FORCED_PROXOUT_TIMEOUT);
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_proximity_out_quirk_timer_func(uint64_t now, void *data)
|
||||
{
|
||||
struct tablet_dispatch *tablet = data;
|
||||
struct input_event events[2] = {
|
||||
{ .time = us2tv(now),
|
||||
.type = EV_KEY,
|
||||
.code = BTN_TOOL_PEN,
|
||||
.value = 0 },
|
||||
{ .time = us2tv(now),
|
||||
.type = EV_SYN,
|
||||
.code = SYN_REPORT,
|
||||
.value = 0 },
|
||||
};
|
||||
struct input_event *e;
|
||||
|
||||
if (tablet->quirks.last_event_time > now - FORCED_PROXOUT_TIMEOUT) {
|
||||
tablet_proximity_out_quirk_set_timer(tablet,
|
||||
tablet->quirks.last_event_time);
|
||||
return;
|
||||
}
|
||||
|
||||
ARRAY_FOR_EACH(events, e) {
|
||||
tablet->base.interface->process(&tablet->base,
|
||||
tablet->device,
|
||||
e,
|
||||
now);
|
||||
}
|
||||
|
||||
tablet->quirks.proximity_out_forced = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handling for the proximity out workaround. Some tablets only send
|
||||
* BTN_TOOL_PEN on the very first event, then leave it set even when the pen
|
||||
* leaves the detectable range. To libinput this looks like we always have
|
||||
* the pen in proximity.
|
||||
*
|
||||
* To avoid this, we set a timer on BTN_TOOL_PEN in. We expect the tablet to
|
||||
* continuously send events, and while it's doing so we keep updating the
|
||||
* timer. Once we go Xms without an event we assume proximity out and inject
|
||||
* a BTN_TOOL_PEN event into the sequence through the timer func.
|
||||
*
|
||||
* We need to remember that we did that, on the first event after the
|
||||
* timeout we need to inject a BTN_TOOL_PEN event again to force proximity
|
||||
* in.
|
||||
*/
|
||||
static inline void
|
||||
tablet_proximity_out_quirk_update(struct tablet_dispatch *tablet,
|
||||
struct evdev_device *device,
|
||||
struct input_event *e,
|
||||
uint64_t time)
|
||||
{
|
||||
if (!tablet->quirks.need_to_force_prox_out)
|
||||
return;
|
||||
|
||||
if (e->type == EV_SYN) {
|
||||
/* If the timer function forced prox out before,
|
||||
fake a BTN_TOOL_PEN event */
|
||||
if (tablet->quirks.proximity_out_forced) {
|
||||
|
||||
struct input_event fake_event = {
|
||||
.time = us2tv(time),
|
||||
.type = EV_KEY,
|
||||
.code = BTN_TOOL_PEN,
|
||||
.value = 1,
|
||||
};
|
||||
|
||||
tablet->base.interface->process(&tablet->base,
|
||||
device,
|
||||
&fake_event,
|
||||
time);
|
||||
tablet->quirks.proximity_out_forced = false;
|
||||
}
|
||||
tablet->quirks.last_event_time = time;
|
||||
} else if (e->type == EV_KEY && e->code == BTN_TOOL_PEN) {
|
||||
if (e->value)
|
||||
tablet_proximity_out_quirk_set_timer(tablet, time);
|
||||
else
|
||||
libinput_timer_cancel(&tablet->quirks.prox_out_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tablet_process(struct evdev_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
|
|
@ -1641,6 +1736,9 @@ tablet_process(struct evdev_dispatch *dispatch,
|
|||
{
|
||||
struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
|
||||
|
||||
/* Warning: this may inject events */
|
||||
tablet_proximity_out_quirk_update(tablet, device, e, time);
|
||||
|
||||
switch (e->type) {
|
||||
case EV_ABS:
|
||||
tablet_process_absolute(tablet, device, e, time);
|
||||
|
|
@ -1683,6 +1781,9 @@ tablet_destroy(struct evdev_dispatch *dispatch)
|
|||
struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
|
||||
struct libinput_tablet_tool *tool, *tmp;
|
||||
|
||||
libinput_timer_cancel(&tablet->quirks.prox_out_timer);
|
||||
libinput_timer_destroy(&tablet->quirks.prox_out_timer);
|
||||
|
||||
list_for_each_safe(tool, tmp, &tablet->tool_list, link) {
|
||||
libinput_tablet_tool_unref(tool);
|
||||
}
|
||||
|
|
@ -1722,6 +1823,7 @@ tablet_check_initial_proximity(struct evdev_device *device,
|
|||
struct evdev_dispatch *dispatch)
|
||||
{
|
||||
struct tablet_dispatch *tablet = tablet_dispatch(dispatch);
|
||||
struct libinput *li = tablet_libinput_context(tablet);
|
||||
bool tool_in_prox = false;
|
||||
int code, state;
|
||||
enum libinput_tablet_tool_type tool;
|
||||
|
|
@ -1743,6 +1845,8 @@ tablet_check_initial_proximity(struct evdev_device *device,
|
|||
return;
|
||||
|
||||
tablet_update_tool(tablet, device, tool, state);
|
||||
if (tablet->quirks.need_to_force_prox_out)
|
||||
tablet_proximity_out_quirk_set_timer(tablet, libinput_now(li));
|
||||
|
||||
tablet->current_tool_id =
|
||||
libevdev_get_event_value(device->evdev,
|
||||
|
|
@ -1922,6 +2026,15 @@ tablet_init(struct tablet_dispatch *tablet,
|
|||
|
||||
tablet_set_status(tablet, TABLET_TOOL_OUT_OF_PROXIMITY);
|
||||
|
||||
if (device->model_flags & EVDEV_MODEL_TABLET_NO_PROXIMITY_OUT) {
|
||||
tablet->quirks.need_to_force_prox_out = true;
|
||||
libinput_timer_init(&tablet->quirks.prox_out_timer,
|
||||
tablet_libinput_context(tablet),
|
||||
"proxout",
|
||||
tablet_proximity_out_quirk_timer_func,
|
||||
tablet);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,13 @@ struct tablet_dispatch {
|
|||
|
||||
/* The paired touch device on devices with both pen & touch */
|
||||
struct evdev_device *touch_device;
|
||||
|
||||
struct {
|
||||
bool need_to_force_prox_out;
|
||||
struct libinput_timer prox_out_timer;
|
||||
bool proximity_out_forced;
|
||||
uint64_t last_event_time;
|
||||
} quirks;
|
||||
};
|
||||
|
||||
static inline struct tablet_dispatch*
|
||||
|
|
|
|||
|
|
@ -2740,6 +2740,7 @@ evdev_read_model_flags(struct evdev_device *device)
|
|||
MODEL(HP_PAVILION_DM4_TOUCHPAD),
|
||||
MODEL(APPLE_TOUCHPAD_ONEBUTTON),
|
||||
MODEL(LOGITECH_MARBLE_MOUSE),
|
||||
MODEL(TABLET_NO_PROXIMITY_OUT),
|
||||
#undef MODEL
|
||||
{ "ID_INPUT_TRACKBALL", EVDEV_MODEL_TRACKBALL },
|
||||
{ NULL, EVDEV_MODEL_DEFAULT },
|
||||
|
|
|
|||
|
|
@ -127,6 +127,7 @@ enum evdev_device_model {
|
|||
EVDEV_MODEL_HP_PAVILION_DM4_TOUCHPAD = (1 << 24),
|
||||
EVDEV_MODEL_APPLE_TOUCHPAD_ONEBUTTON = (1 << 25),
|
||||
EVDEV_MODEL_LOGITECH_MARBLE_MOUSE = (1 << 26),
|
||||
EVDEV_MODEL_TABLET_NO_PROXIMITY_OUT = (1 << 27),
|
||||
};
|
||||
|
||||
enum evdev_button_scroll_state {
|
||||
|
|
|
|||
|
|
@ -42,10 +42,6 @@ static struct input_event proximity_in[] = {
|
|||
};
|
||||
|
||||
static struct input_event proximity_out[] = {
|
||||
{ .type = EV_ABS, .code = ABS_X, .value = 0 },
|
||||
{ .type = EV_ABS, .code = ABS_Y, .value = 0 },
|
||||
{ .type = EV_KEY, .code = BTN_TOOL_PEN, .value = 0 },
|
||||
{ .type = EV_SYN, .code = SYN_REPORT, .value = 0 },
|
||||
{ .type = -1, .code = -1 },
|
||||
};
|
||||
|
||||
|
|
@ -98,6 +94,16 @@ static int events[] = {
|
|||
-1, -1,
|
||||
};
|
||||
|
||||
static const char udev_rule[] =
|
||||
"ACTION==\"remove\", GOTO=\"huion_end\"\n"
|
||||
"KERNEL!=\"event*\", GOTO=\"huion_end\"\n"
|
||||
"ENV{ID_INPUT_TABLET}==\"\", GOTO=\"huion_end\"\n"
|
||||
"\n"
|
||||
"ATTRS{name}==\"litest HUION PenTablet Pen\","
|
||||
" ENV{LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT}=\"1\"\n"
|
||||
"\n"
|
||||
"LABEL=\"huion_end\"";
|
||||
|
||||
struct litest_test_device litest_huion_tablet_device = {
|
||||
.type = LITEST_HUION_TABLET,
|
||||
.features = LITEST_TABLET,
|
||||
|
|
@ -109,4 +115,5 @@ struct litest_test_device litest_huion_tablet_device = {
|
|||
.id = &input_id,
|
||||
.events = events,
|
||||
.absinfo = absinfo,
|
||||
.udev_rule = udev_rule,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3339,6 +3339,12 @@ litest_timeout_trackpoint(void)
|
|||
msleep(320);
|
||||
}
|
||||
|
||||
void
|
||||
litest_timeout_tablet_proxout(void)
|
||||
{
|
||||
msleep(70);
|
||||
}
|
||||
|
||||
void
|
||||
litest_push_event_frame(struct litest_device *dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -729,6 +729,9 @@ litest_timeout_gesture_scroll(void);
|
|||
void
|
||||
litest_timeout_trackpoint(void);
|
||||
|
||||
void
|
||||
litest_timeout_tablet_proxout(void);
|
||||
|
||||
void
|
||||
litest_push_event_frame(struct litest_device *dev);
|
||||
|
||||
|
|
|
|||
|
|
@ -250,6 +250,22 @@ START_TEST(tip_down_prox_in)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
static inline bool
|
||||
tablet_has_proxout_quirk(struct litest_device *dev)
|
||||
{
|
||||
struct udev_device *udev_device;
|
||||
bool has_quirk;
|
||||
|
||||
udev_device = libinput_device_get_udev_device(dev->libinput_device);
|
||||
|
||||
has_quirk = !!udev_device_get_property_value(udev_device,
|
||||
"LIBINPUT_MODEL_TABLET_NO_PROXIMITY_OUT");
|
||||
|
||||
udev_device_unref(udev_device);
|
||||
|
||||
return has_quirk;
|
||||
}
|
||||
|
||||
START_TEST(tip_up_prox_out)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
|
|
@ -262,6 +278,9 @@ START_TEST(tip_up_prox_out)
|
|||
{ -1, -1 }
|
||||
};
|
||||
|
||||
if (tablet_has_proxout_quirk(dev))
|
||||
return;
|
||||
|
||||
litest_tablet_proximity_in(dev, 10, 10, axes);
|
||||
litest_event(dev, EV_KEY, BTN_TOUCH, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
|
|
@ -616,6 +635,9 @@ START_TEST(tip_state_proximity)
|
|||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tablet_event = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
|
|
@ -808,6 +830,9 @@ START_TEST(proximity_in_out)
|
|||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
while ((event = libinput_get_event(li))) {
|
||||
if (libinput_event_get_type(event) ==
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY) {
|
||||
|
|
@ -917,7 +942,9 @@ START_TEST(proximity_out_clear_buttons)
|
|||
litest_event(dev, EV_KEY, button, 1);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
while ((event = libinput_get_event(li))) {
|
||||
|
|
@ -1042,6 +1069,9 @@ START_TEST(proximity_has_axes)
|
|||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
event = libinput_get_event(li);
|
||||
tablet_event = litest_is_tablet_event(event,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY);
|
||||
|
|
@ -2506,6 +2536,10 @@ START_TEST(tool_in_prox_before_start)
|
|||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_TABLET_TOOL_BUTTON);
|
||||
litest_tablet_proximity_out(dev);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event_of_type(li,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY,
|
||||
|
|
@ -4314,6 +4348,101 @@ START_TEST(cintiq_touch_arbitration_remove_tablet)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(huion_static_btn_tool_pen)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
int i;
|
||||
|
||||
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 */
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* New events should fake a proximity in again */
|
||||
litest_event(dev, EV_ABS, ABS_X, 20000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 20000);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
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_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);
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libinput_dispatch(li);
|
||||
|
||||
/* New events, just to ensure cleanup paths are correct */
|
||||
litest_event(dev, EV_ABS, ABS_X, 20000);
|
||||
litest_event(dev, EV_ABS, ABS_Y, 20000);
|
||||
litest_event(dev, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(huion_static_btn_tool_pen_no_timeout_during_usage)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct libinput *li = dev->libinput;
|
||||
int i;
|
||||
|
||||
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);
|
||||
|
||||
/* take longer than the no-activity timeout */
|
||||
for (i = 0; i < 50; 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);
|
||||
msleep(5);
|
||||
}
|
||||
litest_assert_only_typed_events(li,
|
||||
LIBINPUT_EVENT_TABLET_TOOL_AXIS);
|
||||
litest_timeout_tablet_proxout();
|
||||
libinput_dispatch(li);
|
||||
litest_assert_tablet_proximity_event(li,
|
||||
LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT);
|
||||
libinput_dispatch(li);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests_tablet(void)
|
||||
{
|
||||
|
|
@ -4409,4 +4538,7 @@ litest_setup_tests_tablet(void)
|
|||
litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_suspend_touch_device, LITEST_WACOM_CINTIQ_13HDT_FINGER);
|
||||
litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_remove_touch, LITEST_WACOM_CINTIQ_13HDT_PEN);
|
||||
litest_add_for_device("tablet:touch-arbitration", cintiq_touch_arbitration_remove_tablet, LITEST_WACOM_CINTIQ_13HDT_FINGER);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -162,6 +162,25 @@ libinput:name:SYN1EDE:00 06CB:7442:dmi:*svnHewlett-Packard:pnHPStreamNotebookPC1
|
|||
libinput:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnHP:pnHPZBookStudioG3:*
|
||||
LIBINPUT_MODEL_HP_ZBOOK_STUDIO_G3=1
|
||||
|
||||
##########################################
|
||||
# HUION
|
||||
##########################################
|
||||
#
|
||||
# HUION PenTablet device. Some of these devices send a BTN_TOOL_PEN event
|
||||
# with value 1 on the first event received by the device but never send the
|
||||
# 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
|
||||
|
||||
##########################################
|
||||
# LENOVO
|
||||
##########################################
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue