ui/input: add LED state tracking to QemuInputHandlerState

Add per-handler LED state and a NotifierList for UI backends to
subscribe to LED changes.

Devices call qemu_input_handler_set_led() to store their LED state and
notify backends. Notify also on focus change, or list update.

Note: I considered conflating mouse-mode & led-state changes, but those
are quite different events (from different source kinds etc) and we may
want to improve the internal implementation.

Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
This commit is contained in:
Marc-André Lureau
2026-06-09 01:05:22 +04:00
parent 91ecca129d
commit 63cdb870aa
2 changed files with 57 additions and 5 deletions

View File

@@ -14,6 +14,7 @@ struct QemuInputHandlerState {
int id;
int events;
QemuConsole *con;
uint32_t leds_mask;
QTAILQ_ENTRY(QemuInputHandlerState) node;
};
@@ -38,6 +39,8 @@ static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
QTAILQ_HEAD_INITIALIZER(handlers);
static NotifierList mouse_mode_notifiers =
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
static NotifierList leds_notifiers =
NOTIFIER_LIST_INITIALIZER(leds_notifiers);
static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
static QEMUTimer *kbd_timer;
@@ -45,6 +48,14 @@ static uint32_t kbd_default_delay_ms = 10;
static uint32_t queue_count;
static uint32_t queue_limit = 1024;
static void notify_input_changed(uint32_t mask)
{
notifier_list_notify(&mouse_mode_notifiers, NULL);
if (mask & INPUT_EVENT_MASK_KEY) {
notifier_list_notify(&leds_notifiers, NULL);
}
}
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
const QemuInputHandler *handler)
{
@@ -55,8 +66,8 @@ QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
s->handler = handler;
s->id = id++;
QTAILQ_INSERT_TAIL(&handlers, s, node);
notify_input_changed(handler->mask);
notifier_list_notify(&mouse_mode_notifiers, NULL);
return s;
}
@@ -64,21 +75,23 @@ void qemu_input_handler_activate(QemuInputHandlerState *s)
{
QTAILQ_REMOVE(&handlers, s, node);
QTAILQ_INSERT_HEAD(&handlers, s, node);
notifier_list_notify(&mouse_mode_notifiers, NULL);
notify_input_changed(s->handler->mask);
}
void qemu_input_handler_deactivate(QemuInputHandlerState *s)
{
QTAILQ_REMOVE(&handlers, s, node);
QTAILQ_INSERT_TAIL(&handlers, s, node);
notifier_list_notify(&mouse_mode_notifiers, NULL);
notify_input_changed(s->handler->mask);
}
void qemu_input_handler_unregister(QemuInputHandlerState *s)
{
uint32_t mask = s->handler->mask;
QTAILQ_REMOVE(&handlers, s, node);
g_free(s);
notifier_list_notify(&mouse_mode_notifiers, NULL);
notify_input_changed(mask);
}
void qemu_input_handler_bind(QemuInputHandlerState *s,
@@ -98,7 +111,7 @@ void qemu_input_handler_bind(QemuInputHandlerState *s,
}
static QemuInputHandlerState*
qemu_input_find_handler(uint32_t mask, QemuConsole *con)
qemu_input_find_handler(uint32_t mask, const QemuConsole *con)
{
QemuInputHandlerState *s;
@@ -122,6 +135,23 @@ qemu_input_find_handler(uint32_t mask, QemuConsole *con)
return NULL;
}
void qemu_input_handler_set_leds_mask(QemuInputHandlerState *s, uint32_t leds_mask)
{
assert(s->handler->mask & INPUT_EVENT_MASK_KEY);
s->leds_mask = leds_mask;
notifier_list_notify(&leds_notifiers, NULL);
}
void qemu_input_led_notifier_add(Notifier *n)
{
notifier_list_add(&leds_notifiers, n);
}
void qemu_input_led_notifier_remove(Notifier *n)
{
notifier_remove(n);
}
void qmp_input_send_event(const char *device,
bool has_head, int64_t head,
InputEventList *events, Error **errp)
@@ -445,6 +475,17 @@ bool qemu_input_is_absolute(QemuConsole *con)
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
}
uint32_t qemu_input_get_leds_mask(const QemuConsole *con)
{
QemuInputHandlerState *s;
s = qemu_input_find_handler(INPUT_EVENT_MASK_KEY, con);
if (s) {
return s->leds_mask;
}
return 0;
}
int qemu_input_scale_axis(int value,
int min_in, int max_in,
int min_out, int max_out)