From 13b3d3d04b1e9ff7f0d9e42299f675f614f03aad Mon Sep 17 00:00:00 2001 From: hujianwei Date: Wed, 16 Nov 2022 02:15:47 +0000 Subject: [PATCH] Add new seat tests for key presses * 12to11-test.xml (test_seat_controller) : : New requests. * seat.c (MakeSeatForDevicePair): Prevent seat->key_pressed from being NULL as long as keymaps have been initialized. * test_seat.c (DispatchXIFocusIn, DispatchXIFocusOut) (GenerateRawEvent, DispatchXIRawKeyRelease, DispatchXIKeyPress) (DispatchXIKeyRelease): New functions. (seat_controller_impl): Add new functions. (XLGetTestSeat): Prevent seat->key_pressed from being NULL. * tests/seat_test.c (enum test_expect_event_kind): Add keyboard events. (struct test_recorded_keyboard_enter_event) (struct test_recorded_keyboard_key_event) (struct test_recorded_keyboard_modifiers_event): New structs. (enum test_kind, test_names): Add new test. (LAST_TEST): Set to key test. (run_key_test, test_single_step): Implement new test. (expect_keyboard_enter_event, expect_keyboard_modifiers_event) (expect_keyboard_key_event): New function. (handle_keyboard_keymap, handle_keyboard_enter) (handle_keyboard_leave, handle_keyboard_key) (handle_keyboard_repeat_info): New functions. (keyboard_listener, run_test): Attach new keyboard listener. * tests/test_harness.c (test_init_seat): Initialize keyboard. * tests/test_harness.h (struct test_seat): New field `keyboard'. --- 12to11-test.xml | 128 ++++++++++++++ seat.c | 7 + test_seat.c | 140 ++++++++++++++++ tests/seat_test.c | 385 ++++++++++++++++++++++++++++++++++++++++++- tests/test_harness.c | 6 + tests/test_harness.h | 3 + 6 files changed, 668 insertions(+), 1 deletion(-) diff --git a/12to11-test.xml b/12to11-test.xml index 870fbba..9f9334d 100644 --- a/12to11-test.xml +++ b/12to11-test.xml @@ -276,6 +276,10 @@ state. If the value already exists, post a value_exists error. If the valuator is more than 65535 or 0, post an invalid_valuator error. + + If this valuator is passed to a request that generates events + with raw valuators, the value specified will be used as the + raw value for the valuator as well. @@ -632,6 +636,130 @@ + + + Dispatch a focus in event to the seat. + + + + + + + + + + + + + + + + + + + + + + Dispatch a focus out event to the seat. + + + + + + + + + + + + + + + + + + + + + + Dispatch a raw key press event to the seat. + + + + + + + + + + + Dispatch a raw key release event to the seat. + + + + + + + + + + + Dispatch a regular key press event to the seat. + + + + + + + + + + + + + + + + + + + + + Dispatch a regular key release event to the seat. + + + + + + + + + + + + + + + + + + This event is sent immediately after the test_seat_controller diff --git a/seat.c b/seat.c index 05673eb..9efafca 100644 --- a/seat.c +++ b/seat.c @@ -1833,6 +1833,13 @@ MakeSeatForDevicePair (int master_keyboard, int master_pointer, seat->latched_group = state.latched_group; seat->effective_group = state.group; + /* If a keymap is already attached, initialize seat->key_pressed + now. */ + if (xkb_desc) + seat->key_pressed + = XLCalloc (MaskLen (xkb_desc->max_key_code + - xkb_desc->min_key_code), 1); + /* And select for XKB events from the master keyboard device. If the server does not support accessing input extension devices with Xkb, an error will result. */ diff --git a/test_seat.c b/test_seat.c index c8f37c7..8f3ef18 100644 --- a/test_seat.c +++ b/test_seat.c @@ -1129,6 +1129,135 @@ SetLastUserTime (struct wl_client *client, struct wl_resource *resource, controller->seat->last_user_time.milliseconds = milliseconds; } +static void +DispatchXIFocusIn (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + uint32_t root, uint32_t event, uint32_t child, + wl_fixed_t root_x, wl_fixed_t root_y, + wl_fixed_t event_x, wl_fixed_t event_y, int32_t mode, + int32_t focus, int32_t same_screen, + struct wl_resource *buttons_resource, + struct wl_resource *mods_resource, + struct wl_resource *group_resource) +{ + TestSeatController *controller; + XIFocusInEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateCrossingEvent (XI_FocusIn, controller, test_event); + + /* Now dispatch the event. */ + DispatchTestEvent (controller, event, (XIEvent *) &test_event); +} + +static void +DispatchXIFocusOut (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + uint32_t root, uint32_t event, uint32_t child, + wl_fixed_t root_x, wl_fixed_t root_y, + wl_fixed_t event_x, wl_fixed_t event_y, int32_t mode, + int32_t focus, int32_t same_screen, + struct wl_resource *buttons_resource, + struct wl_resource *mods_resource, + struct wl_resource *group_resource) +{ + TestSeatController *controller; + XIFocusInEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateCrossingEvent (XI_FocusOut, controller, test_event); + + /* Now dispatch the event. */ + DispatchTestEvent (controller, event, (XIEvent *) &test_event); +} + +#define GenerateRawEvent(event_type, controller, test_event) \ + test_event.type = GenericEvent; \ + test_event.serial = request_serial_counter++; \ + test_event.send_event = True; \ + test_event.display = compositor.display; \ + test_event.extension = xi2_opcode; \ + test_event.evtype = event_type; \ + test_event.time = time; \ + test_event.deviceid = controller->seat->master_pointer; \ + test_event.sourceid = sourceid; \ + test_event.detail = detail; \ + test_event.flags = flags; \ + TranslateTestValuators (valuators_resource, &test_event.valuators); \ + test_event.raw_values = test_event.valuators.values; + +static void +DispatchXIRawKeyPress (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + int32_t flags, struct wl_resource *valuators_resource) +{ + TestSeatController *controller; + XIRawEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateRawEvent (XI_RawKeyPress, controller, test_event); + + /* Now dispatch the event. */ + HandleRawKey (&test_event); +} + +static void +DispatchXIRawKeyRelease (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + int32_t flags, struct wl_resource *valuators_resource) +{ + TestSeatController *controller; + XIRawEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateRawEvent (XI_RawKeyRelease, controller, test_event); + + /* Now dispatch the event. */ + HandleRawKey (&test_event); +} + +static void +DispatchXIKeyPress (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + uint32_t root, uint32_t event, uint32_t child, + wl_fixed_t root_x, wl_fixed_t root_y, + wl_fixed_t event_x, wl_fixed_t event_y, int32_t flags, + struct wl_resource *buttons_resource, + struct wl_resource *valuators_resource, + struct wl_resource *mods_resource, + struct wl_resource *group_resource) +{ + TestSeatController *controller; + XIDeviceEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateDeviceEvent (XI_KeyPress, controller, test_event); + + /* Now dispatch the event. */ + DispatchTestEvent (controller, event, (XIEvent *) &test_event); +} + +static void +DispatchXIKeyRelease (struct wl_client *client, struct wl_resource *resource, + uint32_t time, int32_t sourceid, int32_t detail, + uint32_t root, uint32_t event, uint32_t child, + wl_fixed_t root_x, wl_fixed_t root_y, + wl_fixed_t event_x, wl_fixed_t event_y, int32_t flags, + struct wl_resource *buttons_resource, + struct wl_resource *valuators_resource, + struct wl_resource *mods_resource, + struct wl_resource *group_resource) +{ + TestSeatController *controller; + XIDeviceEvent test_event; + + controller = wl_resource_get_user_data (resource); + GenerateDeviceEvent (XI_KeyRelease, controller, test_event); + + /* Now dispatch the event. */ + DispatchTestEvent (controller, event, (XIEvent *) &test_event); +} + static const struct test_seat_controller_interface seat_controller_impl = { .destroy = DestroySeatController, @@ -1143,6 +1272,12 @@ static const struct test_seat_controller_interface seat_controller_impl = .dispatch_XI_ButtonRelease = DispatchXIButtonRelease, .get_device_controller = GetDeviceController, .set_last_user_time = SetLastUserTime, + .dispatch_XI_FocusIn = DispatchXIFocusIn, + .dispatch_XI_FocusOut = DispatchXIFocusOut, + .dispatch_XI_RawKeyPress = DispatchXIRawKeyPress, + .dispatch_XI_RawKeyRelease = DispatchXIRawKeyRelease, + .dispatch_XI_KeyPress = DispatchXIKeyPress, + .dispatch_XI_KeyRelease = DispatchXIKeyRelease, }; static void @@ -1248,6 +1383,11 @@ XLGetTestSeat (struct wl_client *client, struct wl_resource *resource, /* Add the seat to the live seat list. */ live_seats = XLListPrepend (live_seats, seat); + /* Initialize seat->key_pressed. */ + seat->key_pressed + = XLCalloc (MaskLen (xkb_desc->max_key_code + - xkb_desc->min_key_code), 1); + /* Retain the seat. */ RetainSeat (seat); controller->seat = seat; diff --git a/tests/seat_test.c b/tests/seat_test.c index 6502866..8a64023 100644 --- a/tests/seat_test.c +++ b/tests/seat_test.c @@ -30,6 +30,9 @@ enum test_expect_event_kind POINTER_LEAVE_EVENT, POINTER_BUTTON_EVENT, POINTER_AXIS_VALUE120_EVENT, + KEYBOARD_ENTER_EVENT, + KEYBOARD_KEY_EVENT, + KEYBOARD_MODIFIERS_EVENT, }; struct test_recorded_event @@ -95,6 +98,45 @@ struct test_recorded_axis_value120_event int32_t value120; }; +struct test_recorded_keyboard_enter_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The event surface. */ + struct wl_surface *surface; + + /* The keys. */ + uint32_t *keys; + + /* The number of keys in that array. */ + size_t num_keys; +}; + +struct test_recorded_keyboard_key_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The key. */ + uint32_t key; + + /* And the key state. */ + uint32_t state; +}; + +struct test_recorded_keyboard_modifiers_event +{ + /* The event header. */ + struct test_recorded_event header; + + /* The modifiers. */ + uint32_t base, latched, locked; + + /* The group. */ + uint32_t group; +}; + struct test_subsurface { /* The subsurface itself. */ @@ -111,6 +153,7 @@ enum test_kind TEST_CLICK_KIND, TEST_GRAB_KIND, TEST_VALUATOR_KIND, + TEST_KEY_KIND, }; static const char *test_names[] = @@ -120,9 +163,10 @@ static const char *test_names[] = "test_click", "test_grab", "test_valuator", + "test_key", }; -#define LAST_TEST TEST_VALUATOR_KIND +#define LAST_TEST TEST_KEY_KIND #define TEST_SOURCE_DEVICE 4500000 /* The display. */ @@ -164,6 +208,11 @@ static void expect_motion_event (double, double); static void expect_leave_event (void); static void expect_button_event (int, int); static void expect_axis_value120_event (uint32_t, int32_t); +static void expect_keyboard_enter_event (struct wl_surface *, uint32_t *, + size_t); +static void expect_keyboard_key_event (uint32_t, uint32_t); +static void expect_keyboard_modifiers_event (uint32_t, uint32_t, + uint32_t, uint32_t); static void expect_no_events (void); @@ -635,6 +684,71 @@ run_valuator_test (void) expect_leave_event (); } +static void +run_key_test (void) +{ + test_seat_controller_dispatch_XI_FocusIn (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + XINotifyAncestor, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + XINotifyNonlinear, + 0, + 1, + NULL, NULL, NULL); + test_seat_controller_dispatch_XI_RawKeyPress (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 67, + 0, + NULL); + test_seat_controller_dispatch_XI_KeyPress (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 67, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + 0, + NULL, NULL, NULL, NULL); + test_seat_controller_dispatch_XI_RawKeyRelease (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 67, + 0, + NULL); + test_seat_controller_dispatch_XI_KeyRelease (display->seat->controller, + test_get_time (), + TEST_SOURCE_DEVICE, + 67, + test_get_root (), + test_surface_window, + None, + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + wl_fixed_from_double (2.0), + 0, + NULL, NULL, NULL, NULL); + + /* Now, verify the events as they arrive. */ + record_events (); + expect_keyboard_key_event (59, WL_KEYBOARD_KEY_STATE_RELEASED); + expect_keyboard_key_event (59, WL_KEYBOARD_KEY_STATE_PRESSED); + expect_keyboard_modifiers_event (0, 0, 0, 0); + expect_keyboard_enter_event (wayland_surface, NULL, 0); +} + static void test_single_step (enum test_kind kind) { @@ -877,6 +991,22 @@ test_single_step (enum test_kind kind) frame (); */ run_valuator_test (); + kind = TEST_KEY_KIND; + goto again; + + case TEST_KEY_KIND: + /* Test simple key press and key release. Dispatch an + XI_FocusIn event to the test surface. Then, press and + release the keycode 67, generating both raw and device + events. Verify that the following events are sent to the + keyboard. + + enter (SERIAL, SURFACE, array[0]) + modifiers (SERIAL, 0, 0, 0, 0) + key (SERIAL, TIME, 59, WL_KEYBOARD_KEY_STATE_PRESSED) + key (SERIAL, TIME, 59, WL_KEYBOARD_KEY_STATE_RELEASED) */ + + run_key_test (); break; } @@ -1046,6 +1176,105 @@ expect_axis_value120_event (uint32_t axis, int32_t value120) "received"); } +static void +expect_keyboard_enter_event (struct wl_surface *surface, uint32_t *keys, + size_t num_keys) +{ + struct test_recorded_event *event; + struct test_recorded_keyboard_enter_event *keyboard_enter_event; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = record_tail->last; + + if (event->kind == KEYBOARD_ENTER_EVENT) + { + keyboard_enter_event + = (struct test_recorded_keyboard_enter_event *) event; + + if (keyboard_enter_event->num_keys != num_keys + || surface != keyboard_enter_event->surface + || memcmp (keyboard_enter_event->keys, keys, + num_keys * sizeof *keys)) + report_test_failure ("expected keyboard_enter event passed" + " with invalid parameters"); + else + { + free (keyboard_enter_event->keys); + free (event); + } + } + else + report_test_failure ("expected keyboard_enter_event, but it was" + " not received"); +} + +static void +expect_keyboard_key_event (uint32_t key, uint32_t state) +{ + struct test_recorded_event *event; + struct test_recorded_keyboard_key_event *keyboard_key_event; + + event = record_tail; + + if (!event) + report_test_failure ("expected event not sent"); + + record_tail = record_tail->last; + + if (event->kind == KEYBOARD_KEY_EVENT) + { + keyboard_key_event + = (struct test_recorded_keyboard_key_event *) event; + + if (key != keyboard_key_event->key + || state != keyboard_key_event->state) + report_test_failure ("expected keyboard_key passed with" + " invalid parameters"); + else + free (event); + } + else + report_test_failure ("expected keyboard_key_event, but it was" + " not received"); +} + +static void +expect_keyboard_modifiers_event (uint32_t base, uint32_t latched, + uint32_t locked, uint32_t group) +{ + struct test_recorded_event *event; + struct test_recorded_keyboard_modifiers_event *keyboard_modifiers_event; + + event = record_tail; + + if (!event) + return; + + record_tail = record_tail->last; + + if (event->kind == KEYBOARD_MODIFIERS_EVENT) + { + keyboard_modifiers_event + = (struct test_recorded_keyboard_modifiers_event *) event; + + if (keyboard_modifiers_event->base != base + || keyboard_modifiers_event->latched != latched + || keyboard_modifiers_event->locked != locked + || keyboard_modifiers_event->group != group) + report_test_failure ("expected keyboard_modifiers passed with" + " invalid parameters"); + else + free (event); + } + else + report_test_failure ("expected keyboard_modifiers_event, but it was" + " not received"); +} + static void expect_no_events (void) { @@ -1351,6 +1580,156 @@ static const struct wl_pointer_listener pointer_listener = +static void +handle_keyboard_keymap (void *data, struct wl_keyboard *keyboard, + uint32_t format, int32_t fd, uint32_t size) +{ + close (fd); +} + +static void +handle_keyboard_enter (void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface, + struct wl_array *keys) +{ + struct test_recorded_keyboard_enter_event *event; + + if (!recording_events) + { + test_log ("ignored keyboard enter event"); + return; + } + + event = malloc (sizeof *event); + + if (!event) + report_test_failure ("failed to record event"); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif + + event->header.kind = KEYBOARD_ENTER_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + if (keys->size % sizeof (uint32_t)) + report_test_failure ("reported key size modulo" + " uint32_t!"); + + event->keys = malloc (keys->size); + + if (!event->keys) + report_test_failure ("failed to allocate key array"); + + memcpy (event->keys, keys->data, keys->size); + event->num_keys = keys->size / sizeof (uint32_t); + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +} + +static void +handle_keyboard_leave (void *data, struct wl_keyboard *keyboard, + uint32_t serial, struct wl_surface *surface) +{ + +} + +static void +handle_keyboard_key (void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t time, uint32_t key, + uint32_t state) +{ + struct test_recorded_keyboard_key_event *event; + + if (!recording_events) + { + test_log ("ignored keyboard key event"); + return; + } + + event = malloc (sizeof *event); + + if (!event) + report_test_failure ("failed to record event"); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif + + event->header.kind = KEYBOARD_KEY_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + event->key = key; + event->state = state; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +} + +static void +handle_keyboard_modifiers (void *data, struct wl_keyboard *keyboard, + uint32_t serial, uint32_t mods_depressed, + uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) +{ + struct test_recorded_keyboard_modifiers_event *event; + + if (!recording_events) + { + test_log ("ignored modifiers event"); + return; + } + + event = malloc (sizeof *event); + + if (!event) + report_test_failure ("failed to record modifiers event"); + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wanalyzer-malloc-leak" +#endif + + event->header.kind = KEYBOARD_MODIFIERS_EVENT; + event->header.last = record_tail; + record_tail = &event->header; + + event->base = mods_depressed; + event->latched = mods_latched; + event->locked = mods_locked; + event->group = group; + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +} + +static void +handle_keyboard_repeat_info (void *data, struct wl_keyboard *keyboard, + int32_t rate, int32_t delay) +{ + +} + +static const struct wl_keyboard_listener keyboard_listener = + { + handle_keyboard_keymap, + handle_keyboard_enter, + handle_keyboard_leave, + handle_keyboard_key, + handle_keyboard_modifiers, + handle_keyboard_repeat_info, + }; + + + static void submit_surface_damage (struct wl_surface *surface, int x, int y, int width, int height) @@ -1420,6 +1799,10 @@ run_test (void) wl_pointer_add_listener (display->seat->pointer, &pointer_listener, NULL); + /* And the keyboard listener. */ + wl_keyboard_add_listener (display->seat->keyboard, &keyboard_listener, + NULL); + while (true) { if (wl_display_dispatch (display->display) == -1) diff --git a/tests/test_harness.c b/tests/test_harness.c index 3ca8959..2c5e630 100644 --- a/tests/test_harness.c +++ b/tests/test_harness.c @@ -907,6 +907,12 @@ test_init_seat (struct test_display *display) if (!display->seat->pointer) report_test_failure ("failed to bind to test pointer"); + + display->seat->keyboard + = wl_seat_get_keyboard (display->seat->seat); + + if (!display->seat->keyboard) + report_test_failure ("failed to bind to test keyboard"); } void __attribute__ ((noreturn)) diff --git a/tests/test_harness.h b/tests/test_harness.h index 46298a9..2bab262 100644 --- a/tests/test_harness.h +++ b/tests/test_harness.h @@ -49,6 +49,9 @@ struct test_seat /* The wl_pointer resource. */ struct wl_pointer *pointer; + /* The keyboard resource. */ + struct wl_keyboard *keyboard; + /* The device ID of the seat. */ uint32_t device_id;