Restructure keymap handling to server-side only

This keeps most of the current structure but gets rid of client-side
keymaps (which have been broken since the server-side devices anyway).
The new approach: clients get a keymap (or NULL) from the server, if
they don't like it they will have to do transformation on their side.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2021-08-10 14:47:55 +10:00
parent 55b79c44a5
commit 3abf13742a
13 changed files with 95 additions and 303 deletions

View file

@ -170,7 +170,6 @@ message DeviceAdded {
uint32 deviceid = 1;
uint32 capabilities = 2;
/* keymap is passed as fd if size is nonzero and type is not none */
bool keymap_from_server = 3;
uint32 keymap_type = 4;
uint32 keymap_size = 5;
string name = 6;

View file

@ -152,8 +152,6 @@ OBJECT_IMPLEMENT_UNREF(ei_keymap);
_public_
OBJECT_IMPLEMENT_GETTER(ei_keymap, type, enum ei_keymap_type);
_public_
OBJECT_IMPLEMENT_GETTER(ei_keymap, source, enum ei_keymap_source);
_public_
OBJECT_IMPLEMENT_GETTER(ei_keymap, fd, int);
_public_
OBJECT_IMPLEMENT_GETTER(ei_keymap, size, size_t);
@ -175,43 +173,7 @@ ei_device_keyboard_get_keymap(struct ei_device *device)
return device->keymap;
}
_public_ void
ei_device_keyboard_configure_keymap(struct ei_device *device,
struct ei_keymap *keymap)
{
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) {
log_bug_client(ei_device_get_context(device),
"%s: Device is not a keyboard\n", __func__);
return;
}
/* Can only call this once */
if (device->keymap) {
log_bug_client(ei_device_get_context(device),
"%s: Device already has a keymap\n", __func__);
return;
}
if (!keymap) {
log_bug_client(ei_device_get_context(device),
"%s: Keymap has already been used\n", __func__);
return;
}
/* Reject any previously used keymaps */
if (keymap->assigned) {
log_bug_client(ei_device_get_context(device),
"%s: Keymap has already been used\n", __func__);
return;
}
keymap->assigned = true;
keymap->source = EI_KEYMAP_SOURCE_CLIENT;
keymap->device = device;
device->keymap = ei_keymap_ref(keymap);
}
_public_ struct ei_keymap *
static struct ei_keymap *
ei_keymap_new(enum ei_keymap_type type, int fd, size_t size)
{
_unref_(ei_keymap) *keymap = ei_keymap_create(NULL);
@ -255,7 +217,6 @@ ei_device_set_keymap(struct ei_device *device,
}
keymap->device = device;
keymap->source = EI_KEYMAP_SOURCE_SERVER;
device->keymap = ei_keymap_ref(keymap);
}

View file

@ -130,7 +130,6 @@ struct ei_device {
struct ei_keymap {
struct object object;
struct ei_device *device;
enum ei_keymap_source source;
enum ei_keymap_type type;
int fd;
size_t size;

View file

@ -110,11 +110,10 @@ ei_proto_parse_message(struct brei_message *bmsg, size_t *consumed)
.device_added.capabilities = a->capabilities,
.device_added.keymap_fd = -1,
.device_added.keymap_type = a->keymap_type,
.device_added.keymap_from_server = a->keymap_from_server,
.device_added.keymap_size = a->keymap_size,
.device_added.seatid = a->seatid,
};
if (a->keymap_type && a->keymap_from_server)
if (a->keymap_type)
msg->device_added.keymap_fd = brei_message_take_fd(bmsg);
}
break;

View file

@ -85,7 +85,6 @@ struct message {
char *name;
uint32_t capabilities;
enum ei_keymap_type keymap_type;
bool keymap_from_server;
int keymap_fd;
size_t keymap_size;
uint32_t seatid;

View file

@ -524,7 +524,7 @@ handle_msg_seat_removed(struct ei *ei, uint32_t seatid)
static int
handle_msg_device_added(struct ei *ei, uint32_t deviceid,
const char *name, uint32_t capabilities,
bool keymap_from_server, enum ei_keymap_type keymap_type,
enum ei_keymap_type keymap_type,
int keymap_fd, size_t keymap_sz,
uint32_t seatid)
{
@ -548,9 +548,7 @@ handle_msg_device_added(struct ei *ei, uint32_t deviceid,
_unref_(ei_device) *device = ei_device_new(seat, deviceid);
ei_device_set_name(device, name);
ei_device_set_capabilities(device, capabilities);
if (keymap_from_server)
ei_device_set_keymap(device, keymap_type,
keymap_fd, keymap_sz);
ei_device_set_keymap(device, keymap_type, keymap_fd, keymap_sz);
ei_device_added(device);
log_debug(ei,
@ -877,7 +875,6 @@ connection_connected_handle_msg(struct ei *ei, struct message *msg)
msg->device_added.deviceid,
msg->device_added.name,
msg->device_added.capabilities,
msg->device_added.keymap_from_server,
msg->device_added.keymap_type,
msg->device_added.keymap_fd,
msg->device_added.keymap_size,

View file

@ -154,25 +154,6 @@ enum ei_keymap_type {
EI_KEYMAP_TYPE_XKB = 1,
};
/**
* @enum ei_keymap_source
*
* Identifies who provided a struct @ref ei_keymap.
*/
enum ei_keymap_source {
/**
* The keymap is the one provided by the client.
*/
EI_KEYMAP_SOURCE_CLIENT = 1,
/**
* The keymap is provided by the server.
*/
EI_KEYMAP_SOURCE_SERVER,
};
/**
* @enum ei_keymap_source
*/
enum ei_event_type {
/**
* The server has approved the connection to this client. Where the
@ -615,24 +596,8 @@ void *
ei_device_get_user_data(struct ei_device *device);
/**
* Create a new keymap of the given @a type. This keymap does not immediately
* apply to the device, use ei_device_keyboard_configure_keymap() to apply
* this keymap. A keymap may only be applied once and to a single device.
*
* The returned keymap has a refcount of at least 1, use ei_keymap_unref()
* to release resources associated with this keymap.
*
* @param type The type of the keymap.
* @param fd A memmap-able file descriptor of size @a size pointing to the
* keymap used by this device. @a fd can be closed by the caller after this
* function completes.
* @param size The size of the data at @a fd in bytes
*
* @return A keymap object or `NULL` on failure.
*/
struct ei_keymap *
ei_keymap_new(enum ei_keymap_type type, int fd, size_t size);
ei_device_get_keymap(struct ei_device *device);
/**
* @return the size of the keymap in bytes
@ -655,22 +620,6 @@ ei_keymap_get_type(struct ei_keymap *keymap);
int
ei_keymap_get_fd(struct ei_keymap *keymap);
/**
* Returns the source for the keymap on this device, if any. This is a
* convenience function for the client to check if its keymap was accepted.
*
* Where ei_device_keyboard_get_keymap() returns a value other `NULL` and
* this function returns @ref EI_KEYMAP_SOURCE_CLIENT, the keymap is the one
* provided with ei_device_keyboard_configure_keymap().
*
* Where ei_device_keyboard_get_keymap() returns a value other than `NULL`
* and this function returns @ref EI_KEYMAP_SOURCE_SERVER, the keymap is one
* created by the server and **not** the one provided with
* ei_device_keyboard_configure_keymap().
*/
enum ei_keymap_source
ei_keymap_get_source(struct ei_keymap *keymap);
/**
* Return the device this keymap belongs to, or `NULL` if it has not yet
* been assigned to a device.
@ -705,39 +654,6 @@ ei_keymap_ref(struct ei_keymap *keymap);
struct ei_keymap *
ei_keymap_unref(struct ei_keymap *keymap);
/**
* Request this keymap for this device with the @ref EI_DEVICE_CAP_KEYBOARD
* capability.
*
* The keymap for this device is a suggestion to the server, the actual
* keymap used by this device is provided with the @ref
* EI_EVENT_DEVICE_ADDED event. It is the client's responsibility to
* handle the situation where the server assigns a specific keymap (or none)
* that differs to the requested keymap.
*
* Note that keymap handling for individual input devices is largely
* left to private implementation details in the server. For example,
* modifier state or group handling may differ between server
* implementations.
*
* A keymap can only be used once and for one device only.
* Once a keymap has been assigned to a device, the caller may drop
* remaining references using ei_keymap_unref().
*
* This function can only be called once per device, further calls are
* ignored.
*
* This function has no effect if called after ei_device_add(). To change
* the keymap, the device must be removed and re-added with a different
* keymap.
*
* @param device The EI device
* @param keymap A non-`NULL` keymap
*/
void
ei_device_keyboard_configure_keymap(struct ei_device *device,
struct ei_keymap *keymap);
/**
* Notify the server that the client is no longer listening to events
* from this device.

View file

@ -41,10 +41,14 @@ _public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, fd, int);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, size, size_t);
_public_
OBJECT_IMPLEMENT_GETTER(eis_keymap, device, struct eis_device *);
static void
eis_keymap_destroy(struct eis_keymap *keymap)
{
if (!keymap->assigned)
eis_device_unref(keymap->device);
xclose(keymap->fd);
}
@ -52,10 +56,9 @@ static
OBJECT_IMPLEMENT_CREATE(eis_keymap);
_public_ struct eis_keymap *
eis_keymap_new(enum eis_keymap_type type, int fd, size_t size)
eis_keymap_new(struct eis_device *device,
enum eis_keymap_type type, int fd, size_t size)
{
_unref_(eis_keymap) *keymap = eis_keymap_create(NULL);
switch (type) {
case EIS_KEYMAP_TYPE_XKB:
break;
@ -70,11 +73,13 @@ eis_keymap_new(enum eis_keymap_type type, int fd, size_t size)
if (newfd < 0)
return NULL;
struct eis_keymap *keymap = eis_keymap_create(NULL);
keymap->device = eis_device_ref(device);
keymap->fd = newfd;
keymap->type = type;
keymap->size = size;
return eis_keymap_ref(keymap);
return keymap;
}
struct eis *
@ -84,32 +89,27 @@ eis_device_get_context(struct eis_device *device)
}
_public_ void
eis_device_keyboard_set_keymap(struct eis_device *device,
struct eis_keymap *keymap)
eis_keymap_add(struct eis_keymap *keymap)
{
struct eis_device *device = eis_keymap_get_device(keymap);
if (device->state != EIS_DEVICE_STATE_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: device already (dis)connected\n", __func__);
return;
}
if (device->keymap && !device->keymap->is_client_keymap) {
if (device->keymap) {
log_bug_client(eis_device_get_context(device),
"%s: keymap can only be configured once\n", __func__);
"%s: only one keymap can only be assigned and only once\n", __func__);
return;
}
if (keymap && keymap->assigned) {
log_bug_client(eis_device_get_context(device),
"%s: keymaps cannot be re-used\n", __func__);
return;
}
device->keymap = eis_keymap_unref(device->keymap);
if (keymap) {
keymap->assigned = true;
device->keymap = eis_keymap_ref(keymap);
}
/* New keymap holds ref to the device, for assigned keymap the device
* holds the ref to the keymap instead */
device->keymap = eis_keymap_ref(keymap);
keymap->assigned = true;
eis_device_unref(keymap->device);
}
_public_ struct eis_keymap *
@ -215,8 +215,16 @@ eis_device_configure_capability(struct eis_device *device, enum eis_device_capab
_public_ void
eis_device_add(struct eis_device *device)
{
if (device->state != EIS_DEVICE_STATE_NEW)
if (device->state != EIS_DEVICE_STATE_NEW) {
log_bug_client(eis_device_get_context(device),
"%s: device already (dis)connected\n", __func__);
return;
}
if (!device->capabilities) {
log_bug_client(eis_device_get_context(device),
"%s: adding device without capabilities\n", __func__);
}
device->state = EIS_DEVICE_STATE_SUSPENDED;
eis_client_add_device(eis_device_get_client(device), device);
@ -234,33 +242,6 @@ eis_device_remove(struct eis_device *device)
eis_device_unref(device);
}
void
eis_device_set_client_keymap(struct eis_device *device,
enum eis_keymap_type type,
int keymap_fd, size_t size)
{
if (device->state != EIS_DEVICE_STATE_NEW) {
log_bug(eis_device_get_context(device),
"%s: device already (dis)connected\n", __func__);
return;
}
if (type == 0 && keymap_fd == -1)
return;
_unref_(eis_keymap) *keymap =
eis_keymap_new(type, keymap_fd, size);
if (!keymap) {
log_bug(eis_device_get_context(device),
"%s: keymap creation failed, using NULL keymap\n", __func__);
return;
}
eis_device_keyboard_set_keymap(device, keymap);
keymap->is_client_keymap = true;
keymap->assigned = true;
}
_public_ bool
eis_device_has_capability(struct eis_device *device,
enum eis_device_capability cap)

View file

@ -176,7 +176,6 @@ struct eis_keymap {
int fd;
size_t size;
bool assigned;
bool is_client_keymap;
};
void

View file

@ -187,12 +187,7 @@ eis_proto_send_device_added(struct eis_client *client, struct eis_device *device
struct eis_keymap *keymap = device->keymap;
added.keymap_type = keymap->type;
added.keymap_size = keymap->size;
added.keymap_from_server = !keymap->is_client_keymap;
if (!keymap->is_client_keymap)
fds[0] = keymap->fd;
} else {
/* it's NULL anyway */
added.keymap_from_server = true;
fds[0] = keymap->fd;
}
msg.device_added = &added;

View file

@ -537,12 +537,13 @@ eis_device_resume(struct eis_device *device);
/**
* Create a new keymap of the given @a type. This keymap does not immediately
* apply to the device, use eis_device_keyboard_set_keymap() to apply
* this keymap. A keymap may only be applied once and to a single device.
* apply to the device, use eis_keymap_add() to apply this keymap. A keymap
* may only be applied once and to a single device.
*
* The returned keymap has a refcount of at least 1, use eis_keymap_unref()
* to release resources associated with this keymap.
*
* @param device The device with a @ref EIS_DEVICE_CAP_KEYBOARD capability
* @param type The type of the keymap.
* @param fd A memmap-able file descriptor of size @a size pointing to the
* keymap used by this device. @a fd can be closed by the caller after this
@ -552,7 +553,26 @@ eis_device_resume(struct eis_device *device);
* @return A keymap object or `NULL` on failure.
*/
struct eis_keymap *
eis_keymap_new(enum eis_keymap_type type, int fd, size_t size);
eis_keymap_new(struct eis_device *device,
enum eis_keymap_type type, int fd, size_t size);
/**
* Set the keymap on the device. Note that **not** calling this function when
* eis_device_keyboard_get_keymap() returns non-`NULL` meas the keymap is not
* applied to the device.
*
* The keymap is constant for the lifetime of the device and assigned to
* this device individually. Where the keymap has to change, remove the
* device and wait for the client to create a new one.
*
* If a keymap is `NULL`, the device does not have an individual keymap
* assigned. Note that this may mean the client needs to guess at the
* keymap layout.
*
* This function has no effect if called after eis_device_add()
*/
void
eis_keymap_add(struct eis_keymap *keymap);
/**
* @return the size of the keymap in bytes
@ -601,26 +621,6 @@ eis_keymap_get_device(struct eis_keymap *keymap);
struct eis_keymap *
eis_device_keyboard_get_keymap(struct eis_device *device);
/**
* Set the keymap on the device. This overwrites the client's keymap
* choice. Note that **not** calling this function when
* eis_device_keyboard_get_keymap() returns non-`NULL` is equivalent to
* accepting the client's choice of keymap.
*
* If the keymap is not `NULL`, the keymap is the one used by this device.
* This keymap is constant for the lifetime of the device and assigned to
* this device individually. Where the keymap has to change, remove the
* device and wait for the client to create a new one.
*
* If the keymap is `NULL`, the device does not have an individual keymap
* assigned. A server that does not handle individual client keymaps must
* call this function with an @a keymap of `NULL`.
*
* This function has no effect if called after eis_device_connect()
*/
void
eis_device_keyboard_set_keymap(struct eis_device *device,
struct eis_keymap *keymap);
/**
* For an event of type @ref EIS_EVENT_SEAT_BIND, return the capabilities

View file

@ -31,6 +31,7 @@
#include <signal.h>
#include <string.h>
#include <stdarg.h>
#include <linux/input-event-codes.h>
#if HAVE_LIBXKBCOMMON
#include <xkbcommon/xkbcommon.h>
@ -69,43 +70,46 @@ colorprint(const char *format, ...)
DEFINE_UNREF_CLEANUP_FUNC(xkb_context);
DEFINE_UNREF_CLEANUP_FUNC(xkb_keymap);
DEFINE_UNREF_CLEANUP_FUNC(xkb_state);
DEFINE_UNREF_CLEANUP_FUNC(memfile);
#endif
#if 0 /* FIXME: needs keymap revamp */
static void
setup_keymap(struct ei_device *kbd, const char *layout)
setup_xkb_keymap(struct ei_keymap *keymap)
{
#if HAVE_LIBXKBCOMMON
if (!keymap)
return;
_unref_(xkb_context) *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx)
return;
struct xkb_rule_names names = {
.rules = "evdev",
.model = "pc105",
.layout = layout,
};
size_t sz = ei_keymap_get_size(keymap);
_cleanup_free_ char *buf = xalloc(sz + 1);
read(ei_keymap_get_fd(keymap), buf, sz);
buf[sz] = '\0';
_unref_(xkb_keymap) *keymap = xkb_keymap_new_from_names(ctx, &names, 0);
if (!keymap)
_unref_(xkb_keymap) *xkbmap = xkb_keymap_new_from_string(ctx, buf,
XKB_KEYMAP_FORMAT_TEXT_V1,
XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkbmap)
return;
const char *str = xkb_keymap_get_as_string(keymap, XKB_KEYMAP_FORMAT_TEXT_V1);
size_t len = strlen(str) - 1;
struct memfile *f = memfile_new(str, len);
if (!f)
_unref_(xkb_state) *xkbstate = xkb_state_new(xkbmap);
if (!xkbstate)
return;
_unref_(ei_keymap) *ei_keymap = ei_keymap_new(EI_KEYMAP_TYPE_XKB,
memfile_get_fd(f),
memfile_get_size(f));
ei_device_keyboard_configure_keymap(kbd, ei_keymap);
char layout[6 * 7 + 1] = {0}; /* 6 keys, 7 bytes per key min */
for (unsigned int evcode = KEY_Q; evcode <= KEY_Y; evcode++) {
char utf8[7];
xkb_keysym_t keysym = xkb_state_key_get_one_sym(xkbstate, evcode + 8);
xkb_keysym_to_utf8(keysym, utf8, sizeof(utf8));
strcat(layout, utf8);
}
memfile_unref(f);
colorprint("XKB keymap: %s\n", layout);
#endif
}
#endif
static void
handle_keymap(struct ei_event *event)
@ -115,21 +119,16 @@ handle_keymap(struct ei_event *event)
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD))
return;
const char *type = "none";
const char *source = "unknown";
struct ei_keymap *keymap = ei_device_keyboard_get_keymap(device);
if (keymap) {
switch (ei_keymap_get_type(keymap)) {
case EI_KEYMAP_TYPE_XKB: type = "xkb"; break;
}
if (!keymap)
return;
switch(ei_keymap_get_source(keymap)) {
case EI_KEYMAP_SOURCE_CLIENT: source = "client"; break;
case EI_KEYMAP_SOURCE_SERVER: source = "server"; break;
}
enum ei_keymap_type type = ei_keymap_get_type(keymap);
switch (type) {
case EI_KEYMAP_TYPE_XKB:
setup_xkb_keymap(keymap);
break;
}
colorprint("Using keymap type %s from the %s\n", type, source);
}
static void
@ -147,7 +146,6 @@ usage(FILE *fp, const char *argv0)
" otherwise XDG_RUNTIME/eis-0\n"
" --portal Use the portal backend.\n"
" --busname Use the given busname (default: org.freedesktop.portal.Desktop)\n"
" --layout Use the given XKB layout (requires libxkbcommon). Default: none\n"
" --verbose Enable debugging output\n"
"",
argv0);
@ -160,8 +158,6 @@ int main(int argc, char **argv)
PORTAL,
} backend = SOCKET;
bool verbose = false;
_unused_ const char *layout = NULL;
_cleanup_free_ char *busname = xstrdup("org.freedesktop.portal.Desktop");
while (1) {
@ -169,14 +165,12 @@ int main(int argc, char **argv)
OPT_BACKEND_SOCKET,
OPT_BACKEND_PORTAL,
OPT_BUSNAME,
OPT_LAYOUT,
OPT_VERBOSE,
};
static struct option long_opts[] = {
{"socket", no_argument, 0, OPT_BACKEND_SOCKET},
{ "portal", no_argument, 0, OPT_BACKEND_PORTAL},
{ "busname", required_argument, 0, OPT_BUSNAME},
{ "layout", required_argument, 0, OPT_LAYOUT},
{ "verbose", no_argument, 0, OPT_VERBOSE},
{ "help", no_argument, 0, 'h'},
{NULL},
@ -204,9 +198,6 @@ int main(int argc, char **argv)
free(busname);
busname = xstrdup(optarg);
break;
case OPT_LAYOUT:
layout = optarg;
break;
default:
usage(stderr, argv[0]);
return EXIT_FAILURE;
@ -298,7 +289,6 @@ int main(int argc, char **argv)
if (ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD)) {
colorprint("New keyboard device: %s\n", ei_device_get_name(device));
kbd = device;
/* FIXME */
handle_keymap(e);
}
}

View file

@ -86,7 +86,7 @@ DEFINE_UNREF_CLEANUP_FUNC(xkb_state);
#endif
static void
setup_server_keymap(struct eis_demo_server *server, struct eis_device *device)
setup_keymap(struct eis_demo_server *server, struct eis_device *device)
{
#if HAVE_LIBXKBCOMMON
colorprint("Using server layout: %s\n", server->layout);
@ -111,9 +111,10 @@ setup_server_keymap(struct eis_demo_server *server, struct eis_device *device)
if (!f)
return;
_unref_(eis_keymap) *k = eis_keymap_new(EIS_KEYMAP_TYPE_XKB, memfile_get_fd(f),
_unref_(eis_keymap) *k = eis_keymap_new(device,
EIS_KEYMAP_TYPE_XKB, memfile_get_fd(f),
memfile_get_size(f));
eis_device_keyboard_set_keymap(device, k);
eis_keymap_add(k);
memfile_unref(f);
_unref_(xkb_state) *state = xkb_state_new(keymap);
@ -126,49 +127,6 @@ setup_server_keymap(struct eis_demo_server *server, struct eis_device *device)
#endif
}
static void
setup_client_keymap(struct eis_demo_server *server, struct eis_device *device)
{
#if HAVE_LIBXKBCOMMON
struct eis_keymap *keymap = eis_device_keyboard_get_keymap(device);
if (!keymap)
return;
colorprint("Using client keymap\n");
int fd = eis_keymap_get_fd(keymap);
size_t size = eis_keymap_get_size(keymap);
char *str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (str == MAP_FAILED)
return;
_unref_(xkb_context) *ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!ctx)
return;
_unref_(xkb_keymap) *xkb_keymap = xkb_keymap_new_from_string(ctx, str,
XKB_KEYMAP_FORMAT_TEXT_V1, 0);
if (!keymap)
return;
_unref_(xkb_state) *state = xkb_state_new(xkb_keymap);
if (!state)
return;
server->ctx = steal(&ctx);
server->keymap = steal(&xkb_keymap);
server->state = steal(&state);
#endif
}
static void
setup_keymap(struct eis_demo_server *server, struct eis_device *device)
{
if (server->layout)
setup_server_keymap(server, device);
else
setup_client_keymap(server, device);
}
static void
handle_key(struct eis_demo_server *server, uint32_t keycode, bool is_press)
{
@ -239,9 +197,9 @@ eis_demo_server_printf_handle_event(struct eis_demo_server *server,
struct eis_device *kbd = eis_device_new(seat);
eis_device_configure_name(kbd, "test keyboard");
/* FIXME: review keymaps */
setup_keymap(server, kbd);
eis_device_configure_capability(kbd, EIS_DEVICE_CAP_KEYBOARD);
if (server->layout)
setup_keymap(server, kbd);
colorprint("Creating keyboard device %s for %s\n", eis_device_get_name(kbd),
eis_client_get_name(client));
eis_device_add(kbd);
@ -338,8 +296,7 @@ usage(FILE *fp, const char *argv0)
"Options:\n"
" --socketpath Use the given socket path. Default: $XDG_RUNTIME/eis-0\n"
" --force Remove the socket if it already exists\n"
" --layout Use the given XKB layout (requires libxkbcommon). Default:\n"
" use the client-supplied keymap, if any\n"
" --layout Use the given XKB layout (requires libxkbcommon). Default: none\n"
" --uinput Set up each device as uinput device (this requires root)\n"
" --verbose Enable debugging output\n"
"",