libei: switch the keymap to be a separate object

This fits better with the rest of the API and also fits much nicer into the
most common use-case of "device doesn't have a keymap".

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
Peter Hutterer 2020-09-28 13:10:20 +10:00
parent 02efb19e2b
commit 76d59c11c9
7 changed files with 482 additions and 133 deletions

View file

@ -60,8 +60,8 @@ ei_device_set_state(struct ei_device *device,
static void
ei_device_destroy(struct ei_device *device)
{
ei_keymap_unref(device->keymap);
free(device->name);
xclose(device->keymap.fd);
}
_public_
@ -101,10 +101,6 @@ ei_device_new(struct ei *ei)
device->id = ++deviceid;
device->state = EI_DEVICE_STATE_NEW;
device->name = xaprintf("unnamed device %d", device->id);
device->keymap.source = EI_KEYMAP_SOURCE_SERVER;
device->keymap.fd = -1;
device->keymap.type = EI_KEYMAP_TYPE_NONE;
device->keymap.size = 0;
return device;
}
@ -170,31 +166,96 @@ ei_device_touch_configure_range(struct ei_device *device,
device->touch.dim.height = height;
}
_public_
OBJECT_IMPLEMENT_REF(ei_keymap);
_public_
OBJECT_IMPLEMENT_UNREF(ei_keymap);
#define _cleanup_ei_keymap_ _cleanup_(ei_keymap_cleanup)
_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);
_public_ struct ei_device *
ei_keymap_get_device(struct ei_keymap *keymap)
{
return keymap->device;
}
static void
ei_keymap_destroy(struct ei_keymap *keymap)
{
xclose(keymap->fd);
}
static
OBJECT_IMPLEMENT_CREATE(ei_keymap);
_public_ struct ei_keymap *
ei_device_keyboard_get_keymap(struct ei_device *device)
{
return device->keymap;
}
_public_ void
ei_device_keyboard_configure_keymap(struct ei_device *device,
enum ei_keymap_type type,
int fd, size_t size)
struct ei_keymap *keymap)
{
if (device->state != EI_DEVICE_STATE_NEW ||
!flag_is_set(device->capabilities, EI_DEVICE_CAP_KEYBOARD))
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD))
return;
if (fd < 0)
if (device->state != EI_DEVICE_STATE_NEW)
return;
/*
* This can be a quiet error because it should never happen
* anyway and if it does, the device will just have a -1 keymap
* after being accepted by the server.
*/
/* Can only call this once */
if (device->keymap) {
log_bug(ei_device_get_context(device),
"Device already has a keymap\n");
return;
}
if (!keymap)
return;
/* Reject any previously used keymaps */
if (keymap->assigned)
return;
keymap->assigned = true;
keymap->source = EI_KEYMAP_SOURCE_CLIENT;
keymap->device = device;
device->keymap = ei_keymap_ref(keymap);
}
_public_ struct ei_keymap *
ei_keymap_new(enum ei_keymap_type type, int fd, size_t size)
{
_cleanup_ei_keymap_ struct ei_keymap *keymap = ei_keymap_create(NULL);
switch (type) {
case EI_KEYMAP_TYPE_XKB:
break;
default:
return NULL;
}
if (fd < 0 || size == 0)
return NULL;
int newfd = dup(fd);
if (newfd < 0)
return;
return NULL;
device->keymap.source = EI_KEYMAP_SOURCE_CLIENT;
device->keymap.fd = newfd;
device->keymap.type = type;
device->keymap.size = size;
keymap->fd = newfd;
keymap->type = type;
keymap->size = size;
return ei_keymap_ref(keymap);
}
void
@ -202,10 +263,15 @@ ei_device_set_keymap(struct ei_device *device,
enum ei_keymap_type type,
int keymap_fd, size_t size)
{
device->keymap.source = EI_KEYMAP_SOURCE_SERVER;
device->keymap.fd = xclose(device->keymap.fd);
device->keymap.type = type;
device->keymap.size = size;
device->keymap = ei_keymap_unref(device->keymap);
_cleanup_ei_keymap_ struct ei_keymap *keymap = ei_keymap_new(type, keymap_fd, size);
if (!keymap)
return; /* FIXME: ei_device_remove() here */
keymap->device = device;
keymap->source = EI_KEYMAP_SOURCE_SERVER;
device->keymap = ei_keymap_ref(keymap);
}
_public_ void
@ -306,30 +372,6 @@ ei_device_touch_get_height(struct ei_device *device)
return device->touch.dim.height;
}
_public_ enum ei_keymap_source
ei_device_keyboard_get_keymap_source(struct ei_device *device)
{
return device->keymap.source;
}
_public_ enum ei_keymap_type
ei_device_keyboard_get_keymap_type(struct ei_device *device)
{
return device->keymap.type;
}
_public_ int
ei_device_keyboard_get_keymap(struct ei_device *device)
{
return device->keymap.fd;
}
_public_ size_t
ei_device_keyboard_get_keymap_size(struct ei_device *device)
{
return device->keymap.size;
}
_public_ void
ei_device_pointer_motion(struct ei_device *device,
double x, double y)
@ -469,6 +511,7 @@ ei_touch_up(struct ei_touch *touch)
#ifdef _enable_tests_
#include "src/util-munit.h"
#include "src/util-memfile.h"
MUNIT_TEST(test_device_new)
{
@ -620,4 +663,5 @@ MUNIT_TEST(test_device_touch_ranges)
return MUNIT_OK;
}
#endif

View file

@ -89,12 +89,17 @@ struct ei_device {
struct dimensions dim;
} touch;
struct {
enum ei_keymap_source source;
enum ei_keymap_type type;
int fd;
size_t size;
} keymap;
struct ei_keymap *keymap;
};
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;
bool assigned;
};
struct ei_touch {

View file

@ -90,8 +90,7 @@ ei_proto_parse_message(struct brei_message *bmsg, size_t *consumed)
.added.keymap_from_server = a->keymap_from_server,
.added.keymap_size = a->keymap_size,
};
if (a->keymap_type != EI_KEYMAP_TYPE_NONE &&
a->keymap_from_server)
if (a->keymap_type && a->keymap_from_server)
msg->added.keymap_fd = brei_message_take_fd(bmsg);
}
break;
@ -237,14 +236,20 @@ ei_proto_send_add(struct ei *ei, struct ei_device *device)
add.pointer_height = device->abs.dim.height;
add.touch_width = device->touch.dim.width;
add.touch_height = device->touch.dim.height;
add.keymap_type = device->keymap.type;
add.keymap_size = device->keymap.size;
add.keymap_type = 0;
int fd[2] = {-1, -1};
struct ei_keymap *keymap = device->keymap;
if (keymap) {
add.keymap_type = ei_keymap_get_type(keymap);
add.keymap_size = ei_keymap_get_size(keymap);
fd[0] = ei_keymap_get_fd(keymap);
}
msg.add_device = &add;
msg.msg_case = CLIENT_MESSAGE__MSG_ADD_DEVICE;
int fd[2] = {device->keymap.fd, -1};
return ei_proto_send_msg_with_fds(ei, &msg, fd);
}

View file

@ -74,6 +74,15 @@ struct ei_device;
*/
struct ei_event;
/**
* @struct ei_keymap
*
* An keymap for a device with the @ref EI_DEVICE_CAP_KEYBOARD capability.
*
* An @ref ei_keymap is refcounted, see ei_keymap_unref().
*/
struct ei_keymap;
/**
* @enum ei_device_capability
*
@ -100,23 +109,19 @@ enum ei_device_capability {
/**
* @enum ei_keymap_type
*
* The set of supported keymap types.
* The set of supported keymap types for a struct @ref ei_keymap.
*/
enum ei_keymap_type {
/**
* No explicit keymap has been assigned.
*/
EI_KEYMAP_TYPE_NONE = 0,
/**
* A libxkbcommon-compatible XKB keymap.
*/
EI_KEYMAP_TYPE_XKB,
EI_KEYMAP_TYPE_XKB = 1,
};
/**
* @enum ei_keymap_source
*
* Identifies who provided the device's keymap.
* Identifies who provided a struct @ref ei_keymap.
*/
enum ei_keymap_source {
/**
@ -531,32 +536,129 @@ ei_device_touch_configure_range(struct ei_device *device,
uint32_t width,
uint32_t height);
/**
* Set the keymap for this device. 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 responsibility of the client
* to handle the situation where a specific keymap is requested but the
* server does not allow its use on the device.
* Create a new keymap of the given @p 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 @p size pointing to the
* keymap used by this device. @p fd can be closed by the caller after this
* function completes.
* @param size The size of the data at @p 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);
/**
* @return the size of the keymap in bytes
*/
size_t
ei_keymap_get_size(struct ei_keymap *keymap);
/**
* Returns the type for this keymap. The type specifies how to interpret the
* data at the file descriptor returned by ei_keymap_get_fd().
*/
enum ei_keymap_type
ei_keymap_get_type(struct ei_keymap *keymap);
/**
* Return a memmap-able file descriptor pointing to the keymap used by the
* device. The keymap is constant for the lifetime of the device and
* assigned to this device individually.
*/
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.
*
* Between ei_device_keyboard_configure_keymap() and libei processing an
* @ref EI_EVENT_DEVICE_ADDED event, the returned device is the one provided
* in ei_device_keyboard_configure_keymap().
*
* After processing and if the server changed the keymap or set the keymap
* to NULL, this keymap may no longer be in use by the device and future
* calls to this function return `NULL`.
*/
struct ei_device *
ei_keymap_get_device(struct ei_keymap *keymap);
/**
* Increase the refcount of this struct by one. Use ei_keymap_unref() to
* decrease the refcount.
*
* @return the argument passed into the function
*/
struct ei_keymap *
ei_keymap_ref(struct ei_keymap *keymap);
/**
* Decrease the refcount of this struct by one. When the refcount reaches
* zero, the context disconnects from the server and all allocated resources
* are released.
*
* @return always NULL
*/
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.
*
* The keymap is constant on the device. To change keymaps, disconnect the
* device and create a new one.
* 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 has no effect if called after ei_device_add()
* 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 type the type of the keymap
* @param fd a memmap-able file descriptor to the keymap
* @param size size of the keymap in bytes
* @param keymap A non-`NULL` keymap
*/
void
ei_device_keyboard_configure_keymap(struct ei_device *device,
enum ei_keymap_type type,
int fd, size_t size);
struct ei_keymap *keymap);
/**
* Request that the device be added to the server.
@ -650,56 +752,28 @@ uint32_t
ei_device_touch_get_height(struct ei_device *device);
/**
* Return a memmap-able file descriptor pointing to the keymap used by the
* device. The keymap is constant for the lifetime of the device and
* assigned to this device individually.
* Return the keymap for this device or `NULL`. The keymap is constant for
* the lifetime of the device after the @ref EI_EVENT_DEVICE_ADDED was
* received and applies to this device individually.
*
* If this function returns -1, this device does not have
* an individual keymap assigned and the ei_device_keyboard_get_keymap_type() is @ref
* EI_KEYMAP_TYPE_NONE.
* If this function returns `NULL`, this device does not have
* an individual keymap assigned. What keymap applies to the device in this
* case is a server implementation detail.
*
* This does not increase the refcount of the keymap. Use ei_keymap_ref() to
* keep a reference beyond the immediate scope.
*
* FIXME: the current API makes it impossible to know when the keymap has
* been consumed so the file stays open forever.
*/
int
struct ei_keymap *
ei_device_keyboard_get_keymap(struct ei_device *device);
/**
* @return the size of the keymap in bytes
* Return the struct @ref ei_device this keymap is associated with.
*/
size_t
ei_device_keyboard_get_keymap_size(struct ei_device *device);
/**
* Returns the type for this keymap. If the type is @ref
* EI_KEYMAP_TYPE_NONE this device does not have a custom keymap assigned to
* it and ei_device_keyboard_get_keymap() returns -1.
*
* Otherwise, the type specifies how to interpret the data at the file
* descriptor returned by ei_device_keyboard_get_keymap().
*/
enum ei_keymap_type
ei_device_keyboard_get_keymap_type(struct ei_device *device);
/**
* 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 than -1 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 -1 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().
*
* Where ei_device_keyboard_get_keymap() returns -1, the return value of this
* function is undefined.
*/
enum ei_keymap_source
ei_device_keyboard_get_keymap_source(struct ei_device *device);
struct ei_device *
ei_keymap_get_context(struct ei_keymap *keymap);
/**
* Return the struct @ref ei context this device is associated with.

View file

@ -222,6 +222,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei_device *, ei_device_unref);
#define _cleanup_ei_device_ _cleanup_(ei_device_unrefp)
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei_touch *, ei_touch_unref);
#define _cleanup_ei_touch_ _cleanup_(ei_touch_unrefp)
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei_keymap *, ei_keymap_unref);
#define _cleanup_ei_keymap_ _cleanup_(ei_keymap_unrefp)
DEFINE_TRIVIAL_CLEANUP_FUNC(struct eis *, eis_unref);
#define _cleanup_eis_ _cleanup_(eis_unrefp)
@ -236,3 +238,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct eis_device *, eis_device_unref);
of a test handles server vs client */
#define with_server(peck_) for (struct eis *eis = peck_get_eis(peck_); eis; eis = NULL)
#define with_client(peck_) for (struct ei *ei = peck_get_ei(peck_); ei; ei = NULL)
#define peck_errno_check(_rc) { \
const int xrc = (_rc); \
if (xrc != 0) \
munit_errorf("errno is not 0: %d - %s\n", -xrc, strerror(-xrc)); \
}

View file

@ -1,13 +1,18 @@
#include "config.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "util-io.h"
#include "util-munit.h"
#include "util-memfile.h"
#include "libei.h"
#include "eierpecken.h"
DEFINE_TRIVIAL_CLEANUP_FUNC(struct memfile *, memfile_unref);
#define _cleanup_memfile_ _cleanup_(memfile_unrefp)
MUNIT_TEST(test_ei_ref_unref)
{
struct ei *ei = ei_new(NULL);
@ -933,6 +938,207 @@ MUNIT_TEST(test_ei_device_multitouch)
return MUNIT_OK;
}
MUNIT_TEST(test_ei_keymap_invalid)
{
const char data[5] = {1, 2, 3, 4, 5};
_cleanup_memfile_ struct memfile *fd = memfile_new(data, sizeof(data));
munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB + 1,
memfile_get_fd(fd), memfile_get_size(fd)));
munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB - 1,
memfile_get_fd(fd), memfile_get_size(fd)));
munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB,
-1, memfile_get_size(fd)));
munit_assert_ptr_null(ei_keymap_new(EI_KEYMAP_TYPE_XKB,
memfile_get_fd(fd), 0));
/* Valid keymap, valgrind checks only */
_cleanup_ei_keymap_ struct ei_keymap *unused =
ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd), memfile_get_size(fd));
munit_assert_ptr_not_null(unused);
return MUNIT_OK;
}
MUNIT_TEST(test_ei_keymap_set)
{
const char data[5] = {1, 2, 3, 4, 5};
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_ei_device_ struct ei_device *device = NULL;
_cleanup_memfile_ struct memfile *fd1 = memfile_new(data, sizeof(data));
_cleanup_ei_keymap_ struct ei_keymap *keymap = NULL;
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTODEVICES);
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_memfile_ struct memfile *fd2 = memfile_new(data, sizeof(data));
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD);
keymap = ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd1), memfile_get_size(fd1));
ei_device_keyboard_configure_keymap(device, keymap);
munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap);
/* Not possible to overwrite a keymap on a device */
_cleanup_ei_keymap_ struct ei_keymap *overwrite =
ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2));
ei_device_keyboard_configure_keymap(device, overwrite);
munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap);
ei_device_add(device);
/* Still impossible to overwrite after add */
_cleanup_ei_keymap_ struct ei_keymap *ignored =
ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2));
ei_device_keyboard_configure_keymap(device, ignored);
munit_assert_ptr_equal(ei_device_keyboard_get_keymap(device), keymap);
}
peck_dispatch_until_stable(peck);
with_server(peck) {
_cleanup_eis_event_ struct eis_event *event =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED);
struct eis_device *eis_device = eis_event_get_device(event);
int fd = eis_device_keyboard_get_keymap(eis_device);
munit_assert_int(fd, !=, -1);
munit_assert_uint(eis_device_keyboard_get_keymap_size(eis_device), ==, memfile_get_size(fd1));
munit_assert_uint(eis_device_keyboard_get_keymap_type(eis_device), ==, EIS_KEYMAP_TYPE_XKB);
eis_device_disconnect(eis_device);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *event =
peck_ei_next_event(ei, EI_EVENT_DEVICE_REMOVED);
struct ei_device *d = ei_event_get_device(event);
munit_assert_ptr_equal(d, device);
/* Rejecting a device does not unset the keymap because
* you're not supposed to do anything with the device anyway */
struct ei_keymap *km = ei_device_keyboard_get_keymap(device);
munit_assert_ptr_equal(keymap, km);
munit_assert_int(ei_keymap_get_source(keymap), ==, EI_KEYMAP_SOURCE_CLIENT);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_keymap_null)
{
const char data[5] = {1, 2, 3, 4, 5};
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_memfile_ struct memfile *fd = memfile_new(data, sizeof(data));
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_device_ struct ei_device *device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD);
_cleanup_ei_keymap_ struct ei_keymap *keymap =
ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd), memfile_get_size(fd));
ei_device_keyboard_configure_keymap(device, keymap);
ei_device_add(device);
}
peck_dispatch_until_stable(peck);
/* server sets the keymap to NULL */
with_server(peck) {
_cleanup_eis_event_ struct eis_event *event =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED);
struct eis_device *device = eis_event_get_device(event);
eis_device_keyboard_set_keymap(device, EIS_KEYMAP_TYPE_NONE, -1, 0);
eis_device_allow_capability(device, EIS_DEVICE_CAP_KEYBOARD);
eis_device_connect(device);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *event =
peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED);
struct ei_device *device = ei_event_get_device(event);
struct ei_keymap *keymap = ei_device_keyboard_get_keymap(device);
munit_assert_ptr_null(keymap);
}
return MUNIT_OK;
}
MUNIT_TEST(test_ei_keymap_changed)
{
const char data[5] = {1, 2, 3, 4, 5};
_cleanup_peck_ struct peck *peck = peck_new();
_cleanup_memfile_ struct memfile *fd1 = memfile_new(data, sizeof(data));
peck_enable_eis_behavior(peck, PECK_EIS_BEHAVIOR_ACCEPT_CLIENT);
peck_enable_ei_behavior(peck, PECK_EI_BEHAVIOR_AUTOCONNNECT);
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_device_ struct ei_device *device = NULL;
const char otherdata[2] = {10, 20};
_cleanup_memfile_ struct memfile *fd2 = memfile_new(data, sizeof(otherdata));
device = ei_device_new(ei);
ei_device_configure_name(device, __func__);
ei_device_configure_capability(device, EI_DEVICE_CAP_KEYBOARD);
_cleanup_ei_keymap_ struct ei_keymap *keymap =
ei_keymap_new(EI_KEYMAP_TYPE_XKB, memfile_get_fd(fd2), memfile_get_size(fd2));
ei_device_keyboard_configure_keymap(device, keymap);
ei_device_add(device);
}
peck_dispatch_until_stable(peck);
/* server sets the keymap to some other fd */
with_server(peck) {
_cleanup_eis_event_ struct eis_event *event =
peck_eis_next_event(eis, EIS_EVENT_DEVICE_ADDED);
struct eis_device *device = eis_event_get_device(event);
eis_device_keyboard_set_keymap(device, EIS_KEYMAP_TYPE_XKB,
memfile_get_fd(fd1),
memfile_get_size(fd1));
eis_device_allow_capability(device, EIS_DEVICE_CAP_KEYBOARD);
eis_device_connect(device);
}
peck_dispatch_until_stable(peck);
with_client(peck) {
_cleanup_ei_event_ struct ei_event *event =
peck_ei_next_event(ei, EI_EVENT_DEVICE_ADDED);
struct ei_device *device = ei_event_get_device(event);
struct ei_keymap *keymap = ei_device_keyboard_get_keymap(device);
munit_assert_ptr_not_null(keymap);
munit_assert_int(ei_keymap_get_type(keymap), ==, EI_KEYMAP_TYPE_XKB);
munit_assert_int(ei_keymap_get_source(keymap), ==, EI_KEYMAP_SOURCE_SERVER);
int km = ei_keymap_get_fd(keymap);
char buf[5];
int rc = min(xread(km, buf, sizeof(buf)), 0);
peck_errno_check(rc);
munit_assert_int(memcmp(buf, data, sizeof(buf)), ==, 0);
}
return MUNIT_OK;
}
int
main(int argc, char **argv)
{

View file

@ -46,6 +46,7 @@
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei *, ei_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei_device *, ei_device_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(struct ei_keymap *, ei_keymap_unref);
static inline void
_printf_(1, 2)
@ -99,8 +100,12 @@ setup_keymap(struct ei_device *kbd, const char *layout)
if (!f)
return;
ei_device_keyboard_configure_keymap(kbd, EI_KEYMAP_TYPE_XKB,
memfile_get_fd(f), memfile_get_size(f));
_cleanup_(ei_keymap_unrefp) struct 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);
memfile_unref(f);
#endif
}
@ -113,16 +118,18 @@ handle_keymap(struct ei_event *event)
if (!ei_device_has_capability(device, EI_DEVICE_CAP_KEYBOARD))
return;
const char *type = "unknown";
switch (ei_device_keyboard_get_keymap_type(device)) {
case EI_KEYMAP_TYPE_NONE: type = "none"; break;
case EI_KEYMAP_TYPE_XKB: type = "xkb"; break;
}
const char *type = "none";
const char *source = "unknown";
switch(ei_device_keyboard_get_keymap_source(device)) {
case EI_KEYMAP_SOURCE_CLIENT: source = "client"; break;
case EI_KEYMAP_SOURCE_SERVER: source = "server"; break;
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;
}
switch(ei_keymap_get_source(keymap)) {
case EI_KEYMAP_SOURCE_CLIENT: source = "client"; break;
case EI_KEYMAP_SOURCE_SERVER: source = "server"; break;
}
}
colorprint("Using keymap type %s from the %s\n", type, source);