diff --git a/src/evdev-frame.h b/src/evdev-frame.h index 0f50e0a3..15a37aaf 100644 --- a/src/evdev-frame.h +++ b/src/evdev-frame.h @@ -29,6 +29,7 @@ #include #include +#include "util-bits.h" #include "util-input-event.h" #include "util-mem.h" #include "util-newtype.h" @@ -652,3 +653,121 @@ evdev_frame_clone(struct evdev_frame *frame) return clone; } + +struct evdev_mask { + bitmask_t ev; + bitmask_t rel; + bitmask_t sw; + infmask_t key; /* < BTN_MISC */ + infmask_t btn; /* >= BTN_MISC */ + infmask_t abs; +}; + +static_assert(sizeof(bitmask_t) * 8 >= EV_MAX, "bitmask size too small"); +static_assert(sizeof(bitmask_t) * 8 >= EV_REL, "bitmask size too small"); +static_assert(sizeof(bitmask_t) * 8 >= EV_SW, "bitmask size too small"); + +static inline void +evdev_mask_reset(struct evdev_mask *mask) +{ + mask->ev = bitmask_new(); + mask->rel = bitmask_new(); + mask->sw = bitmask_new(); + infmask_reset(&mask->key); + infmask_reset(&mask->btn); + infmask_reset(&mask->abs); +} + +static inline struct evdev_mask * +evdev_mask_new(void) +{ + struct evdev_mask *mask = zalloc(sizeof(*mask)); + evdev_mask_reset(mask); + return mask; +} + +static inline void +evdev_mask_destroy(struct evdev_mask *mask) +{ + if (mask) { + evdev_mask_reset(mask); + free(mask); + } +} + +DEFINE_DESTROY_CLEANUP_FUNC(evdev_mask); + +static inline void +evdev_mask_set_usage(struct evdev_mask *mask, evdev_usage_t usage) +{ + unsigned int type = evdev_usage_type(usage); + unsigned int code = evdev_usage_code(usage); + + if (type >= EV_MAX) + return; + + bitmask_set_bit(&mask->ev, type); + + switch (type) { + case EV_ABS: + if (code <= ABS_MAX) + infmask_set_bit(&mask->abs, code); + break; + case EV_KEY: + if (code < BTN_MISC) + infmask_set_bit(&mask->key, code); + else if (code <= KEY_MAX) + infmask_set_bit(&mask->btn, code - BTN_MISC); + break; + case EV_REL: + if (code <= REL_MAX) + bitmask_set_bit(&mask->rel, code); + break; + case EV_SW: + if (code <= SW_MAX) + bitmask_set_bit(&mask->sw, code); + break; + } +} + +static inline void +evdev_mask_set_enum(struct evdev_mask *mask, enum evdev_usage usage) +{ + evdev_mask_set_usage(mask, evdev_usage_from(usage)); +} + +static inline bool +evdev_mask_is_set(const struct evdev_mask *mask, evdev_usage_t usage) +{ + unsigned int type = evdev_usage_type(usage); + unsigned int code = evdev_usage_code(usage); + + if (type >= EV_MAX) + return false; + + if (!bitmask_bit_is_set(mask->ev, type)) + return false; + + bool isset = false; + switch (type) { + case EV_ABS: + isset = infmask_bit_is_set(&mask->abs, code); + break; + case EV_KEY: + if (code < BTN_MISC) + isset = infmask_bit_is_set(&mask->key, code); + else + isset = infmask_bit_is_set(&mask->btn, code - BTN_MISC); + break; + case EV_REL: + isset = bitmask_bit_is_set(mask->rel, code); + break; + case EV_SW: + isset = bitmask_bit_is_set(mask->sw, code); + break; + default: + break; + } + + return isset; +} diff --git a/test/test-utils.c b/test/test-utils.c index 26193d0c..36b4fd16 100644 --- a/test/test-utils.c +++ b/test/test-utils.c @@ -3150,6 +3150,51 @@ START_TEST(infmask_test) } END_TEST +START_TEST(evdev_mask_test) +{ + _destroy_(evdev_mask) *mask = evdev_mask_new(); + + evdev_mask_reset(mask); + + litest_assert(bitmask_is_empty(mask->ev)); + litest_assert(bitmask_is_empty(mask->rel)); + litest_assert(bitmask_is_empty(mask->sw)); + litest_assert(infmask_is_empty(&mask->key)); + litest_assert(infmask_is_empty(&mask->btn)); + litest_assert(infmask_is_empty(&mask->abs)); + + evdev_mask_set_enum(mask, EVDEV_BTN_TOOL_PEN); + evdev_mask_set_enum(mask, EVDEV_BTN_TOOL_AIRBRUSH); + + litest_assert(bitmask_bit_is_set(mask->ev, EV_KEY)); + + /* Verify these are in btn, not key */ + litest_assert(!infmask_is_empty(&mask->btn)); + litest_assert(infmask_is_empty(&mask->key)); + + litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_PEN))); + litest_assert( + !evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_RUBBER))); + litest_assert( + evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_AIRBRUSH))); + + /* Test regular key (should go into key field) */ + evdev_mask_set_enum(mask, EVDEV_KEY_ESC); + litest_assert(!infmask_is_empty(&mask->key)); + litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_KEY_ESC))); + + evdev_mask_set_enum(mask, EVDEV_REL_X); + litest_assert(bitmask_bit_is_set(mask->ev, EV_REL)); + litest_assert(bitmask_bit_is_set(mask->rel, REL_X)); + litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_REL_X))); + + evdev_mask_set_enum(mask, EVDEV_ABS_X); + litest_assert(bitmask_bit_is_set(mask->ev, EV_ABS)); + litest_assert(!infmask_is_empty(&mask->abs)); + litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_ABS_X))); +} +END_TEST + int main(void) { @@ -3238,6 +3283,8 @@ main(void) ADD_TEST(infmask_test); + ADD_TEST(evdev_mask_test); + enum litest_runner_result result = litest_runner_run_tests(runner); litest_runner_destroy(runner);