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 <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2021-08-23 09:00:29 +10:00
parent 730a82d28d
commit 6f70e97cce
15 changed files with 266 additions and 0 deletions

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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 *

View file

@ -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);

View file

@ -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 {

View file

@ -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[] = {

View file

@ -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.

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);

View file

@ -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 *

View file

@ -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

View file

@ -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

View file

@ -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");

View file

@ -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;
}