From 6f70e97cce823af4c277a0a25f771519339d1178 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 23 Aug 2021 09:00:29 +1000 Subject: [PATCH] Implement key modifier mask events similar to Wayland Since the server controls the keymap, and that keymap is likely merged with some other device let's add the events so we notify the client of things like numlock-is-down etc. Signed-off-by: Peter Hutterer --- proto/ei.proto | 9 ++++++++ src/libei-event.c | 34 ++++++++++++++++++++++++++++++ src/libei-private.h | 9 ++++++++ src/libei-proto.c | 8 ++++++++ src/libei-proto.h | 3 +++ src/libei.c | 42 +++++++++++++++++++++++++++++++++++++ src/libei.h | 48 +++++++++++++++++++++++++++++++++++++++++++ src/libeis-client.c | 23 +++++++++++++++++++++ src/libeis-device.c | 14 +++++++++++++ src/libeis-private.h | 12 +++++++++++ src/libeis-proto.c | 17 +++++++++++++++ src/libeis-proto.h | 2 ++ src/libeis.h | 9 ++++++++ test/eierpecken.c | 1 + test/test-ei-device.c | 35 +++++++++++++++++++++++++++++++ 15 files changed, 266 insertions(+) diff --git a/proto/ei.proto b/proto/ei.proto index 92324a4..84e6960 100644 --- a/proto/ei.proto +++ b/proto/ei.proto @@ -217,6 +217,14 @@ message DevicePaused { uint32 deviceid = 1; } +message KeyboardModifiers { + uint32 deviceid = 1; + uint32 depressed = 2; + uint32 locked = 3; + uint32 latched = 4; + uint32 group = 5; +} + message ServerMessage { oneof msg { Connected connected = 2; @@ -230,6 +238,7 @@ message ServerMessage { DeviceRemoved device_removed = 10; DeviceResumed device_resumed = 11; DevicePaused device_paused = 12; + KeyboardModifiers keyboard_modifiers = 13; } } diff --git a/src/libei-event.c b/src/libei-event.c index a970b97..5774bad 100644 --- a/src/libei-event.c +++ b/src/libei-event.c @@ -47,6 +47,7 @@ ei_event_type_to_string(enum ei_event_type type) CASE_RETURN_STRING(EI_EVENT_DEVICE_REMOVED); CASE_RETURN_STRING(EI_EVENT_DEVICE_PAUSED); CASE_RETURN_STRING(EI_EVENT_DEVICE_RESUMED); + CASE_RETURN_STRING(EI_EVENT_KEYBOARD_MODIFIERS); } assert(!"Unhandled event type"); @@ -64,6 +65,7 @@ ei_event_destroy(struct ei_event *event) case EI_EVENT_DEVICE_REMOVED: case EI_EVENT_DEVICE_PAUSED: case EI_EVENT_DEVICE_RESUMED: + case EI_EVENT_KEYBOARD_MODIFIERS: break; } ei_device_unref(event->device); @@ -121,3 +123,35 @@ check_event_type(struct ei_event *event, if (!check_event_type(event_, __func__, __VA_ARGS__, -1)) \ return retval_; \ + +_public_ uint32_t +ei_event_keyboard_get_xkb_mods_depressed(struct ei_event *event) +{ + require_event_type(event, 0, EI_EVENT_KEYBOARD_MODIFIERS); + + return event->modifiers.depressed; +} + +_public_ uint32_t +ei_event_keyboard_get_xkb_mods_latched(struct ei_event *event) +{ + require_event_type(event, 0, EI_EVENT_KEYBOARD_MODIFIERS); + + return event->modifiers.latched; +} + +_public_ uint32_t +ei_event_keyboard_get_xkb_mods_locked(struct ei_event *event) +{ + require_event_type(event, 0, EI_EVENT_KEYBOARD_MODIFIERS); + + return event->modifiers.locked; +} + +_public_ uint32_t +ei_event_keyboard_get_xkb_group(struct ei_event *event) +{ + require_event_type(event, 0, EI_EVENT_KEYBOARD_MODIFIERS); + + return event->modifiers.group; +} diff --git a/src/libei-private.h b/src/libei-private.h index 63131aa..aff44f5 100644 --- a/src/libei-private.h +++ b/src/libei-private.h @@ -153,12 +153,21 @@ struct ei_touch { double x, y; }; +struct ei_xkb_modifiers { + uint32_t depressed; + uint32_t latched; + uint32_t locked; + uint32_t group; +}; + struct ei_event { struct object object; /* Parent is struct ei */ enum ei_event_type type; struct list link; struct ei_seat *seat; /* NULL if device is non-NULL */ struct ei_device *device; + + struct ei_xkb_modifiers modifiers; }; struct ei_event * diff --git a/src/libei-proto.c b/src/libei-proto.c index a885edc..b74437b 100644 --- a/src/libei-proto.c +++ b/src/libei-proto.c @@ -105,6 +105,14 @@ ei_proto_handle_message(struct ei *ei, proto->device_region->height, proto->device_region->scale); break; + case SERVER_MESSAGE__MSG_KEYBOARD_MODIFIERS: + rc = call(keyboard_modifiers, ei, + proto->keyboard_modifiers->deviceid, + proto->keyboard_modifiers->depressed, + proto->keyboard_modifiers->latched, + proto->keyboard_modifiers->locked, + proto->keyboard_modifiers->group); + break; case SERVER_MESSAGE__MSG_DEVICE_REMOVED: rc = call(device_removed, ei, proto->device_removed->deviceid); diff --git a/src/libei-proto.h b/src/libei-proto.h index 118b59e..3a53141 100644 --- a/src/libei-proto.h +++ b/src/libei-proto.h @@ -51,6 +51,9 @@ struct ei_proto_interface { enum ei_keymap_type keymap_type, int keymap_fd, size_t keymap_size); + int (*keyboard_modifiers)(struct ei *ei, uint32_t deviceid, + uint32_t depressed, uint32_t latched, + uint32_t locked, uint32_t group); }; struct ei_proto_requests { diff --git a/src/libei.c b/src/libei.c index ac70e68..aa52581 100644 --- a/src/libei.c +++ b/src/libei.c @@ -262,6 +262,21 @@ queue_resumed_event(struct ei_device *device) queue_event(ei, e); } +static void +queue_keyboard_modifiers_event(struct ei_device *device, + const struct ei_xkb_modifiers *mods) +{ + struct ei *ei= ei_device_get_context(device); + + struct ei_event *e = ei_event_new(ei); + e->type = EI_EVENT_KEYBOARD_MODIFIERS; + e->seat = ei_seat_ref(ei_device_get_seat(device)); + e->device = ei_device_ref(device); + e->modifiers = *mods; + + queue_event(ei, e); +} + void ei_disconnect(struct ei *ei) { @@ -423,6 +438,32 @@ handle_msg_device_region(struct ei *ei, uint32_t deviceid, return 0; } +static int +handle_msg_keyboard_modifiers(struct ei *ei, uint32_t deviceid, + uint32_t depressed, uint32_t latched, + uint32_t locked, uint32_t group) +{ + log_debug(ei, "Setting modifiers for %#x\n", deviceid); + + struct ei_device *device = ei_find_device(ei, deviceid); + if (!device) + return 0; + + if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) { + log_bug(ei,"Modifier event for non-keyboard\n"); + return -EPROTO; + } + + struct ei_xkb_modifiers mods = { + .depressed = depressed, + .latched = latched, + .locked = locked, + .group = group, + }; + queue_keyboard_modifiers_event(device, &mods); + + return 0; +} static int handle_msg_device_removed(struct ei *ei, uint32_t deviceid) @@ -687,6 +728,7 @@ static const struct ei_proto_interface intf_state_connected = { .device_region = handle_msg_device_region, .device_keymap = handle_msg_device_keymap, .device_done = handle_msg_device_added_done, + .keyboard_modifiers = handle_msg_keyboard_modifiers, }; static const struct ei_proto_interface *interfaces[] = { diff --git a/src/libei.h b/src/libei.h index 2a4d187..cacdc11 100644 --- a/src/libei.h +++ b/src/libei.h @@ -236,6 +236,22 @@ enum ei_event_type { * The client may send events. */ EI_EVENT_DEVICE_RESUMED, + + /** + * The server has changed the modifier state on the device's + * keymap. See + * ei_event_keyboard_get_xkb_mods_depressed(), + * ei_event_keyboard_get_xkb_mods_latched(), + * ei_event_keyboard_get_xkb_mods_locked(), and + * ei_event_keyboard_get_xkb_group(). + * + * This event is sent in response to an external modifier state + * change. Where the client triggers a modifier state change in + * response to ei_device_keyboard_key(), no such event is sent. + * + * This event may arrive while a device is paused. + */ + EI_EVENT_KEYBOARD_MODIFIERS, }; /** @@ -545,6 +561,38 @@ ei_event_get_device(struct ei_event *event); uint64_t ei_event_get_time(struct ei_event *event); +/** + * For an event of type @ref EI_EVENT_KEYBOARD_MODIFIERS, get the + * mask of currently logically pressed-down modifiers. + * See ei_device_get_keymap() for the corresponding keymap. + */ +uint32_t +ei_event_keyboard_get_xkb_mods_depressed(struct ei_event *event); + +/** + * For an event of type @ref EI_EVENT_KEYBOARD_MODIFIERS, get the + * mask of currently logically latched modifiers. + * See ei_device_get_keymap() for the corresponding keymap. + */ +uint32_t +ei_event_keyboard_get_xkb_mods_latched(struct ei_event *event); + +/** + * For an event of type @ref EI_EVENT_KEYBOARD_MODIFIERS, get the + * mask of currently logically locked modifiers. + * See ei_device_get_keymap() for the corresponding keymap. + */ +uint32_t +ei_event_keyboard_get_xkb_mods_locked(struct ei_event *event); + +/** + * For an event of type @ref EI_EVENT_KEYBOARD_MODIFIERS, get the + * logical group state. + * See ei_device_get_keymap() for the corresponding keymap. + */ +uint32_t +ei_event_keyboard_get_xkb_group(struct ei_event *event); + /** * Increase the refcount of this struct by one. Use ei_device_unref() to * decrease the refcount. diff --git a/src/libeis-client.c b/src/libeis-client.c index 3c3b461..626a993 100644 --- a/src/libeis-client.c +++ b/src/libeis-client.c @@ -143,6 +143,14 @@ client_send_device_resumed(struct eis_client *client, struct eis_device *device) return eis->requests->device_resumed(device); } +static int +client_send_keyboard_modifiers(struct eis_client *client, struct eis_device *device, + const struct eis_xkb_modifiers *mods) +{ + struct eis *eis = eis_client_get_context(client); + return eis->requests->keyboard_modifiers(device, mods); +} + _public_ void eis_client_connect(struct eis_client *client) { @@ -643,3 +651,18 @@ eis_client_resume_device(struct eis_client *client, struct eis_device *device) { client_send_device_resumed(client, device); } + +void +eis_client_keyboard_modifiers(struct eis_client *client, struct eis_device *device, + uint32_t depressed, uint32_t latched, uint32_t locked, + uint32_t group) +{ + struct eis_xkb_modifiers mods = { + .depressed = depressed, + .locked = locked, + .latched = latched, + .group = group, + }; + client_send_keyboard_modifiers(client, device, &mods); +} + diff --git a/src/libeis-device.c b/src/libeis-device.c index e77f73d..03f8e45 100644 --- a/src/libeis-device.c +++ b/src/libeis-device.c @@ -474,3 +474,17 @@ eis_device_resume(struct eis_device *device) device->state = EIS_DEVICE_STATE_RESUMED; eis_client_resume_device(eis_device_get_client(device), device); } + +_public_ void +eis_device_keyboard_send_xkb_modifiers(struct eis_device *device, uint32_t depressed, + uint32_t latched, uint32_t locked, uint32_t group) +{ + if (!eis_device_has_capability(device, EIS_DEVICE_CAP_KEYBOARD)) { + log_bug_client(eis_device_get_context(device), + "%s: device is not a keyboard\n", __func__); + return; + } + + eis_client_keyboard_modifiers(eis_device_get_client(device), + device, depressed, latched, locked, group); +} diff --git a/src/libeis-private.h b/src/libeis-private.h index 6281b69..4a16e62 100644 --- a/src/libeis-private.h +++ b/src/libeis-private.h @@ -181,6 +181,13 @@ struct eis_keymap { bool assigned; }; +struct eis_xkb_modifiers { + uint32_t depressed; + uint32_t locked; + uint32_t latched; + uint32_t group; +}; + void eis_init_object(struct eis *eis, struct object *parent); @@ -213,6 +220,11 @@ void eis_client_pause_device(struct eis_client *client, struct eis_device *device); +void +eis_client_keyboard_modifiers(struct eis_client *client, struct eis_device *device, + uint32_t depressed, uint32_t latched, uint32_t locked, + uint32_t group); + void eis_seat_bind(struct eis_seat *seat, uint32_t cap); diff --git a/src/libeis-proto.c b/src/libeis-proto.c index 88e5917..2e23fdb 100644 --- a/src/libeis-proto.c +++ b/src/libeis-proto.c @@ -56,6 +56,7 @@ log_wire_message(struct eis *eis, const ServerMessage *msg) MSG_STRING_CASE(DEVICE_REMOVED); MSG_STRING_CASE(DEVICE_RESUMED); MSG_STRING_CASE(DEVICE_PAUSED); + MSG_STRING_CASE(KEYBOARD_MODIFIERS); break; default: assert(!"Unimplemented message type"); @@ -202,6 +203,21 @@ eis_proto_send_device_region(struct eis_device *device, const struct eis_region return eis_proto_send_msg(eis_device_get_client(device), &msg); } +static int +eis_proto_send_keyboard_modifiers(struct eis_device *device, const struct eis_xkb_modifiers *mods) +{ + prepare_msg(KEYBOARD_MODIFIERS, KeyboardModifiers, keyboard_modifiers); + + keyboard_modifiers.deviceid = device->id; + keyboard_modifiers.depressed = mods->depressed; + keyboard_modifiers.locked = mods->locked; + keyboard_modifiers.latched = mods->latched; + keyboard_modifiers.group = mods->group; + + return eis_proto_send_msg(eis_device_get_client(device), &msg); +} + + static int eis_proto_send_device_removed(struct eis_device *device) { @@ -244,6 +260,7 @@ static const struct eis_proto_requests requests = { .device_keymap = eis_proto_send_device_keymap, .device_done = eis_proto_send_device_done, .device_region = eis_proto_send_device_region, + .keyboard_modifiers = eis_proto_send_keyboard_modifiers, }; const struct eis_proto_requests * diff --git a/src/libeis-proto.h b/src/libeis-proto.h index 75ead8f..f4be539 100644 --- a/src/libeis-proto.h +++ b/src/libeis-proto.h @@ -70,6 +70,8 @@ struct eis_proto_requests { int (*device_done)(struct eis_device *device); int (*device_region)(struct eis_device *device, const struct eis_region *region); + int (*keyboard_modifiers)(struct eis_device *device, + const struct eis_xkb_modifiers *mods); }; int diff --git a/src/libeis.h b/src/libeis.h index 92ed402..9a65e52 100644 --- a/src/libeis.h +++ b/src/libeis.h @@ -633,6 +633,15 @@ eis_keymap_get_device(struct eis_keymap *keymap); struct eis_keymap * eis_device_keyboard_get_keymap(struct eis_device *device); +/** + * Notify the client of the current XKB modifier state. + */ +void +eis_device_keyboard_send_xkb_modifiers(struct eis_device *device, + uint32_t depressed, + uint32_t latched, + uint32_t locked, + uint32_t group); /** * For an event of type @ref EIS_EVENT_SEAT_BIND, return the capabilities diff --git a/test/eierpecken.c b/test/eierpecken.c index bc6a747..db5f104 100644 --- a/test/eierpecken.c +++ b/test/eierpecken.c @@ -943,6 +943,7 @@ peck_ei_event_type_name(enum ei_event_type type) CASE_STRING(DEVICE_REMOVED); CASE_STRING(DEVICE_PAUSED); CASE_STRING(DEVICE_RESUMED); + CASE_STRING(KEYBOARD_MODIFIERS); } #undef CASE_STRING assert(!"Unhandled ei event type"); diff --git a/test/test-ei-device.c b/test/test-ei-device.c index b9f77c4..138d5c3 100644 --- a/test/test-ei-device.c +++ b/test/test-ei-device.c @@ -768,3 +768,38 @@ MUNIT_TEST(test_ei_keymap_set) return MUNIT_OK; } + +MUNIT_TEST(test_ei_keyboard_modifiers) +{ + _unref_(peck) *peck = peck_new(); + + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_ALL); + peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ADD_KEYBOARD); + peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES); + peck_dispatch_until_stable(peck); + + with_server(peck) { + struct eis_device *kbd = peck_eis_get_default_keyboard(peck); + eis_device_keyboard_send_xkb_modifiers(kbd, 0x1, 0x2, 0x4, 0x8); + } + + peck_dispatch_until_stable(peck); + + with_client(peck) { + _unref_(ei_event) *event = + peck_ei_next_event(ei, EI_EVENT_KEYBOARD_MODIFIERS); + + uint32_t depressed, locked, latched, group; + depressed = ei_event_keyboard_get_xkb_mods_depressed(event); + latched = ei_event_keyboard_get_xkb_mods_latched(event); + locked = ei_event_keyboard_get_xkb_mods_locked(event); + group = ei_event_keyboard_get_xkb_group(event); + + munit_assert_uint(depressed, ==, 0x1); + munit_assert_uint(latched, ==, 0x2); + munit_assert_uint(locked, ==, 0x4); + munit_assert_uint(group, ==, 0x8); + } + + return MUNIT_OK; +}