mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 20:30:27 +01:00
touchpad: don't disable on external mice until we see an event
Instead of disabling the touchpad as soon as a mouse is seen by libinput, disable it as soon as a mouse sends an actual event. This works around the current issues with many devices (touchpads and keyboards alike) announcing a HID Mouse Application Collection which gets its own event node in the kernel. That event node usually just sits there and does nothing but its mere presence disabled the touchpad. Let's change this and instead only disable once we see an event. Closes: #1104 Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1414>
This commit is contained in:
parent
89351c715a
commit
33b1d87c08
4 changed files with 127 additions and 35 deletions
|
|
@ -45,6 +45,8 @@
|
|||
#define FAKE_FINGER_OVERFLOW bit(7)
|
||||
#define THUMB_IGNORE_SPEED_THRESHOLD 20 /* mm/s */
|
||||
|
||||
#define MOUSE_HAS_SENT_EVENTS bit(1)
|
||||
|
||||
enum notify {
|
||||
DONT_NOTIFY,
|
||||
DO_NOTIFY,
|
||||
|
|
@ -1918,7 +1920,7 @@ tp_interface_process(struct evdev_dispatch *dispatch,
|
|||
static void
|
||||
tp_remove_sendevents(struct tp_dispatch *tp)
|
||||
{
|
||||
struct evdev_paired_device *kbd;
|
||||
struct evdev_paired_device *kbd, *mouse;
|
||||
|
||||
libinput_timer_cancel(&tp->palm.trackpoint_timer);
|
||||
libinput_timer_cancel(&tp->dwt.keyboard_timer);
|
||||
|
|
@ -1930,6 +1932,10 @@ tp_remove_sendevents(struct tp_dispatch *tp)
|
|||
libinput_device_remove_event_listener(&kbd->listener);
|
||||
}
|
||||
|
||||
list_for_each_safe(mouse, &tp->sendevents.external_mice_list, link) {
|
||||
evdev_paired_device_destroy(mouse);
|
||||
}
|
||||
|
||||
if (tp->lid_switch.lid_switch)
|
||||
libinput_device_remove_event_listener(&tp->lid_switch.listener);
|
||||
|
||||
|
|
@ -2530,24 +2536,60 @@ tp_pair_tablet(struct evdev_device *touchpad, struct evdev_device *tablet)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_external_mouse_event(usec_t time, struct libinput_event *event, void *data)
|
||||
{
|
||||
struct tp_dispatch *tp = data;
|
||||
|
||||
if (event->type < LIBINPUT_EVENT_POINTER_MOTION ||
|
||||
event->type >= LIBINPUT_EVENT_TOUCH_DOWN)
|
||||
return;
|
||||
|
||||
struct libinput_device *libinput_device = libinput_event_get_device(event);
|
||||
struct evdev_device *device = (struct evdev_device *)libinput_device;
|
||||
struct evdev_paired_device *paired;
|
||||
list_for_each(paired, &tp->sendevents.external_mice_list, link) {
|
||||
if (paired->device == device) {
|
||||
paired->flags |= MOUSE_HAS_SENT_EVENTS;
|
||||
/* In theory we should be waiting for a neutral state here but
|
||||
* that's hopefully niche enough. tp_suspend() clears our state
|
||||
* anyway.
|
||||
*/
|
||||
if (tp->sendevents.current_mode ==
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
|
||||
tp_suspend(tp, tp->device, SUSPEND_EXTERNAL_MOUSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
tp_pair_external_mouse(struct evdev_device *touchpad, struct evdev_device *mouse)
|
||||
{
|
||||
struct tp_dispatch *tp = (struct tp_dispatch *)touchpad->dispatch;
|
||||
|
||||
if (!(mouse->tags & EVDEV_TAG_EXTERNAL_MOUSE))
|
||||
return;
|
||||
|
||||
struct evdev_paired_device *paired = zalloc(sizeof(*paired));
|
||||
paired->device = mouse;
|
||||
libinput_device_add_event_listener(&mouse->base,
|
||||
&paired->listener,
|
||||
tp_external_mouse_event,
|
||||
tp);
|
||||
list_insert(&tp->sendevents.external_mice_list, &paired->link);
|
||||
}
|
||||
|
||||
static void
|
||||
tp_interface_device_added(struct evdev_device *device,
|
||||
struct evdev_device *added_device)
|
||||
{
|
||||
struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
|
||||
|
||||
tp_pair_trackpoint(device, added_device);
|
||||
tp_dwt_pair_keyboard(device, added_device);
|
||||
tp_pair_lid_switch(device, added_device);
|
||||
tp_pair_tablet_mode_switch(device, added_device);
|
||||
tp_pair_tablet(device, added_device);
|
||||
|
||||
if (tp->sendevents.current_mode !=
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
|
||||
return;
|
||||
|
||||
if (added_device->tags & EVDEV_TAG_EXTERNAL_MOUSE)
|
||||
tp_suspend(tp, device, SUSPEND_EXTERNAL_MOUSE);
|
||||
tp_pair_external_mouse(device, added_device);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -2555,7 +2597,7 @@ tp_interface_device_removed(struct evdev_device *device,
|
|||
struct evdev_device *removed_device)
|
||||
{
|
||||
struct tp_dispatch *tp = (struct tp_dispatch *)device->dispatch;
|
||||
struct evdev_paired_device *kbd;
|
||||
struct evdev_paired_device *kbd, *mouse;
|
||||
|
||||
if (removed_device == tp->buttons.trackpoint) {
|
||||
/* Clear any pending releases for the trackpoint */
|
||||
|
|
@ -2589,21 +2631,18 @@ tp_interface_device_removed(struct evdev_device *device,
|
|||
tp_resume(tp, device, SUSPEND_TABLET_MODE);
|
||||
}
|
||||
|
||||
if (tp->sendevents.current_mode ==
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE) {
|
||||
struct libinput_device *dev;
|
||||
bool found = false;
|
||||
|
||||
list_for_each(dev, &device->base.seat->devices_list, link) {
|
||||
struct evdev_device *d = evdev_device(dev);
|
||||
if (d != removed_device &&
|
||||
(d->tags & EVDEV_TAG_EXTERNAL_MOUSE)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
bool have_external_mouse_sending_events = false;
|
||||
list_for_each_safe(mouse, &tp->sendevents.external_mice_list, link) {
|
||||
if (mouse->device == removed_device) {
|
||||
evdev_paired_device_destroy(mouse);
|
||||
} else if (mouse->flags & MOUSE_HAS_SENT_EVENTS) {
|
||||
have_external_mouse_sending_events = true;
|
||||
}
|
||||
if (!found)
|
||||
tp_resume(tp, device, SUSPEND_EXTERNAL_MOUSE);
|
||||
}
|
||||
if (tp->sendevents.current_mode ==
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE &&
|
||||
!have_external_mouse_sending_events) {
|
||||
tp_resume(tp, device, SUSPEND_EXTERNAL_MOUSE);
|
||||
}
|
||||
|
||||
if (removed_device == tp->left_handed.tablet_device) {
|
||||
|
|
@ -3468,6 +3507,8 @@ tp_init_sendevents(struct tp_dispatch *tp, struct evdev_device *device)
|
|||
{
|
||||
char timer_name[64];
|
||||
|
||||
list_init(&tp->sendevents.external_mice_list);
|
||||
|
||||
snprintf(timer_name,
|
||||
sizeof(timer_name),
|
||||
"%s trackpoint",
|
||||
|
|
|
|||
|
|
@ -482,6 +482,8 @@ struct tp_dispatch {
|
|||
struct {
|
||||
struct libinput_device_config_send_events config;
|
||||
enum libinput_config_send_events_mode current_mode;
|
||||
|
||||
struct list external_mice_list;
|
||||
} sendevents;
|
||||
|
||||
struct {
|
||||
|
|
|
|||
|
|
@ -1015,6 +1015,7 @@ struct evdev_paired_device {
|
|||
struct list link;
|
||||
struct evdev_device *device;
|
||||
struct libinput_event_listener listener;
|
||||
uint32_t flags; /* generic flags used by the caller */
|
||||
};
|
||||
|
||||
static inline void
|
||||
|
|
|
|||
|
|
@ -5817,6 +5817,7 @@ START_TEST(touchpad_disabled_on_mouse)
|
|||
bool suspend = litest_test_param_get_bool(test_env->params, "suspend");
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
|
||||
status = libinput_device_config_send_events_set_mode(
|
||||
dev->libinput_device,
|
||||
|
|
@ -5831,6 +5832,18 @@ START_TEST(touchpad_disabled_on_mouse)
|
|||
mouse = litest_add_device(li, LITEST_MOUSE);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_ADDED);
|
||||
|
||||
/* Mouse hasn't sent events yet */
|
||||
litest_touch_down(dev, 0, 20, 30);
|
||||
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
/* Now send the events */
|
||||
litest_event(mouse, EV_REL, REL_X, -1);
|
||||
litest_event(mouse, EV_REL, REL_Y, 1);
|
||||
litest_event(mouse, EV_SYN, SYN_REPORT, 0);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_touch_down(dev, 0, 20, 30);
|
||||
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10);
|
||||
litest_touch_up(dev, 0);
|
||||
|
|
@ -5862,12 +5875,15 @@ END_TEST
|
|||
START_TEST(touchpad_disabled_double_mouse)
|
||||
{
|
||||
struct litest_device *dev = litest_current_device();
|
||||
struct litest_device *mouse1, *mouse2;
|
||||
struct litest_device *nonsending_mouse, *sending_mouse;
|
||||
struct libinput *li = dev->libinput;
|
||||
enum libinput_config_status status;
|
||||
bool suspend = litest_test_param_get_bool(test_env->params, "suspend");
|
||||
bool suspend_nonsending =
|
||||
litest_test_param_get_bool(test_env->params, "suspend-nonsending");
|
||||
int32_t remove = litest_test_param_get_i32(test_env->params, "remove");
|
||||
|
||||
litest_drain_events(li);
|
||||
litest_disable_hold_gestures(dev->libinput_device);
|
||||
|
||||
status = libinput_device_config_send_events_set_mode(
|
||||
dev->libinput_device,
|
||||
|
|
@ -5879,19 +5895,26 @@ START_TEST(touchpad_disabled_double_mouse)
|
|||
litest_touch_up(dev, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
mouse1 = litest_add_device(li, LITEST_MOUSE);
|
||||
mouse2 = litest_add_device(li, LITEST_MOUSE_LOW_DPI);
|
||||
nonsending_mouse = litest_add_device(li, LITEST_MOUSE);
|
||||
sending_mouse = litest_add_device(li, LITEST_MOUSE_LOW_DPI);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_ADDED);
|
||||
|
||||
/* Mouse hasn't sent events yet */
|
||||
litest_touch_down(dev, 0, 20, 30);
|
||||
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
if (suspend) {
|
||||
/* Now send the events */
|
||||
litest_event(sending_mouse, EV_REL, REL_X, -1);
|
||||
litest_event(sending_mouse, EV_REL, REL_Y, 1);
|
||||
litest_event(sending_mouse, EV_SYN, SYN_REPORT, 0);
|
||||
litest_drain_events(li);
|
||||
|
||||
if (suspend_nonsending) {
|
||||
/* Disable one external mouse -> don't expect touchpad events */
|
||||
status = libinput_device_config_send_events_set_mode(
|
||||
mouse1->libinput_device,
|
||||
nonsending_mouse->libinput_device,
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED);
|
||||
litest_assert_enum_eq(status, LIBINPUT_CONFIG_STATUS_SUCCESS);
|
||||
}
|
||||
|
|
@ -5901,15 +5924,34 @@ START_TEST(touchpad_disabled_double_mouse)
|
|||
litest_touch_up(dev, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_device_destroy(mouse1);
|
||||
switch (remove) {
|
||||
case 1:
|
||||
litest_device_destroy(steal(&nonsending_mouse));
|
||||
break;
|
||||
case 2:
|
||||
litest_device_destroy(steal(&sending_mouse));
|
||||
break;
|
||||
}
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
|
||||
|
||||
litest_touch_down(dev, 0, 20, 30);
|
||||
litest_touch_move_to(dev, 0, 20, 30, 90, 30, 10);
|
||||
litest_touch_up(dev, 0);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
litest_device_destroy(mouse2);
|
||||
/* Removing the only mouse that sent events should resume our touchpad */
|
||||
switch (remove) {
|
||||
case 1:
|
||||
litest_assert_empty_queue(li);
|
||||
break;
|
||||
case 2:
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
break;
|
||||
}
|
||||
|
||||
if (sending_mouse)
|
||||
litest_device_destroy(steal(&sending_mouse));
|
||||
if (nonsending_mouse)
|
||||
litest_device_destroy(steal(&nonsending_mouse));
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_DEVICE_REMOVED);
|
||||
|
||||
litest_touch_down(dev, 0, 20, 30);
|
||||
|
|
@ -7072,6 +7114,12 @@ TEST_COLLECTION(touchpad)
|
|||
|
||||
litest_with_parameters(params, "suspend", 'b') {
|
||||
litest_add_parametrized_for_device(touchpad_disabled_on_mouse, LITEST_SYNAPTICS_CLICKPAD_X220, params);
|
||||
}
|
||||
|
||||
litest_with_parameters(params,
|
||||
"suspend-nonsending", 'b',
|
||||
"remove", 'I', 2, litest_named_i32(2, "sending-mouse"),
|
||||
litest_named_i32(1, "nonsending-mouse")) {
|
||||
litest_add_parametrized_for_device(touchpad_disabled_double_mouse, LITEST_SYNAPTICS_CLICKPAD_X220, params);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue