mirror of
https://gitlab.freedesktop.org/libevdev/libevdev.git
synced 2025-12-20 18:30:07 +01:00
Initialize the slots correctly when enabling ABS_MT_SLOT
Previously, enabling or disabling ABS_MT_SLOT would not change the actual slots, it was treated as a normal bitflag. This means we couldn't initialize a libevdev context from scratch and have it behave like a correct MT context. Fixes #4 Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
This commit is contained in:
parent
4d745caab4
commit
da67db5f59
3 changed files with 281 additions and 34 deletions
|
|
@ -315,6 +315,90 @@ libevdev_change_fd(struct libevdev *dev, int fd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_tracking_ids(struct libevdev *dev)
|
||||
{
|
||||
if (dev->num_slots == -1 ||
|
||||
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_TRACKING_ID))
|
||||
return;
|
||||
|
||||
for (int slot = 0; slot < dev->num_slots; slot++)
|
||||
libevdev_set_slot_value(dev, slot, ABS_MT_TRACKING_ID, -1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
free_slots(struct libevdev *dev)
|
||||
{
|
||||
dev->num_slots = -1;
|
||||
free(dev->mt_slot_vals);
|
||||
free(dev->mt_sync.tracking_id_changes);
|
||||
free(dev->mt_sync.slot_update);
|
||||
free(dev->mt_sync.mt_state);
|
||||
dev->mt_slot_vals = NULL;
|
||||
dev->mt_sync.tracking_id_changes = NULL;
|
||||
dev->mt_sync.slot_update = NULL;
|
||||
dev->mt_sync.mt_state = NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
init_slots(struct libevdev *dev)
|
||||
{
|
||||
const struct input_absinfo *abs_info;
|
||||
int rc = 0;
|
||||
|
||||
free(dev->mt_slot_vals);
|
||||
free(dev->mt_sync.tracking_id_changes);
|
||||
free(dev->mt_sync.slot_update);
|
||||
free(dev->mt_sync.mt_state);
|
||||
dev->mt_slot_vals = NULL;
|
||||
dev->mt_sync.tracking_id_changes = NULL;
|
||||
dev->mt_sync.slot_update = NULL;
|
||||
dev->mt_sync.mt_state = NULL;
|
||||
|
||||
/* devices with ABS_RESERVED aren't MT devices,
|
||||
see the documentation for multitouch-related
|
||||
functions for more details */
|
||||
if (libevdev_has_event_code(dev, EV_ABS, ABS_RESERVED) ||
|
||||
!libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
|
||||
if (dev->num_slots != -1) {
|
||||
free_slots(dev);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT);
|
||||
|
||||
free_slots(dev);
|
||||
dev->num_slots = abs_info->maximum + 1;
|
||||
dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int));
|
||||
if (!dev->mt_slot_vals) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dev->current_slot = abs_info->value;
|
||||
|
||||
dev->mt_sync.mt_state_sz = sizeof(*dev->mt_sync.mt_state) +
|
||||
(dev->num_slots) * sizeof(int);
|
||||
dev->mt_sync.mt_state = calloc(1, dev->mt_sync.mt_state_sz);
|
||||
|
||||
dev->mt_sync.tracking_id_changes_sz = NLONGS(dev->num_slots) * sizeof(long);
|
||||
dev->mt_sync.tracking_id_changes = malloc(dev->mt_sync.tracking_id_changes_sz);
|
||||
|
||||
dev->mt_sync.slot_update_sz = NLONGS(dev->num_slots * ABS_MT_CNT) * sizeof(long);
|
||||
dev->mt_sync.slot_update = malloc(dev->mt_sync.slot_update_sz);
|
||||
|
||||
if (!dev->mt_sync.tracking_id_changes ||
|
||||
!dev->mt_sync.slot_update ||
|
||||
!dev->mt_sync.mt_state) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
reset_tracking_ids(dev);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
LIBEVDEV_EXPORT int
|
||||
libevdev_set_fd(struct libevdev* dev, int fd)
|
||||
{
|
||||
|
|
@ -461,42 +545,12 @@ libevdev_set_fd(struct libevdev* dev, int fd)
|
|||
|
||||
dev->fd = fd;
|
||||
|
||||
/* devices with ABS_RESERVED aren't MT devices,
|
||||
see the documentation for multitouch-related
|
||||
functions for more details */
|
||||
if (!libevdev_has_event_code(dev, EV_ABS, ABS_RESERVED) &&
|
||||
libevdev_has_event_code(dev, EV_ABS, ABS_MT_SLOT)) {
|
||||
const struct input_absinfo *abs_info;
|
||||
|
||||
abs_info = libevdev_get_abs_info(dev, ABS_MT_SLOT);
|
||||
|
||||
dev->num_slots = abs_info->maximum + 1;
|
||||
dev->mt_slot_vals = calloc(dev->num_slots * ABS_MT_CNT, sizeof(int));
|
||||
if (!dev->mt_slot_vals) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
dev->current_slot = abs_info->value;
|
||||
|
||||
dev->mt_sync.mt_state_sz = sizeof(*dev->mt_sync.mt_state) +
|
||||
(dev->num_slots) * sizeof(int);
|
||||
dev->mt_sync.mt_state = calloc(1, dev->mt_sync.mt_state_sz);
|
||||
|
||||
dev->mt_sync.tracking_id_changes_sz = NLONGS(dev->num_slots) * sizeof(long);
|
||||
dev->mt_sync.tracking_id_changes = malloc(dev->mt_sync.tracking_id_changes_sz);
|
||||
|
||||
dev->mt_sync.slot_update_sz = NLONGS(dev->num_slots * ABS_MT_CNT) * sizeof(long);
|
||||
dev->mt_sync.slot_update = malloc(dev->mt_sync.slot_update_sz);
|
||||
|
||||
if (!dev->mt_sync.tracking_id_changes ||
|
||||
!dev->mt_sync.slot_update ||
|
||||
!dev->mt_sync.mt_state) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
rc = init_slots(dev);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
if (dev->num_slots != -1)
|
||||
sync_mt_state(dev, 0);
|
||||
}
|
||||
|
||||
rc = init_event_queue(dev);
|
||||
if (rc < 0) {
|
||||
|
|
@ -1487,6 +1541,12 @@ libevdev_enable_event_code(struct libevdev *dev, unsigned int type,
|
|||
if (type == EV_ABS) {
|
||||
const struct input_absinfo *abs = data;
|
||||
dev->abs_info[code] = *abs;
|
||||
if (code == ABS_MT_SLOT) {
|
||||
if (init_slots(dev) != 0)
|
||||
return -1;
|
||||
} else if (code == ABS_MT_TRACKING_ID) {
|
||||
reset_tracking_ids(dev);
|
||||
}
|
||||
} else if (type == EV_REP) {
|
||||
const int *value = data;
|
||||
dev->rep_values[code] = *value;
|
||||
|
|
@ -1511,6 +1571,15 @@ libevdev_disable_event_code(struct libevdev *dev, unsigned int type, unsigned in
|
|||
|
||||
clear_bit(mask, code);
|
||||
|
||||
if (type == EV_ABS) {
|
||||
if (code == ABS_MT_SLOT) {
|
||||
if (init_slots(dev) != 0)
|
||||
return -1;
|
||||
} else if (code == ABS_MT_TRACKING_ID) {
|
||||
reset_tracking_ids(dev);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ test_event_codes_SOURCES = \
|
|||
test-main.c \
|
||||
test-event-codes.c \
|
||||
test-event-names.c \
|
||||
test-context.c \
|
||||
$(common_sources)
|
||||
test_event_codes_LDADD = $(CHECK_LIBS) $(top_builddir)/libevdev/libevdev.la
|
||||
test_event_codes_LDFLAGS = -no-install
|
||||
|
|
|
|||
177
test/test-context.c
Normal file
177
test/test-context.c
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* Copyright © 2019 Red Hat, Inc.
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software and its
|
||||
* documentation for any purpose is hereby granted without fee, provided that
|
||||
* the above copyright notice appear in all copies and that both that copyright
|
||||
* notice and this permission notice appear in supporting documentation, and
|
||||
* that the name of the copyright holders not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without specific,
|
||||
* written prior permission. The copyright holders make no representations
|
||||
* about the suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||||
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
|
||||
* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
|
||||
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
* OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include "test-common.h"
|
||||
|
||||
START_TEST(test_info)
|
||||
{
|
||||
struct libevdev *d = libevdev_new();
|
||||
|
||||
libevdev_set_name(d, "some name");
|
||||
ck_assert_str_eq(libevdev_get_name(d), "some name");
|
||||
libevdev_set_phys(d, "physical");
|
||||
ck_assert_str_eq(libevdev_get_phys(d), "physical");
|
||||
libevdev_set_uniq(d, "very unique");
|
||||
ck_assert_str_eq(libevdev_get_uniq(d), "very unique");
|
||||
|
||||
libevdev_set_id_bustype(d, 1);
|
||||
libevdev_set_id_vendor(d, 2);
|
||||
libevdev_set_id_product(d, 3);
|
||||
libevdev_set_id_version(d, 4);
|
||||
ck_assert_int_eq(libevdev_get_id_bustype(d), 1);
|
||||
ck_assert_int_eq(libevdev_get_id_vendor(d), 2);
|
||||
ck_assert_int_eq(libevdev_get_id_product(d), 3);
|
||||
ck_assert_int_eq(libevdev_get_id_version(d), 4);
|
||||
|
||||
libevdev_free(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_properties)
|
||||
{
|
||||
for (unsigned prop = 0; prop < INPUT_PROP_CNT; prop++) {
|
||||
struct libevdev *d = libevdev_new();
|
||||
|
||||
ck_assert(!libevdev_has_property(d, prop));
|
||||
libevdev_enable_property(d, prop);
|
||||
ck_assert(libevdev_has_property(d, prop));
|
||||
libevdev_free(d);
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_bits)
|
||||
{
|
||||
for (unsigned type = 1; type < EV_CNT; type++) {
|
||||
unsigned max = libevdev_event_type_get_max(type);
|
||||
|
||||
if((int)max == -1)
|
||||
continue;
|
||||
|
||||
for (unsigned code = 0; code <= max; code++) {
|
||||
struct libevdev *d = libevdev_new();
|
||||
const struct input_absinfo abs = {
|
||||
10, 20, 30, 40, 50
|
||||
};
|
||||
const void *data = NULL;
|
||||
|
||||
if (type == EV_ABS || type == EV_REP)
|
||||
data = &abs;
|
||||
|
||||
ck_assert(!libevdev_has_event_code(d, type, code));
|
||||
libevdev_enable_event_code(d, type, code, data);
|
||||
ck_assert(libevdev_has_event_code(d, type, code));
|
||||
libevdev_free(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_mt_slots_enable_disable)
|
||||
{
|
||||
struct libevdev *d = libevdev_new();
|
||||
struct input_absinfo abs = {0};
|
||||
|
||||
abs.maximum = 5;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 6);
|
||||
|
||||
libevdev_disable_event_code(d, EV_ABS, ABS_MT_SLOT);
|
||||
ck_assert(!libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), -1);
|
||||
|
||||
abs.maximum = 2;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 3);
|
||||
|
||||
libevdev_free(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_mt_slots_increase_decrease)
|
||||
{
|
||||
struct libevdev *d = libevdev_new();
|
||||
struct input_absinfo abs = {0};
|
||||
|
||||
abs.maximum = 5;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 6);
|
||||
|
||||
abs.maximum = 2;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 3);
|
||||
|
||||
abs.maximum = 6;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 7);
|
||||
|
||||
abs.maximum = 10;
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
ck_assert(libevdev_has_event_code(d, EV_ABS, ABS_MT_SLOT));
|
||||
ck_assert_int_eq(libevdev_get_num_slots(d), 11);
|
||||
|
||||
libevdev_free(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_mt_tracking_id)
|
||||
{
|
||||
struct libevdev *d = libevdev_new();
|
||||
struct input_absinfo abs = { .maximum = 5 };
|
||||
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_SLOT, &abs);
|
||||
|
||||
/* Not yet enabled, so 0. This is technically undefined */
|
||||
for (int slot = 0; slot < 5; slot++)
|
||||
ck_assert_int_eq(libevdev_get_slot_value(d, 0, ABS_MT_TRACKING_ID), 0);
|
||||
|
||||
libevdev_enable_event_code(d, EV_ABS, ABS_MT_TRACKING_ID, &abs);
|
||||
|
||||
for (int slot = 0; slot < 5; slot++)
|
||||
ck_assert_int_eq(libevdev_get_slot_value(d, 0, ABS_MT_TRACKING_ID), -1);
|
||||
|
||||
libevdev_free(d);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
TEST_SUITE(event_name_suite)
|
||||
{
|
||||
Suite *s = suite_create("Context manipulation");
|
||||
TCase *tc;
|
||||
|
||||
tc = tcase_create("Device info");
|
||||
tcase_add_test(tc, test_info);
|
||||
tcase_add_test(tc, test_properties);
|
||||
tcase_add_test(tc, test_bits);
|
||||
tcase_add_test(tc, test_mt_slots_enable_disable);
|
||||
tcase_add_test(tc, test_mt_slots_increase_decrease);
|
||||
tcase_add_test(tc, test_mt_tracking_id);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue