mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-02-03 11:10:29 +01:00
fallback: suspend internal keyboards and trackpoints on tablet-mode switch
Because on some devices the keyboard is where the fingers are holding the device when in tablet mode. https://bugs.freedesktop.org/show_bug.cgi?id=102729 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
350ce2b3f1
commit
84d49ee49c
2 changed files with 269 additions and 6 deletions
|
|
@ -66,7 +66,16 @@ struct fallback_dispatch {
|
|||
struct device_coords rel;
|
||||
|
||||
struct {
|
||||
int state;
|
||||
/* The struct for the tablet mode switch device itself */
|
||||
struct {
|
||||
int state;
|
||||
} sw;
|
||||
/* The struct for other devices listening to the tablet mode
|
||||
switch */
|
||||
struct {
|
||||
struct evdev_device *sw_device;
|
||||
struct libinput_event_listener listener;
|
||||
} other;
|
||||
} tablet_mode;
|
||||
|
||||
/* Bitmask of pressed keys used to ignore initial release events from
|
||||
|
|
@ -181,7 +190,7 @@ fallback_interface_get_switch_state(struct evdev_dispatch *evdev_dispatch,
|
|||
abort();
|
||||
}
|
||||
|
||||
return dispatch->tablet_mode.state ?
|
||||
return dispatch->tablet_mode.sw.state ?
|
||||
LIBINPUT_SWITCH_STATE_ON :
|
||||
LIBINPUT_SWITCH_STATE_OFF;
|
||||
}
|
||||
|
|
@ -992,10 +1001,10 @@ fallback_process_switch(struct fallback_dispatch *dispatch,
|
|||
fallback_lid_notify_toggle(dispatch, device, time);
|
||||
break;
|
||||
case SW_TABLET_MODE:
|
||||
if (dispatch->tablet_mode.state == e->value)
|
||||
if (dispatch->tablet_mode.sw.state == e->value)
|
||||
return;
|
||||
|
||||
dispatch->tablet_mode.state = e->value;
|
||||
dispatch->tablet_mode.sw.state = e->value;
|
||||
if (e->value)
|
||||
state = LIBINPUT_SWITCH_STATE_ON;
|
||||
else
|
||||
|
|
@ -1263,6 +1272,8 @@ fallback_interface_remove(struct evdev_dispatch *evdev_dispatch)
|
|||
struct fallback_dispatch *dispatch = fallback_dispatch(evdev_dispatch);
|
||||
struct paired_keyboard *kbd;
|
||||
|
||||
libinput_device_remove_event_listener(&dispatch->tablet_mode.other.listener);
|
||||
|
||||
ARRAY_FOR_EACH(dispatch->lid.paired_keyboard, kbd) {
|
||||
if (!kbd->device)
|
||||
continue;
|
||||
|
|
@ -1299,7 +1310,7 @@ fallback_interface_sync_initial_state(struct evdev_device *device,
|
|||
}
|
||||
}
|
||||
|
||||
if (dispatch->tablet_mode.state) {
|
||||
if (dispatch->tablet_mode.sw.state) {
|
||||
switch_notify_toggle(&device->base,
|
||||
time,
|
||||
LIBINPUT_SWITCH_TABLET_MODE,
|
||||
|
|
@ -1377,11 +1388,94 @@ fallback_lid_pair_keyboard(struct evdev_device *lid_switch,
|
|||
"lid: too many internal keyboards\n");
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_resume(struct fallback_dispatch *dispatch,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
if (dispatch->base.sendevents.current_mode ==
|
||||
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED)
|
||||
return;
|
||||
|
||||
evdev_device_resume(device);
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_suspend(struct fallback_dispatch *dispatch,
|
||||
struct evdev_device *device)
|
||||
{
|
||||
evdev_device_suspend(device);
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_tablet_mode_switch_event(uint64_t time,
|
||||
struct libinput_event *event,
|
||||
void *data)
|
||||
{
|
||||
struct fallback_dispatch *dispatch = data;
|
||||
struct evdev_device *device = dispatch->device;
|
||||
struct libinput_event_switch *swev;
|
||||
|
||||
if (libinput_event_get_type(event) != LIBINPUT_EVENT_SWITCH_TOGGLE)
|
||||
return;
|
||||
|
||||
swev = libinput_event_get_switch_event(event);
|
||||
if (libinput_event_switch_get_switch(swev) !=
|
||||
LIBINPUT_SWITCH_TABLET_MODE)
|
||||
return;
|
||||
|
||||
|
||||
switch (libinput_event_switch_get_switch_state(swev)) {
|
||||
case LIBINPUT_SWITCH_STATE_OFF:
|
||||
fallback_resume(dispatch, device);
|
||||
evdev_log_debug(device, "tablet-mode: resuming device\n");
|
||||
break;
|
||||
case LIBINPUT_SWITCH_STATE_ON:
|
||||
fallback_suspend(dispatch, device);
|
||||
evdev_log_debug(device, "tablet-mode: suspending device\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_keyboard_pair_tablet_mode(struct evdev_device *keyboard,
|
||||
struct evdev_device *tablet_mode_switch)
|
||||
{
|
||||
struct fallback_dispatch *dispatch =
|
||||
fallback_dispatch(keyboard->dispatch);
|
||||
|
||||
if ((keyboard->tags &
|
||||
(EVDEV_TAG_TRACKPOINT|EVDEV_TAG_INTERNAL_KEYBOARD)) == 0)
|
||||
return;
|
||||
|
||||
if ((tablet_mode_switch->tags & EVDEV_TAG_TABLET_MODE_SWITCH) == 0)
|
||||
return;
|
||||
|
||||
if (dispatch->tablet_mode.other.sw_device)
|
||||
return;
|
||||
|
||||
evdev_log_debug(keyboard,
|
||||
"tablet_mode_switch: activated for %s<->%s\n",
|
||||
keyboard->devname,
|
||||
tablet_mode_switch->devname);
|
||||
|
||||
libinput_device_add_event_listener(&tablet_mode_switch->base,
|
||||
&dispatch->tablet_mode.other.listener,
|
||||
fallback_tablet_mode_switch_event,
|
||||
dispatch);
|
||||
dispatch->tablet_mode.other.sw_device = tablet_mode_switch;
|
||||
|
||||
if (evdev_device_switch_get_state(tablet_mode_switch,
|
||||
LIBINPUT_SWITCH_TABLET_MODE)
|
||||
== LIBINPUT_SWITCH_STATE_ON)
|
||||
fallback_suspend(dispatch, keyboard);
|
||||
}
|
||||
|
||||
static void
|
||||
fallback_interface_device_added(struct evdev_device *device,
|
||||
struct evdev_device *added_device)
|
||||
{
|
||||
fallback_lid_pair_keyboard(device, added_device);
|
||||
fallback_keyboard_pair_tablet_mode(device, added_device);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1403,6 +1497,14 @@ fallback_interface_device_removed(struct evdev_device *device,
|
|||
libinput_device_init_event_listener(&kbd->listener);
|
||||
kbd->device = NULL;
|
||||
}
|
||||
|
||||
if (removed_device == dispatch->tablet_mode.other.sw_device) {
|
||||
libinput_device_remove_event_listener(
|
||||
&dispatch->tablet_mode.other.listener);
|
||||
libinput_device_init_event_listener(
|
||||
&dispatch->tablet_mode.other.listener);
|
||||
dispatch->tablet_mode.other.sw_device = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct evdev_dispatch_interface fallback_interface = {
|
||||
|
|
@ -1602,8 +1704,10 @@ fallback_dispatch_init_switch(struct fallback_dispatch *dispatch,
|
|||
val = libevdev_get_event_value(device->evdev,
|
||||
EV_SW,
|
||||
SW_TABLET_MODE);
|
||||
dispatch->tablet_mode.state = val;
|
||||
dispatch->tablet_mode.sw.state = val;
|
||||
}
|
||||
|
||||
libinput_device_init_event_listener(&dispatch->tablet_mode.other.listener);
|
||||
}
|
||||
|
||||
struct evdev_dispatch *
|
||||
|
|
|
|||
|
|
@ -864,6 +864,161 @@ START_TEST(tablet_mode_disable_touchpad_on_init)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_mode_disable_keyboard)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
struct libinput *li = sw->libinput;
|
||||
|
||||
if (!switch_has_tablet_mode(sw))
|
||||
return;
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_switch_action(sw,
|
||||
LIBINPUT_SWITCH_TABLET_MODE,
|
||||
LIBINPUT_SWITCH_STATE_ON);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
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_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_mode_disable_keyboard_on_init)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
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);
|
||||
|
||||
/* keyboard comes with switch already on - no events */
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
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_keyboard_key(keyboard, KEY_A, true);
|
||||
litest_keyboard_key(keyboard, KEY_A, false);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(tablet_mode_disable_trackpoint)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *trackpoint;
|
||||
struct libinput *li = sw->libinput;
|
||||
|
||||
if (!switch_has_tablet_mode(sw))
|
||||
return;
|
||||
|
||||
trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_switch_action(sw,
|
||||
LIBINPUT_SWITCH_TABLET_MODE,
|
||||
LIBINPUT_SWITCH_STATE_ON);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 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_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(trackpoint);
|
||||
}
|
||||
END_TEST
|
||||
START_TEST(tablet_mode_disable_trackpoint_on_init)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *trackpoint;
|
||||
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);
|
||||
|
||||
/* trackpoint comes with switch already on - no events */
|
||||
trackpoint = litest_add_device(li, LITEST_TRACKPOINT);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 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_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(trackpoint, EV_REL, REL_Y, -1);
|
||||
litest_event(trackpoint, EV_SYN, SYN_REPORT, 0);
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(trackpoint);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests_lid(void)
|
||||
{
|
||||
|
|
@ -896,4 +1051,8 @@ litest_setup_tests_lid(void)
|
|||
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);
|
||||
litest_add("tablet-mode:keyboard", tablet_mode_disable_keyboard, LITEST_SWITCH, LITEST_ANY);
|
||||
litest_add("tablet-mode:keyboard", tablet_mode_disable_keyboard_on_init, LITEST_SWITCH, LITEST_ANY);
|
||||
litest_add("tablet-mode:trackpoint", tablet_mode_disable_trackpoint, LITEST_SWITCH, LITEST_ANY);
|
||||
litest_add("tablet-mode:trackpoint", tablet_mode_disable_trackpoint_on_init, LITEST_SWITCH, LITEST_ANY);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue