diff --git a/src/libeis-device.c b/src/libeis-device.c index a7bf00d..df2d009 100644 --- a/src/libeis-device.c +++ b/src/libeis-device.c @@ -428,6 +428,13 @@ client_msg_button(struct eis_button *button, uint32_t btn, uint32_t state) "Button event for non-button device"); } + if (btn >= KEY_CNT) + return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Button event for invalid button %x (KEY_CNT is %#x)", btn, KEY_CNT); + + if (!eis_device_update_key_button_state(device, btn, state)) + return NULL; + if (device->state == EIS_DEVICE_STATE_EMULATING) { eis_queue_pointer_button_event(device, btn, !!state); return NULL; @@ -598,6 +605,13 @@ client_msg_keyboard_key(struct eis_keyboard *keyboard, uint32_t key, uint32_t st "Key event for non-keyboard device"); } + if (key >= KEY_CNT) + return brei_result_new(EIS_CONNECTION_DISCONNECT_REASON_PROTOCOL, + "Key event for invalid key %x (KEY_CNT is %#x)", key, KEY_CNT); + + if (!eis_device_update_key_button_state(device, key, state)) + return NULL; + if (device->state == EIS_DEVICE_STATE_EMULATING) { eis_queue_keyboard_key_event(device, key, !!state); return NULL; @@ -1447,6 +1461,8 @@ eis_device_pause(struct eis_device *device) device->state = EIS_DEVICE_STATE_PAUSED; eis_device_event_paused(device, eis_client_get_next_serial(client)); + + memset(device->key_button_state.down, 0, sizeof(device->key_button_state.down)); } _public_ void diff --git a/src/libeis-device.h b/src/libeis-device.h index 5f6f2a1..97e74fa 100644 --- a/src/libeis-device.h +++ b/src/libeis-device.h @@ -26,10 +26,14 @@ #include "libeis.h" +#include "util-bits.h" #include "util-object.h" #include "util-list.h" #include "brei-shared.h" +#define KEY_MAX 0x2ffU +#define KEY_CNT (KEY_MAX + 1) + enum eis_device_state { EIS_DEVICE_STATE_NEW, EIS_DEVICE_STATE_AWAITING_READY, @@ -75,6 +79,9 @@ struct eis_device { bool x_is_cancelled, y_is_cancelled; } scroll_state; + struct { + unsigned char down[NCHARS(KEY_CNT)]; + } key_button_state; }; struct eis_touch { @@ -118,6 +125,21 @@ OBJECT_DECLARE_GETTER(eis_device, button_interface, const struct eis_button_inte OBJECT_DECLARE_GETTER(eis_device, keyboard_interface, const struct eis_keyboard_interface *); OBJECT_DECLARE_GETTER(eis_device, touchscreen_interface, const struct eis_touchscreen_interface *); +static inline bool +eis_device_update_key_button_state(struct eis_device *device, uint32_t key_btn, uint32_t state) +{ + if (state) { + if (bit_is_set(device->key_button_state.down, key_btn)) + return false; + set_bit(device->key_button_state.down, key_btn); + } else { + if (!bit_is_set(device->key_button_state.down, key_btn)) + return false; + clear_bit(device->key_button_state.down, key_btn); + } + return true; +} + void eis_device_set_client_keymap(struct eis_device *device, enum eis_keymap_type type, diff --git a/test/test-ei-device.c b/test/test-ei-device.c index 261de35..df24604 100644 --- a/test/test-ei-device.c +++ b/test/test-ei-device.c @@ -390,10 +390,20 @@ MUNIT_TEST(test_ei_device_button_button) struct ei_device *device = peck_ei_get_default_pointer(peck); ei_device_button_button(device, BTN_LEFT, true); ei_device_frame(device, peck_ei_now(peck)); + + /* double press is quietly ignored */ + ei_device_button_button(device, BTN_LEFT, true); + ei_device_frame(device, peck_ei_now(peck)); + ei_device_button_button(device, BTN_RIGHT, true); ei_device_frame(device, peck_ei_now(peck)); ei_device_button_button(device, BTN_RIGHT, false); ei_device_frame(device, peck_ei_now(peck)); + + /* double release is quietly ignored */ + ei_device_button_button(device, BTN_RIGHT, false); + ei_device_frame(device, peck_ei_now(peck)); + ei_device_button_button(device, BTN_LEFT, false); ei_device_frame(device, peck_ei_now(peck)); } @@ -421,6 +431,7 @@ MUNIT_TEST(test_ei_device_button_button) munit_assert_int(eis_event_button_get_button(lu), ==, BTN_LEFT); munit_assert_false(eis_event_button_get_is_press(lu)); + peck_assert_no_eis_events(eis); } return MUNIT_OK; @@ -439,6 +450,15 @@ MUNIT_TEST(test_ei_device_keyboard_key) struct ei_device *device = peck_ei_get_default_keyboard(peck); ei_device_keyboard_key(device, KEY_Q, true); ei_device_frame(device, peck_ei_now(peck)); + + /* Double press is quietly ignored */ + ei_device_keyboard_key(device, KEY_Q, true); + ei_device_frame(device, peck_ei_now(peck)); + + ei_device_keyboard_key(device, KEY_Q, false); + ei_device_frame(device, peck_ei_now(peck)); + + /* Double release is quietly ignored */ ei_device_keyboard_key(device, KEY_Q, false); ei_device_frame(device, peck_ei_now(peck)); }