diff options
Diffstat (limited to 'test/test-keyboard.c')
-rw-r--r-- | test/test-keyboard.c | 392 |
1 files changed, 392 insertions, 0 deletions
diff --git a/test/test-keyboard.c b/test/test-keyboard.c new file mode 100644 index 00000000..780506aa --- /dev/null +++ b/test/test-keyboard.c @@ -0,0 +1,392 @@ +/* + * Copyright © 2014 Jonas Ådahl <jadahl@gmail.com> + * + * 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 <check.h> +#include <stdio.h> + +#include "libinput-util.h" +#include "litest.h" + +START_TEST(keyboard_seat_key_count) +{ + const int num_devices = 4; + struct litest_device *devices[num_devices]; + struct libinput *libinput; + struct libinput_event *ev; + struct libinput_event_keyboard *kev; + int i; + int seat_key_count = 0; + int expected_key_button_count = 0; + char device_name[255]; + + libinput = litest_create_context(); + for (i = 0; i < num_devices; ++i) { + sprintf(device_name, "litest Generic keyboard (%d)", i); + devices[i] = litest_add_device_with_overrides(libinput, + LITEST_KEYBOARD, + device_name, + NULL, NULL, NULL); + } + + for (i = 0; i < num_devices; ++i) + litest_keyboard_key(devices[i], KEY_A, true); + + libinput_dispatch(libinput); + while ((ev = libinput_get_event(libinput))) { + if (libinput_event_get_type(ev) != + LIBINPUT_EVENT_KEYBOARD_KEY) { + libinput_event_destroy(ev); + libinput_dispatch(libinput); + continue; + } + + kev = litest_is_keyboard_event(ev, + KEY_A, + LIBINPUT_KEY_STATE_PRESSED); + + ++expected_key_button_count; + seat_key_count = + libinput_event_keyboard_get_seat_key_count(kev); + ck_assert_int_eq(expected_key_button_count, seat_key_count); + + libinput_event_destroy(ev); + libinput_dispatch(libinput); + } + + ck_assert_int_eq(seat_key_count, num_devices); + + for (i = 0; i < num_devices; ++i) + litest_keyboard_key(devices[i], KEY_A, false); + + libinput_dispatch(libinput); + while ((ev = libinput_get_event(libinput))) { + if (libinput_event_get_type(ev) != + LIBINPUT_EVENT_KEYBOARD_KEY) { + libinput_event_destroy(ev); + libinput_dispatch(libinput); + continue; + } + + kev = libinput_event_get_keyboard_event(ev); + ck_assert_notnull(kev); + ck_assert_int_eq(libinput_event_keyboard_get_key(kev), KEY_A); + ck_assert_int_eq(libinput_event_keyboard_get_key_state(kev), + LIBINPUT_KEY_STATE_RELEASED); + + --expected_key_button_count; + seat_key_count = + libinput_event_keyboard_get_seat_key_count(kev); + ck_assert_int_eq(expected_key_button_count, seat_key_count); + + libinput_event_destroy(ev); + libinput_dispatch(libinput); + } + + ck_assert_int_eq(seat_key_count, 0); + + for (i = 0; i < num_devices; ++i) + litest_delete_device(devices[i]); + libinput_unref(libinput); +} +END_TEST + +START_TEST(keyboard_ignore_no_pressed_release) +{ + struct litest_device *dev; + struct libinput *unused_libinput; + struct libinput *libinput; + struct libinput_event *event; + struct libinput_event_keyboard *kevent; + int events[] = { + EV_KEY, KEY_A, + -1, -1, + }; + enum libinput_key_state *state; + enum libinput_key_state expected_states[] = { + LIBINPUT_KEY_STATE_PRESSED, + LIBINPUT_KEY_STATE_RELEASED, + }; + + /* We can't send pressed -> released -> pressed events using uinput + * as such non-symmetric events are dropped. Work-around this by first + * adding the test device to the tested context after having sent an + * initial pressed event. */ + unused_libinput = litest_create_context(); + dev = litest_add_device_with_overrides(unused_libinput, + LITEST_KEYBOARD, + "Generic keyboard", + NULL, NULL, events); + + litest_keyboard_key(dev, KEY_A, true); + litest_drain_events(unused_libinput); + + libinput = litest_create_context(); + libinput_path_add_device(libinput, + libevdev_uinput_get_devnode(dev->uinput)); + litest_drain_events(libinput); + + litest_keyboard_key(dev, KEY_A, false); + litest_keyboard_key(dev, KEY_A, true); + litest_keyboard_key(dev, KEY_A, false); + + libinput_dispatch(libinput); + + ARRAY_FOR_EACH(expected_states, state) { + event = libinput_get_event(libinput); + ck_assert_notnull(event); + ck_assert_int_eq(libinput_event_get_type(event), + LIBINPUT_EVENT_KEYBOARD_KEY); + kevent = libinput_event_get_keyboard_event(event); + ck_assert_int_eq(libinput_event_keyboard_get_key(kevent), + KEY_A); + ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent), + *state); + libinput_event_destroy(event); + libinput_dispatch(libinput); + } + + litest_assert_empty_queue(libinput); + litest_delete_device(dev); + libinput_unref(libinput); + libinput_unref(unused_libinput); +} +END_TEST + +START_TEST(keyboard_key_auto_release) +{ + struct libinput *libinput; + struct litest_device *dev; + struct libinput_event *event; + enum libinput_event_type type; + struct libinput_event_keyboard *kevent; + struct { + int code; + int released; + } keys[] = { + { .code = KEY_A, }, + { .code = KEY_S, }, + { .code = KEY_D, }, + { .code = KEY_G, }, + { .code = KEY_Z, }, + { .code = KEY_DELETE, }, + { .code = KEY_F24, }, + }; + int events[2 * (ARRAY_LENGTH(keys) + 1)]; + unsigned i; + int key; + int valid_code; + + /* Enable all tested keys on the device */ + i = 0; + while (i < 2 * ARRAY_LENGTH(keys)) { + key = keys[i / 2].code; + events[i++] = EV_KEY; + events[i++] = key; + } + events[i++] = -1; + events[i++] = -1; + + libinput = litest_create_context(); + dev = litest_add_device_with_overrides(libinput, + LITEST_KEYBOARD, + "Generic keyboard", + NULL, NULL, events); + + litest_drain_events(libinput); + + /* Send pressed events, without releasing */ + for (i = 0; i < ARRAY_LENGTH(keys); ++i) { + key = keys[i].code; + litest_event(dev, EV_KEY, key, 1); + litest_event(dev, EV_SYN, SYN_REPORT, 0); + + libinput_dispatch(libinput); + + event = libinput_get_event(libinput); + kevent = litest_is_keyboard_event(event, + key, + LIBINPUT_KEY_STATE_PRESSED); + libinput_event_destroy(event); + } + + litest_drain_events(libinput); + + /* "Disconnect" device */ + litest_delete_device(dev); + + /* Mark all released keys until device is removed */ + while (1) { + event = libinput_get_event(libinput); + ck_assert_notnull(event); + type = libinput_event_get_type(event); + + if (type == LIBINPUT_EVENT_DEVICE_REMOVED) { + libinput_event_destroy(event); + break; + } + + ck_assert_int_eq(type, LIBINPUT_EVENT_KEYBOARD_KEY); + kevent = libinput_event_get_keyboard_event(event); + ck_assert_int_eq(libinput_event_keyboard_get_key_state(kevent), + LIBINPUT_KEY_STATE_RELEASED); + key = libinput_event_keyboard_get_key(kevent); + + valid_code = 0; + for (i = 0; i < ARRAY_LENGTH(keys); ++i) { + if (keys[i].code == key) { + ck_assert_int_eq(keys[i].released, 0); + keys[i].released = 1; + valid_code = 1; + } + } + ck_assert_int_eq(valid_code, 1); + libinput_event_destroy(event); + } + + /* Check that all pressed keys has been released. */ + for (i = 0; i < ARRAY_LENGTH(keys); ++i) { + ck_assert_int_eq(keys[i].released, 1); + } + + libinput_unref(libinput); +} +END_TEST + +START_TEST(keyboard_has_key) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + unsigned int code; + int evdev_has, libinput_has; + + ck_assert(libinput_device_has_capability( + device, + LIBINPUT_DEVICE_CAP_KEYBOARD)); + + for (code = 0; code < KEY_CNT; code++) { + evdev_has = libevdev_has_event_code(dev->evdev, EV_KEY, code); + libinput_has = libinput_device_keyboard_has_key(device, code); + ck_assert_int_eq(evdev_has, libinput_has); + } +} +END_TEST + +START_TEST(keyboard_keys_bad_device) +{ + struct litest_device *dev = litest_current_device(); + struct libinput_device *device = dev->libinput_device; + unsigned int code; + int has_key; + + if (libinput_device_has_capability(device, + LIBINPUT_DEVICE_CAP_KEYBOARD)) + return; + + for (code = 0; code < KEY_CNT; code++) { + has_key = libinput_device_keyboard_has_key(device, code); + ck_assert_int_eq(has_key, -1); + } +} +END_TEST + +START_TEST(keyboard_time_usec) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event_keyboard *kev; + struct libinput_event *event; + uint64_t time_usec; + + if (!libevdev_has_event_code(dev->evdev, EV_KEY, KEY_A)) + return; + + litest_drain_events(dev->libinput); + + litest_keyboard_key(dev, KEY_A, true); + + litest_wait_for_event(li); + + event = libinput_get_event(li); + kev = litest_is_keyboard_event(event, + KEY_A, + LIBINPUT_KEY_STATE_PRESSED); + + time_usec = libinput_event_keyboard_get_time_usec(kev); + ck_assert_int_eq(libinput_event_keyboard_get_time(kev), + (uint32_t) (time_usec / 1000)); + + libinput_event_destroy(event); + litest_drain_events(dev->libinput); +} +END_TEST + +START_TEST(keyboard_no_buttons) +{ + struct litest_device *dev = litest_current_device(); + struct libinput *li = dev->libinput; + struct libinput_event *event; + int code; + const char *name; + + litest_drain_events(dev->libinput); + + for (code = 0; code < KEY_MAX; code++) { + if (!libevdev_has_event_code(dev->evdev, EV_KEY, code)) + continue; + + name = libevdev_event_code_get_name(EV_KEY, code); + if (!name || !strneq(name, "KEY_", 4)) + continue; + + litest_keyboard_key(dev, code, true); + litest_keyboard_key(dev, code, false); + libinput_dispatch(li); + + event = libinput_get_event(li); + litest_is_keyboard_event(event, + code, + LIBINPUT_KEY_STATE_PRESSED); + libinput_event_destroy(event); + event = libinput_get_event(li); + litest_is_keyboard_event(event, + code, + LIBINPUT_KEY_STATE_RELEASED); + libinput_event_destroy(event); + } +} +END_TEST + +void +litest_setup_tests_keyboard(void) +{ + litest_add_no_device("keyboard:seat key count", keyboard_seat_key_count); + litest_add_no_device("keyboard:key counting", keyboard_ignore_no_pressed_release); + litest_add_no_device("keyboard:key counting", keyboard_key_auto_release); + litest_add("keyboard:keys", keyboard_has_key, LITEST_KEYS, LITEST_ANY); + litest_add("keyboard:keys", keyboard_keys_bad_device, LITEST_ANY, LITEST_ANY); + litest_add("keyboard:time", keyboard_time_usec, LITEST_KEYS, LITEST_ANY); + + litest_add("keyboard:events", keyboard_no_buttons, LITEST_KEYS, LITEST_ANY); +} |