summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2017-09-01 17:30:08 +1000
committerPeter Hutterer <peter.hutterer@who-t.net>2017-09-06 09:26:00 +1000
commit986604fd9d86e92a2f04499ca23970f440201349 (patch)
tree17178b82efc60c061b1106d2426f703bef576ddf
parent82f2dd8faa0f78351f0c59431a374166cb851c9e (diff)
touchpad: if a device has a tablet mode switch, disable the touchpad
On some devices with a tablet mode switch, the touchpad is inacessible when in tablet mode and we don't really need this except to avoid possible ghost touches (none have been mentioned so far). On other devices like the Lenovo Yoga, the touchpad points to the back of the device and it's hard to use the device without accidentally using the touchpad. For those, disabling the touchpad is the best solution. https://bugs.freedesktop.org/show_bug.cgi?id=102408 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
-rw-r--r--src/evdev-mt-touchpad.c58
-rw-r--r--src/evdev-mt-touchpad.h5
-rw-r--r--src/evdev.c19
-rw-r--r--src/evdev.h4
-rw-r--r--test/test-switch.c177
5 files changed, 198 insertions, 65 deletions
diff --git a/src/evdev-mt-touchpad.c b/src/evdev-mt-touchpad.c
index 58595785..eb3dde3c 100644
--- a/src/evdev-mt-touchpad.c
+++ b/src/evdev-mt-touchpad.c
@@ -1479,6 +1479,10 @@ tp_remove_sendevents(struct tp_dispatch *tp)
if (tp->lid_switch.lid_switch)
libinput_device_remove_event_listener(
&tp->lid_switch.listener);
+
+ if (tp->tablet_mode_switch.tablet_mode_switch)
+ libinput_device_remove_event_listener(
+ &tp->tablet_mode_switch.listener);
}
static void
@@ -1861,23 +1865,34 @@ tp_pair_trackpoint(struct evdev_device *touchpad,
}
static void
-tp_lid_switch_event(uint64_t time, struct libinput_event *event, void *data)
+tp_switch_event(uint64_t time, struct libinput_event *event, void *data)
{
struct tp_dispatch *tp = data;
struct libinput_event_switch *swev;
+ const char *which = NULL;
if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE)
return;
swev = libinput_event_get_switch_event(event);
+
+ switch (libinput_event_switch_get_switch(swev)) {
+ case LIBINPUT_SWITCH_LID:
+ which = "lid";
+ break;
+ case LIBINPUT_SWITCH_TABLET_MODE:
+ which = "tablet-mode";
+ break;
+ }
+
switch (libinput_event_switch_get_switch_state(swev)) {
case LIBINPUT_SWITCH_STATE_OFF:
tp_resume(tp, tp->device);
- evdev_log_debug(tp->device, "lid: resume touchpad\n");
+ evdev_log_debug(tp->device, "%s: resume touchpad\n", which);
break;
case LIBINPUT_SWITCH_STATE_ON:
tp_suspend(tp, tp->device);
- evdev_log_debug(tp->device, "lid: suspend touchpad\n");
+ evdev_log_debug(tp->device, "%s: suspend touchpad\n", which);
break;
}
}
@@ -1899,12 +1914,40 @@ tp_pair_lid_switch(struct evdev_device *touchpad,
libinput_device_add_event_listener(&lid_switch->base,
&tp->lid_switch.listener,
- tp_lid_switch_event, tp);
+ tp_switch_event, tp);
tp->lid_switch.lid_switch = lid_switch;
}
}
static void
+tp_pair_tablet_mode_switch(struct evdev_device *touchpad,
+ struct evdev_device *tablet_mode_switch)
+{
+ struct tp_dispatch *tp = (struct tp_dispatch*)touchpad->dispatch;
+
+ if ((tablet_mode_switch->tags & EVDEV_TAG_TABLET_MODE_SWITCH) == 0)
+ return;
+
+ if (tp->tablet_mode_switch.tablet_mode_switch == NULL) {
+ evdev_log_debug(touchpad,
+ "tablet_mode_switch: activated for %s<->%s\n",
+ touchpad->devname,
+ tablet_mode_switch->devname);
+
+ libinput_device_add_event_listener(&tablet_mode_switch->base,
+ &tp->tablet_mode_switch.listener,
+ tp_switch_event, tp);
+ tp->tablet_mode_switch.tablet_mode_switch = tablet_mode_switch;
+
+ if (evdev_device_switch_get_state(tablet_mode_switch,
+ LIBINPUT_SWITCH_TABLET_MODE)
+ == LIBINPUT_SWITCH_STATE_ON) {
+ tp_suspend(tp, touchpad);
+ }
+ }
+}
+
+static void
tp_interface_device_added(struct evdev_device *device,
struct evdev_device *added_device)
{
@@ -1913,6 +1956,7 @@ tp_interface_device_added(struct evdev_device *device,
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);
if (tp->sendevents.current_mode !=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
@@ -1954,6 +1998,12 @@ tp_interface_device_removed(struct evdev_device *device,
tp->lid_switch.lid_switch = NULL;
}
+ if (removed_device == tp->tablet_mode_switch.tablet_mode_switch) {
+ libinput_device_remove_event_listener(
+ &tp->tablet_mode_switch.listener);
+ tp->tablet_mode_switch.tablet_mode_switch = NULL;
+ }
+
if (tp->sendevents.current_mode !=
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE)
return;
diff --git a/src/evdev-mt-touchpad.h b/src/evdev-mt-touchpad.h
index 4c667eff..efbdb3bf 100644
--- a/src/evdev-mt-touchpad.h
+++ b/src/evdev-mt-touchpad.h
@@ -407,6 +407,11 @@ struct tp_dispatch {
struct libinput_event_listener listener;
struct evdev_device *lid_switch;
} lid_switch;
+
+ struct {
+ struct libinput_event_listener listener;
+ struct evdev_device *tablet_mode_switch;
+ } tablet_mode_switch;
};
static inline struct tp_dispatch*
diff --git a/src/evdev.c b/src/evdev.c
index f9d8d34a..46f8ad57 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -185,6 +185,25 @@ fallback_lid_notify_toggle(struct fallback_dispatch *dispatch,
}
}
+enum libinput_switch_state
+evdev_device_switch_get_state(struct evdev_device *device,
+ enum libinput_switch sw)
+{
+ struct fallback_dispatch *dispatch = fallback_dispatch(device->dispatch);
+
+ switch (sw) {
+ case LIBINPUT_SWITCH_TABLET_MODE:
+ break;
+ default:
+ /* Internal function only, so we can abort here */
+ abort();
+ }
+
+ return dispatch->tablet_mode.state ?
+ LIBINPUT_SWITCH_STATE_ON :
+ LIBINPUT_SWITCH_STATE_OFF;
+}
+
void
evdev_pointer_notify_physical_button(struct evdev_device *device,
uint64_t time,
diff --git a/src/evdev.h b/src/evdev.h
index 4895c2ec..5192927c 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -524,6 +524,10 @@ struct libinput_tablet_pad_mode_group *
evdev_device_tablet_pad_get_mode_group(struct evdev_device *device,
unsigned int index);
+enum libinput_switch_state
+evdev_device_switch_get_state(struct evdev_device *device,
+ enum libinput_switch sw);
+
double
evdev_device_transform_x(struct evdev_device *device,
double x,
diff --git a/test/test-switch.c b/test/test-switch.c
index 59809798..77ba5593 100644
--- a/test/test-switch.c
+++ b/test/test-switch.c
@@ -36,6 +36,13 @@ switch_has_lid(struct litest_device *dev)
LIBINPUT_SWITCH_LID);
}
+static inline bool
+switch_has_tablet_mode(struct litest_device *dev)
+{
+ return libinput_device_switch_has_switch(dev->libinput_device,
+ LIBINPUT_SWITCH_TABLET_MODE);
+}
+
START_TEST(switch_has_cap)
{
struct litest_device *dev = litest_current_device();
@@ -228,30 +235,29 @@ START_TEST(switch_not_down_on_init)
END_TEST
static inline struct litest_device *
-lid_init_paired_touchpad(struct libinput *li)
+switch_init_paired_touchpad(struct libinput *li)
{
enum litest_device_type which = LITEST_SYNAPTICS_I2C;
return litest_add_device(li, which);
}
-START_TEST(lid_disable_touchpad)
+START_TEST(switch_disable_touchpad)
{
struct litest_device *sw = litest_current_device();
struct litest_device *touchpad;
struct libinput *li = sw->libinput;
+ enum libinput_switch which = _i; /* ranged test */
- if (!switch_has_lid(sw))
+ if (!libinput_device_switch_has_switch(sw->libinput_device, which))
return;
- touchpad = lid_init_paired_touchpad(li);
+ touchpad = switch_init_paired_touchpad(li);
litest_disable_tap(touchpad->libinput_device);
litest_drain_events(li);
- /* lid is down - no events */
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ /* switch is on - no events */
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
litest_touch_down(touchpad, 0, 50, 50);
@@ -259,10 +265,8 @@ START_TEST(lid_disable_touchpad)
litest_touch_up(touchpad, 0);
litest_assert_empty_queue(li);
- /* lid is up - motion events */
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_OFF);
+ /* switch is off - motion events */
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
litest_touch_down(touchpad, 0, 50, 50);
@@ -274,16 +278,17 @@ START_TEST(lid_disable_touchpad)
}
END_TEST
-START_TEST(lid_disable_touchpad_during_touch)
+START_TEST(switch_disable_touchpad_during_touch)
{
struct litest_device *sw = litest_current_device();
struct litest_device *touchpad;
struct libinput *li = sw->libinput;
+ enum libinput_switch which = _i; /* ranged test */
- if (!switch_has_lid(sw))
+ if (!libinput_device_switch_has_switch(sw->libinput_device, which))
return;
- touchpad = lid_init_paired_touchpad(li);
+ touchpad = switch_init_paired_touchpad(li);
litest_disable_tap(touchpad->libinput_device);
litest_drain_events(li);
@@ -291,9 +296,7 @@ START_TEST(lid_disable_touchpad_during_touch)
litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 5, 1);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
litest_touch_move_to(touchpad, 0, 70, 50, 50, 50, 5, 1);
@@ -304,23 +307,22 @@ START_TEST(lid_disable_touchpad_during_touch)
}
END_TEST
-START_TEST(lid_disable_touchpad_edge_scroll)
+START_TEST(switch_disable_touchpad_edge_scroll)
{
struct litest_device *sw = litest_current_device();
struct litest_device *touchpad;
struct libinput *li = sw->libinput;
+ enum libinput_switch which = _i; /* ranged test */
- if (!switch_has_lid(sw))
+ if (!libinput_device_switch_has_switch(sw->libinput_device, which))
return;
- touchpad = lid_init_paired_touchpad(li);
+ touchpad = switch_init_paired_touchpad(li);
litest_enable_edge_scroll(touchpad);
litest_drain_events(li);
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
litest_touch_down(touchpad, 0, 99, 20);
@@ -342,17 +344,18 @@ START_TEST(lid_disable_touchpad_edge_scroll)
}
END_TEST
-START_TEST(lid_disable_touchpad_edge_scroll_interrupt)
+START_TEST(switch_disable_touchpad_edge_scroll_interrupt)
{
struct litest_device *sw = litest_current_device();
struct litest_device *touchpad;
struct libinput *li = sw->libinput;
struct libinput_event *event;
+ enum libinput_switch which = _i; /* ranged test */
- if (!switch_has_lid(sw))
+ if (!libinput_device_switch_has_switch(sw->libinput_device, which))
return;
- touchpad = lid_init_paired_touchpad(li);
+ touchpad = switch_init_paired_touchpad(li);
litest_enable_edge_scroll(touchpad);
litest_drain_events(li);
@@ -364,9 +367,7 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt)
libinput_dispatch(li);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_AXIS);
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON);
libinput_dispatch(li);
event = libinput_get_event(li);
@@ -376,38 +377,36 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt)
libinput_event_destroy(event);
event = libinput_get_event(li);
- litest_is_switch_event(event,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ litest_is_switch_event(event, which, LIBINPUT_SWITCH_STATE_ON);
libinput_event_destroy(event);
litest_delete_device(touchpad);
}
END_TEST
-START_TEST(lid_disable_touchpad_already_open)
+START_TEST(switch_disable_touchpad_already_open)
{
struct litest_device *sw = litest_current_device();
struct litest_device *touchpad;
struct libinput *li = sw->libinput;
+ enum libinput_switch which = _i; /* ranged test */
- if (!switch_has_lid(sw))
+ if (!libinput_device_switch_has_switch(sw->libinput_device, which))
return;
- touchpad = lid_init_paired_touchpad(li);
+ touchpad = switch_init_paired_touchpad(li);
+
litest_disable_tap(touchpad->libinput_device);
litest_drain_events(li);
- /* default: lid is up - motion events */
+ /* default: switch is off - motion events */
litest_touch_down(touchpad, 0, 50, 50);
litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
litest_touch_up(touchpad, 0);
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
- /* open lid - motion events */
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_OFF);
+ /* disable switch - motion events */
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF);
litest_assert_empty_queue(li);
litest_touch_down(touchpad, 0, 50, 50);
@@ -495,27 +494,34 @@ START_TEST(lid_open_on_key_touchpad_enabled)
}
END_TEST
-START_TEST(lid_suspend_with_keyboard)
+START_TEST(switch_suspend_with_keyboard)
{
struct libinput *li;
struct litest_device *keyboard;
struct litest_device *sw;
+ enum libinput_switch which = _i; /* ranged test */
li = litest_create_context();
- sw = litest_add_device(li, LITEST_LID_SWITCH);
+ switch(which) {
+ case LIBINPUT_SWITCH_LID:
+ sw = litest_add_device(li, LITEST_LID_SWITCH);
+ break;
+ case LIBINPUT_SWITCH_TABLET_MODE:
+ sw = litest_add_device(li, LITEST_THINKPAD_EXTRABUTTONS);
+ break;
+ default:
+ abort();
+ }
+
libinput_dispatch(li);
keyboard = litest_add_device(li, LITEST_KEYBOARD);
libinput_dispatch(li);
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_ON);
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_ON);
litest_drain_events(li);
- litest_switch_action(sw,
- LIBINPUT_SWITCH_LID,
- LIBINPUT_SWITCH_STATE_OFF);
+ litest_switch_action(sw, which, LIBINPUT_SWITCH_STATE_OFF);
litest_drain_events(li);
litest_delete_device(keyboard);
@@ -528,14 +534,25 @@ START_TEST(lid_suspend_with_keyboard)
}
END_TEST
-START_TEST(lid_suspend_with_touchpad)
+START_TEST(switch_suspend_with_touchpad)
{
struct libinput *li;
struct litest_device *touchpad, *sw;
+ enum libinput_switch which = _i; /* ranged test */
li = litest_create_context();
- sw = litest_add_device(li, LITEST_LID_SWITCH);
+ switch(which) {
+ case LIBINPUT_SWITCH_LID:
+ sw = litest_add_device(li, LITEST_LID_SWITCH);
+ break;
+ case LIBINPUT_SWITCH_TABLET_MODE:
+ sw = litest_add_device(li, LITEST_THINKPAD_EXTRABUTTONS);
+ break;
+ default:
+ abort();
+ }
+
litest_drain_events(li);
touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
@@ -671,6 +688,44 @@ START_TEST(lid_key_press)
}
END_TEST
+START_TEST(tablet_mode_disable_touchpad_on_init)
+{
+ struct litest_device *sw = litest_current_device();
+ struct litest_device *touchpad;
+ struct libinput *li = sw->libinput;
+
+ if (!switch_has_tablet_mode(sw))
+ return;
+
+ litest_switch_action(sw,
+ LIBINPUT_SWITCH_TABLET_MODE,
+ LIBINPUT_SWITCH_STATE_ON);
+ litest_drain_events(li);
+
+ /* touchpad comes with switch already on - no events */
+ touchpad = switch_init_paired_touchpad(li);
+ litest_disable_tap(touchpad->libinput_device);
+ litest_drain_events(li);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_empty_queue(li);
+
+ litest_switch_action(sw,
+ LIBINPUT_SWITCH_TABLET_MODE,
+ LIBINPUT_SWITCH_STATE_OFF);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_SWITCH_TOGGLE);
+
+ litest_touch_down(touchpad, 0, 50, 50);
+ litest_touch_move_to(touchpad, 0, 50, 50, 70, 50, 10, 1);
+ litest_touch_up(touchpad, 0);
+ litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
+
+ litest_delete_device(touchpad);
+}
+END_TEST
+
void
litest_setup_tests_lid(void)
{
@@ -684,20 +739,20 @@ litest_setup_tests_lid(void)
litest_add_ranged("switch:toggle", switch_toggle_double, LITEST_SWITCH, LITEST_ANY, &switches);
litest_add_ranged("switch:toggle", switch_down_on_init, LITEST_SWITCH, LITEST_ANY, &switches);
litest_add("switch:toggle", switch_not_down_on_init, LITEST_SWITCH, LITEST_ANY);
- litest_add("lid:disable_touchpad", lid_disable_touchpad, LITEST_SWITCH, LITEST_ANY);
- litest_add("lid:disable_touchpad", lid_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY);
- litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll, LITEST_SWITCH, LITEST_ANY);
- litest_add("lid:disable_touchpad", lid_disable_touchpad_edge_scroll_interrupt, LITEST_SWITCH, LITEST_ANY);
- litest_add("lid:disable_touchpad", lid_disable_touchpad_already_open, LITEST_SWITCH, LITEST_ANY);
+ litest_add_ranged("switch:touchpad", switch_disable_touchpad, LITEST_SWITCH, LITEST_ANY, &switches);
+ litest_add_ranged("switch:touchpad", switch_disable_touchpad_during_touch, LITEST_SWITCH, LITEST_ANY, &switches);
+ litest_add_ranged("switch:touchpad", switch_disable_touchpad_edge_scroll, LITEST_SWITCH, LITEST_ANY, &switches);
+ litest_add_ranged("switch:touchpad", switch_disable_touchpad_edge_scroll_interrupt, LITEST_SWITCH, LITEST_ANY, &switches);
+ litest_add_ranged("switch:touchpad", switch_disable_touchpad_already_open, LITEST_SWITCH, LITEST_ANY, &switches);
+
+ litest_add_ranged_no_device("switch:keyboard", switch_suspend_with_keyboard, &switches);
+ litest_add_ranged_no_device("switch:touchpad", switch_suspend_with_touchpad, &switches);
litest_add("lid:keyboard", lid_open_on_key, LITEST_SWITCH, LITEST_ANY);
litest_add("lid:keyboard", lid_open_on_key_touchpad_enabled, LITEST_SWITCH, LITEST_ANY);
-
- litest_add_no_device("lid:keyboard", lid_suspend_with_keyboard);
- litest_add_no_device("lid:disable_touchpad", lid_suspend_with_touchpad);
-
litest_add_for_device("lid:buggy", lid_update_hw_on_key, LITEST_LID_SWITCH_SURFACE3);
litest_add_for_device("lid:buggy", lid_update_hw_on_key_closed_on_init, LITEST_LID_SWITCH_SURFACE3);
-
litest_add_for_device("lid:keypress", lid_key_press, LITEST_GPIO_KEYS);
+
+ litest_add("tablet-mode:touchpad", tablet_mode_disable_touchpad_on_init, LITEST_SWITCH, LITEST_ANY);
}