eis: quietly ignore double key presses and releases

This is only implemented on the EIS side of things because that side is
mostly what we want to protect (read: the compositors). The duplicates
are still sent on the protocol.

Part-of: <https://gitlab.freedesktop.org/libinput/libei/-/merge_requests/368>
This commit is contained in:
Peter Hutterer 2025-12-10 16:07:41 +10:00 committed by Marge Bot
parent 65c0b39c3e
commit 84c23989e9
3 changed files with 58 additions and 0 deletions

View file

@ -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

View file

@ -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,

View file

@ -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));
}