https://bugs.freedesktop.org/show_bug.cgi?id=101008
Signed-off-by: Peter Hutterer <peter.hutte...@who-t.net> --- meson.build | 1 + src/evdev.c | 57 +++++++++++++---- src/evdev.h | 5 ++ src/libinput.h | 16 +++++ test/litest-device-thinkpad-extrabuttons.c | 90 +++++++++++++++++++++++++++ test/litest.c | 5 ++ test/litest.h | 1 + test/test-switch.c | 98 +++++++++++++++++++++++++----- 8 files changed, 246 insertions(+), 27 deletions(-) create mode 100644 test/litest-device-thinkpad-extrabuttons.c diff --git a/meson.build b/meson.build index a20018ff..41381553 100644 --- a/meson.build +++ b/meson.build @@ -565,6 +565,7 @@ if get_option('tests') 'test/litest-device-synaptics-st.c', 'test/litest-device-synaptics-t440.c', 'test/litest-device-synaptics-x1-carbon-3rd.c', + 'test/litest-device-thinkpad-extrabuttons.c', 'test/litest-device-trackpoint.c', 'test/litest-device-touch-screen.c', 'test/litest-device-touchscreen-fuzz.c', diff --git a/src/evdev.c b/src/evdev.c index 9dec2c4f..f9d8d34a 100644 --- a/src/evdev.c +++ b/src/evdev.c @@ -1161,6 +1161,7 @@ fallback_process_switch(struct fallback_dispatch *dispatch, struct input_event *e, uint64_t time) { + enum libinput_switch_state state; bool is_closed; switch (e->code) { @@ -1174,6 +1175,20 @@ fallback_process_switch(struct fallback_dispatch *dispatch, dispatch->lid.is_closed = is_closed; fallback_lid_notify_toggle(dispatch, device, time); break; + case SW_TABLET_MODE: + if (dispatch->tablet_mode.state == e->value) + return; + + dispatch->tablet_mode.state = e->value; + if (e->value) + state = LIBINPUT_SWITCH_STATE_ON; + else + state = LIBINPUT_SWITCH_STATE_OFF; + switch_notify_toggle(&device->base, + time, + LIBINPUT_SWITCH_TABLET_MODE, + state); + break; } } @@ -1381,12 +1396,6 @@ evdev_tag_keyboard(struct evdev_device *device, } static void -evdev_tag_lid_switch(struct evdev_device *device) -{ - device->tags |= EVDEV_TAG_LID_SWITCH; -} - -static void fallback_process(struct evdev_dispatch *evdev_dispatch, struct evdev_device *device, struct input_event *event, @@ -1566,6 +1575,13 @@ fallback_sync_initial_state(struct evdev_device *device, fallback_lid_notify_toggle(dispatch, device, time); } } + + if (dispatch->tablet_mode.state) { + switch_notify_toggle(&device->base, + time, + LIBINPUT_SWITCH_TABLET_MODE, + LIBINPUT_SWITCH_STATE_ON); + } } static void @@ -2197,11 +2213,20 @@ static inline void fallback_dispatch_init_switch(struct fallback_dispatch *dispatch, struct evdev_device *device) { + int val; + if (device->tags & EVDEV_TAG_LID_SWITCH) { libinput_device_init_event_listener(&dispatch->lid.listener); dispatch->lid.reliability = evdev_read_switch_reliability_prop(device); dispatch->lid.is_closed = false; } + + if (device->tags & EVDEV_TAG_TABLET_MODE_SWITCH) { + val = libevdev_get_event_value(device->evdev, + EV_SW, + SW_TABLET_MODE); + dispatch->tablet_mode.state = val; + } } static struct evdev_dispatch * @@ -3115,11 +3140,18 @@ evdev_configure_device(struct evdev_device *device) evdev_log_info(device, "device is a touch device\n"); } - if (udev_tags & EVDEV_UDEV_TAG_SWITCH && - libevdev_has_event_code(evdev, EV_SW, SW_LID)) { - device->seat_caps |= EVDEV_DEVICE_SWITCH; - evdev_tag_lid_switch(device); - evdev_log_info(device, "device is a switch device\n"); + if (udev_tags & EVDEV_UDEV_TAG_SWITCH) { + if (libevdev_has_event_code(evdev, EV_SW, SW_LID)) { + device->seat_caps |= EVDEV_DEVICE_SWITCH; + device->tags |= EVDEV_TAG_LID_SWITCH; + evdev_log_info(device, "device is a switch device\n"); + } + + if (libevdev_has_event_code(evdev, EV_SW, SW_TABLET_MODE)) { + device->seat_caps |= EVDEV_DEVICE_SWITCH; + device->tags |= EVDEV_TAG_TABLET_MODE_SWITCH; + evdev_log_info(device, "device is a switch device\n"); + } } if (device->seat_caps & EVDEV_DEVICE_POINTER && @@ -3651,6 +3683,9 @@ evdev_device_has_switch(struct evdev_device *device, case LIBINPUT_SWITCH_LID: code = SW_LID; break; + case LIBINPUT_SWITCH_TABLET_MODE: + code = SW_TABLET_MODE; + break; default: return -1; } diff --git a/src/evdev.h b/src/evdev.h index 0b8b2791..4895c2ec 100644 --- a/src/evdev.h +++ b/src/evdev.h @@ -75,6 +75,7 @@ enum evdev_device_tags { EVDEV_TAG_LID_SWITCH = (1 << 5), EVDEV_TAG_INTERNAL_KEYBOARD = (1 << 6), EVDEV_TAG_EXTERNAL_KEYBOARD = (1 << 7), + EVDEV_TAG_TABLET_MODE_SWITCH = (1 << 8), }; enum evdev_middlebutton_state { @@ -376,6 +377,10 @@ struct fallback_dispatch { struct device_coords rel; + struct { + int state; + } tablet_mode; + /* Bitmask of pressed keys used to ignore initial release events from * the kernel. */ unsigned long hw_key_mask[NLONGS(KEY_CNT)]; diff --git a/src/libinput.h b/src/libinput.h index 0a9c9d87..1a06bc7c 100644 --- a/src/libinput.h +++ b/src/libinput.h @@ -624,6 +624,22 @@ enum libinput_switch { * LIBINPUT_SWITCH_STATE_OFF. */ LIBINPUT_SWITCH_LID = 1, + + /** + * This switch indicates whether the device is in normal laptop mode + * or behaves like a tablet-like device where the primary + * interaction is usually a touch screen. When in tablet mode, the + * keyboard and touchpad are usually inaccessible. + * + * If the switch is in state @ref LIBINPUT_SWITCH_STATE_OFF, the + * device is in laptop mode. If the switch is in state @ref + * LIBINPUT_SWITCH_STATE_ON, the device is in tablet mode and the + * keyboard or touchpad may not be accessible. + * + * It is up to the caller to identify which devices are inaccessible + * in tablet mode. + */ + LIBINPUT_SWITCH_TABLET_MODE, }; /** diff --git a/test/litest-device-thinkpad-extrabuttons.c b/test/litest-device-thinkpad-extrabuttons.c new file mode 100644 index 00000000..84541493 --- /dev/null +++ b/test/litest-device-thinkpad-extrabuttons.c @@ -0,0 +1,90 @@ +/* + * Copyright © 2017 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" + +#include "litest.h" +#include "litest-int.h" + +static void litest_extrabuttons_setup(void) +{ + struct litest_device *d = litest_create_device(LITEST_THINKPAD_EXTRABUTTONS); + litest_set_current_device(d); +} + +static struct input_id input_id = { + .bustype = 0x19, + .vendor = 0x17aa, + .product = 0x5054, +}; + +static int events[] = { + EV_KEY, KEY_MUTE, + EV_KEY, KEY_VOLUMEUP, + EV_KEY, KEY_VOLUMEDOWN, + EV_KEY, KEY_SCALE, + EV_KEY, KEY_SLEEP, + EV_KEY, KEY_FILE, + EV_KEY, KEY_PROG1, + EV_KEY, KEY_COFFEE, + EV_KEY, KEY_BACK, + EV_KEY, KEY_CONFIG, + EV_KEY, KEY_REFRESH, + EV_KEY, KEY_F20, + EV_KEY, KEY_F21, + EV_KEY, KEY_F24, + EV_KEY, KEY_SUSPEND, + EV_KEY, KEY_CAMERA, + EV_KEY, KEY_SEARCH, + EV_KEY, KEY_BRIGHTNESSDOWN, + EV_KEY, KEY_BRIGHTNESSUP, + EV_KEY, KEY_SWITCHVIDEOMODE, + EV_KEY, KEY_KBDILLUMTOGGLE, + EV_KEY, KEY_BATTERY, + EV_KEY, KEY_WLAN, + EV_KEY, KEY_UNKNOWN, + EV_KEY, KEY_ZOOM, + EV_KEY, KEY_FN_F1, + EV_KEY, KEY_FN_F10, + EV_KEY, KEY_FN_F11, + EV_KEY, KEY_VOICECOMMAND, + EV_KEY, KEY_BRIGHTNESS_MIN, + + EV_SW, SW_RFKILL_ALL, + EV_SW, SW_TABLET_MODE, + + -1, -1, +}; + +struct litest_test_device litest_thinkpad_extrabuttons_device = { + .type = LITEST_THINKPAD_EXTRABUTTONS, + .features = LITEST_KEYS | LITEST_SWITCH, + .shortname = "thinkpad-extrabuttons", + .setup = litest_extrabuttons_setup, + .interface = NULL, + + .name = "ThinkPad Extra Buttons", + .id = &input_id, + .events = events, + .absinfo = NULL, +}; diff --git a/test/litest.c b/test/litest.c index 82ca14db..1f238431 100644 --- a/test/litest.c +++ b/test/litest.c @@ -417,6 +417,7 @@ extern struct litest_test_device litest_appletouch_device; extern struct litest_test_device litest_gpio_keys_device; extern struct litest_test_device litest_ignored_mouse_device; extern struct litest_test_device litest_wacom_mobilestudio_13hdt_pad_device; +extern struct litest_test_device litest_thinkpad_extrabuttons_device; struct litest_test_device* devices[] = { &litest_synaptics_clickpad_device, @@ -485,6 +486,7 @@ struct litest_test_device* devices[] = { &litest_gpio_keys_device, &litest_ignored_mouse_device, &litest_wacom_mobilestudio_13hdt_pad_device, + &litest_thinkpad_extrabuttons_device, NULL, }; @@ -2189,6 +2191,9 @@ litest_switch_action(struct litest_device *dev, case LIBINPUT_SWITCH_LID: code = SW_LID; break; + case LIBINPUT_SWITCH_TABLET_MODE: + code = SW_TABLET_MODE; + break; default: litest_abort_msg("Invalid switch %d", sw); break; diff --git a/test/litest.h b/test/litest.h index 39aa882b..8643f32d 100644 --- a/test/litest.h +++ b/test/litest.h @@ -237,6 +237,7 @@ enum litest_device_type { LITEST_GPIO_KEYS, LITEST_IGNORED_MOUSE, LITEST_WACOM_MOBILESTUDIO_PRO_16_PAD, + LITEST_THINKPAD_EXTRABUTTONS, }; enum litest_device_feature { diff --git a/test/test-switch.c b/test/test-switch.c index 045f226e..59809798 100644 --- a/test/test-switch.c +++ b/test/test-switch.c @@ -29,6 +29,13 @@ #include "libinput-util.h" #include "litest.h" +static inline bool +switch_has_lid(struct litest_device *dev) +{ + return libinput_device_switch_has_switch(dev->libinput_device, + LIBINPUT_SWITCH_LID); +} + START_TEST(switch_has_cap) { struct litest_device *dev = litest_current_device(); @@ -39,38 +46,60 @@ START_TEST(switch_has_cap) } END_TEST -START_TEST(switch_has) +START_TEST(switch_has_lid_switch) { struct litest_device *dev = litest_current_device(); + if (!libevdev_has_event_code(dev->evdev, EV_SW, SW_LID)) + return; + ck_assert_int_eq(libinput_device_switch_has_switch(dev->libinput_device, LIBINPUT_SWITCH_LID), 1); } END_TEST +START_TEST(switch_has_tablet_mode_switch) +{ + struct litest_device *dev = litest_current_device(); + + if (!libevdev_has_event_code(dev->evdev, EV_SW, SW_TABLET_MODE)) + return; + + ck_assert_int_eq(libinput_device_switch_has_switch(dev->libinput_device, + LIBINPUT_SWITCH_TABLET_MODE), + 1); +} +END_TEST + START_TEST(switch_toggle) { struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; struct libinput_event *event; - enum libinput_switch sw = LIBINPUT_SWITCH_LID; + enum libinput_switch sw = _i; /* ranged test */ litest_drain_events(li); litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON); libinput_dispatch(li); - event = libinput_get_event(li); - litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_ON); - libinput_event_destroy(event); + if (libinput_device_switch_has_switch(dev->libinput_device, sw)) { + event = libinput_get_event(li); + litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_ON); + libinput_event_destroy(event); + } else { + litest_assert_empty_queue(li); + } litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_OFF); libinput_dispatch(li); - event = libinput_get_event(li); - litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_OFF); - libinput_event_destroy(event); + if (libinput_device_switch_has_switch(dev->libinput_device, sw)) { + event = libinput_get_event(li); + litest_is_switch_event(event, sw, LIBINPUT_SWITCH_STATE_OFF); + libinput_event_destroy(event); + } litest_assert_empty_queue(li); } @@ -81,7 +110,10 @@ START_TEST(switch_toggle_double) struct litest_device *dev = litest_current_device(); struct libinput *li = dev->libinput; struct libinput_event *event; - enum libinput_switch sw = LIBINPUT_SWITCH_LID; + enum libinput_switch sw = _i; /* ranged test */ + + if (!libinput_device_switch_has_switch(dev->libinput_device, sw)) + return; litest_drain_events(li); @@ -123,9 +155,12 @@ START_TEST(switch_down_on_init) struct litest_device *dev = litest_current_device(); struct libinput *li; struct libinput_event *event; - enum libinput_switch sw = LIBINPUT_SWITCH_LID; + enum libinput_switch sw = _i; /* ranged test */ - if (!lid_switch_is_reliable(dev)) + if (!libinput_device_switch_has_switch(dev->libinput_device, sw)) + return; + + if (sw == LIBINPUT_SWITCH_LID && !lid_switch_is_reliable(dev)) return; litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON); @@ -166,7 +201,10 @@ START_TEST(switch_not_down_on_init) struct libinput_event *event; enum libinput_switch sw = LIBINPUT_SWITCH_LID; - if (lid_switch_is_reliable(dev)) + if (!libinput_device_switch_has_switch(dev->libinput_device, sw)) + return; + + if (sw == LIBINPUT_SWITCH_LID && lid_switch_is_reliable(dev)) return; litest_switch_action(dev, sw, LIBINPUT_SWITCH_STATE_ON); @@ -203,6 +241,9 @@ START_TEST(lid_disable_touchpad) struct litest_device *touchpad; struct libinput *li = sw->libinput; + if (!switch_has_lid(sw)) + return; + touchpad = lid_init_paired_touchpad(li); litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); @@ -239,6 +280,9 @@ START_TEST(lid_disable_touchpad_during_touch) struct litest_device *touchpad; struct libinput *li = sw->libinput; + if (!switch_has_lid(sw)) + return; + touchpad = lid_init_paired_touchpad(li); litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); @@ -266,6 +310,9 @@ START_TEST(lid_disable_touchpad_edge_scroll) struct litest_device *touchpad; struct libinput *li = sw->libinput; + if (!switch_has_lid(sw)) + return; + touchpad = lid_init_paired_touchpad(li); litest_enable_edge_scroll(touchpad); @@ -302,6 +349,9 @@ START_TEST(lid_disable_touchpad_edge_scroll_interrupt) struct libinput *li = sw->libinput; struct libinput_event *event; + if (!switch_has_lid(sw)) + return; + touchpad = lid_init_paired_touchpad(li); litest_enable_edge_scroll(touchpad); @@ -341,6 +391,9 @@ START_TEST(lid_disable_touchpad_already_open) struct litest_device *touchpad; struct libinput *li = sw->libinput; + if (!switch_has_lid(sw)) + return; + touchpad = lid_init_paired_touchpad(li); litest_disable_tap(touchpad->libinput_device); litest_drain_events(li); @@ -373,6 +426,9 @@ START_TEST(lid_open_on_key) struct libinput *li = sw->libinput; struct libinput_event *event; + if (!switch_has_lid(sw)) + return; + keyboard = litest_add_device(li, LITEST_KEYBOARD); litest_switch_action(sw, @@ -409,6 +465,9 @@ START_TEST(lid_open_on_key_touchpad_enabled) struct litest_device *keyboard, *touchpad; struct libinput *li = sw->libinput; + if (!switch_has_lid(sw)) + return; + keyboard = litest_add_device(li, LITEST_KEYBOARD); touchpad = litest_add_device(li, LITEST_SYNAPTICS_I2C); @@ -501,6 +560,9 @@ START_TEST(lid_update_hw_on_key) struct litest_device *keyboard; struct libinput_event *event; + if (!switch_has_lid(sw)) + return; + sleep(5); keyboard = litest_add_device(li, LITEST_KEYBOARD); @@ -612,11 +674,15 @@ END_TEST void litest_setup_tests_lid(void) { + struct range switches = { LIBINPUT_SWITCH_LID, + LIBINPUT_SWITCH_TABLET_MODE + 1}; + litest_add("switch:has", switch_has_cap, LITEST_SWITCH, LITEST_ANY); - litest_add("switch:has", switch_has, LITEST_SWITCH, LITEST_ANY); - litest_add("switch:toggle", switch_toggle, LITEST_SWITCH, LITEST_ANY); - litest_add("switch:toggle", switch_toggle_double, LITEST_SWITCH, LITEST_ANY); - litest_add("switch:toggle", switch_down_on_init, LITEST_SWITCH, LITEST_ANY); + litest_add("switch:has", switch_has_lid_switch, LITEST_SWITCH, LITEST_ANY); + litest_add("switch:has", switch_has_tablet_mode_switch, LITEST_SWITCH, LITEST_ANY); + litest_add_ranged("switch:toggle", switch_toggle, LITEST_SWITCH, LITEST_ANY, &switches); + 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); -- 2.13.5 _______________________________________________ wayland-devel mailing list wayland-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/wayland-devel