mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2026-01-04 17:50:15 +01:00
switch: hook up to keyboard events to fix the lid switch state
Extra insurance against broken lid switches. Listen to events from the (internal) keyboard when we are logically closed. If any, assume we're open after all and update accordingly. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
d17e84fc0f
commit
4eb29a8cc5
2 changed files with 174 additions and 4 deletions
110
src/evdev-lid.c
110
src/evdev-lid.c
|
|
@ -30,10 +30,56 @@
|
|||
|
||||
struct lid_switch_dispatch {
|
||||
struct evdev_dispatch base;
|
||||
struct evdev_device *device;
|
||||
|
||||
bool lid_is_closed;
|
||||
|
||||
struct {
|
||||
struct evdev_device *keyboard;
|
||||
struct libinput_event_listener listener;
|
||||
} keyboard;
|
||||
};
|
||||
|
||||
static void
|
||||
lid_switch_keyboard_event(uint64_t time,
|
||||
struct libinput_event *event,
|
||||
void *data)
|
||||
{
|
||||
struct lid_switch_dispatch *dispatch =
|
||||
(struct lid_switch_dispatch*)data;
|
||||
|
||||
if (!dispatch->lid_is_closed)
|
||||
return;
|
||||
|
||||
if (event->type != LIBINPUT_EVENT_KEYBOARD_KEY)
|
||||
return;
|
||||
|
||||
dispatch->lid_is_closed = false;
|
||||
switch_notify_toggle(&dispatch->device->base,
|
||||
time,
|
||||
LIBINPUT_SWITCH_LID,
|
||||
dispatch->lid_is_closed);
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_toggle_keyboard_listener(struct lid_switch_dispatch *dispatch,
|
||||
bool is_closed)
|
||||
{
|
||||
if (!dispatch->keyboard.keyboard)
|
||||
return;
|
||||
|
||||
if (is_closed) {
|
||||
libinput_device_add_event_listener(
|
||||
&dispatch->keyboard.keyboard->base,
|
||||
&dispatch->keyboard.listener,
|
||||
lid_switch_keyboard_event,
|
||||
dispatch);
|
||||
} else {
|
||||
libinput_device_remove_event_listener(
|
||||
&dispatch->keyboard.listener);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_process_switch(struct lid_switch_dispatch *dispatch,
|
||||
struct evdev_device *device,
|
||||
|
|
@ -49,7 +95,11 @@ lid_switch_process_switch(struct lid_switch_dispatch *dispatch,
|
|||
if (dispatch->lid_is_closed == is_closed)
|
||||
return;
|
||||
|
||||
lid_switch_toggle_keyboard_listener(dispatch,
|
||||
is_closed);
|
||||
|
||||
dispatch->lid_is_closed = is_closed;
|
||||
|
||||
switch_notify_toggle(&device->base,
|
||||
time,
|
||||
LIBINPUT_SWITCH_LID,
|
||||
|
|
@ -107,6 +157,56 @@ lid_switch_destroy(struct evdev_dispatch *evdev_dispatch)
|
|||
free(dispatch);
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_pair_keyboard(struct evdev_device *lid_switch,
|
||||
struct evdev_device *keyboard)
|
||||
{
|
||||
struct lid_switch_dispatch *dispatch =
|
||||
(struct lid_switch_dispatch*)lid_switch->dispatch;
|
||||
unsigned int bus_kbd = libevdev_get_id_bustype(keyboard->evdev);
|
||||
|
||||
if ((keyboard->tags & EVDEV_TAG_KEYBOARD) == 0)
|
||||
return;
|
||||
|
||||
/* If we already have a keyboard paired, override it if the new one
|
||||
* is a serio device. Otherwise keep the current one */
|
||||
if (dispatch->keyboard.keyboard) {
|
||||
if (bus_kbd != BUS_I8042)
|
||||
return;
|
||||
libinput_device_remove_event_listener(&dispatch->keyboard.listener);
|
||||
}
|
||||
|
||||
dispatch->keyboard.keyboard = keyboard;
|
||||
log_debug(evdev_libinput_context(lid_switch),
|
||||
"lid: keyboard paired with %s<->%s\n",
|
||||
lid_switch->devname,
|
||||
keyboard->devname);
|
||||
|
||||
/* We don't init the event listener yet - we don't care about
|
||||
* keyboard events until the lid is closed */
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_interface_device_added(struct evdev_device *device,
|
||||
struct evdev_device *added_device)
|
||||
{
|
||||
lid_switch_pair_keyboard(device, added_device);
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_interface_device_removed(struct evdev_device *device,
|
||||
struct evdev_device *removed_device)
|
||||
{
|
||||
struct lid_switch_dispatch *dispatch =
|
||||
(struct lid_switch_dispatch*)device->dispatch;
|
||||
|
||||
if (removed_device == dispatch->keyboard.keyboard) {
|
||||
libinput_device_remove_event_listener(
|
||||
&dispatch->keyboard.listener);
|
||||
dispatch->keyboard.keyboard = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
lid_switch_sync_initial_state(struct evdev_device *device,
|
||||
struct evdev_dispatch *evdev_dispatch)
|
||||
|
|
@ -148,10 +248,10 @@ struct evdev_dispatch_interface lid_switch_interface = {
|
|||
NULL, /* suspend */
|
||||
NULL, /* remove */
|
||||
lid_switch_destroy,
|
||||
NULL, /* device_added */
|
||||
NULL, /* device_removed */
|
||||
NULL, /* device_suspended */
|
||||
NULL, /* device_resumed */
|
||||
lid_switch_interface_device_added,
|
||||
lid_switch_interface_device_removed,
|
||||
lid_switch_interface_device_removed, /* device_suspended, treat as remove */
|
||||
lid_switch_interface_device_added, /* device_resumed, treat as add */
|
||||
lid_switch_sync_initial_state,
|
||||
NULL, /* toggle_touch */
|
||||
};
|
||||
|
|
@ -165,6 +265,8 @@ evdev_lid_switch_dispatch_create(struct evdev_device *lid_device)
|
|||
return NULL;
|
||||
|
||||
dispatch->base.interface = &lid_switch_interface;
|
||||
dispatch->device = lid_device;
|
||||
libinput_device_init_event_listener(&dispatch->keyboard.listener);
|
||||
|
||||
evdev_init_sendevents(lid_device, &dispatch->base);
|
||||
|
||||
|
|
|
|||
|
|
@ -293,6 +293,71 @@ START_TEST(lid_disable_touchpad_already_open)
|
|||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(lid_open_on_key)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *keyboard;
|
||||
struct libinput *li = sw->libinput;
|
||||
struct libinput_event *event;
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
|
||||
litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(keyboard, EV_KEY, KEY_A, 1);
|
||||
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(keyboard, EV_KEY, KEY_A, 0);
|
||||
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_wait_for_event_of_type(li, LIBINPUT_EVENT_SWITCH_TOGGLE, -1);
|
||||
event = libinput_get_event(li);
|
||||
litest_is_switch_event(event,
|
||||
LIBINPUT_SWITCH_LID,
|
||||
LIBINPUT_SWITCH_STATE_OFF);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_KEYBOARD_KEY);
|
||||
|
||||
litest_lid_action(sw, LIBINPUT_SWITCH_STATE_OFF);
|
||||
litest_assert_empty_queue(li);
|
||||
|
||||
libinput_event_destroy(event);
|
||||
litest_delete_device(keyboard);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(lid_open_on_key_touchpad_enabled)
|
||||
{
|
||||
struct litest_device *sw = litest_current_device();
|
||||
struct litest_device *keyboard, *touchpad;
|
||||
struct libinput *li = sw->libinput;
|
||||
|
||||
keyboard = litest_add_device(li, LITEST_KEYBOARD);
|
||||
touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C);
|
||||
|
||||
litest_lid_action(sw, LIBINPUT_SWITCH_STATE_ON);
|
||||
litest_drain_events(li);
|
||||
|
||||
litest_event(keyboard, EV_KEY, KEY_A, 1);
|
||||
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||
litest_event(keyboard, EV_KEY, KEY_A, 0);
|
||||
litest_event(keyboard, EV_SYN, SYN_REPORT, 0);
|
||||
litest_drain_events(li);
|
||||
litest_timeout_dwt_long();
|
||||
|
||||
litest_touch_down(touchpad, 0, 50, 50);
|
||||
litest_touch_move_to(touchpad, 0, 50, 50, 70, 70, 10, 1);
|
||||
litest_touch_up(touchpad, 0);
|
||||
libinput_dispatch(li);
|
||||
|
||||
litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
|
||||
|
||||
litest_delete_device(keyboard);
|
||||
litest_delete_device(touchpad);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
litest_setup_tests_lid(void)
|
||||
{
|
||||
|
|
@ -304,4 +369,7 @@ litest_setup_tests_lid(void)
|
|||
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("lid:keyboard", lid_open_on_key, LITEST_SWITCH, LITEST_ANY);
|
||||
litest_add("lid:keyboard", lid_open_on_key_touchpad_enabled, LITEST_SWITCH, LITEST_ANY);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue