mirror of
https://gitlab.freedesktop.org/libinput/libei.git
synced 2026-01-02 12:10:10 +01:00
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:
parent
02efb19e2b
commit
76d59c11c9
7 changed files with 482 additions and 133 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
196
src/libei.h
196
src/libei.h
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)); \
|
||||
}
|
||||
|
|
|
|||
208
test/test-ei.c
208
test/test-ei.c
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue