2014-05-19 15:18:37 +02:00
|
|
|
#include "hw/qdev.h"
|
2013-11-27 10:35:26 +01:00
|
|
|
#include "sysemu/sysemu.h"
|
|
|
|
#include "qapi-types.h"
|
2015-03-17 18:29:20 +01:00
|
|
|
#include "qemu/error-report.h"
|
2013-12-10 17:09:36 +01:00
|
|
|
#include "qmp-commands.h"
|
2013-12-04 15:20:05 +01:00
|
|
|
#include "trace.h"
|
2013-11-27 10:35:26 +01:00
|
|
|
#include "ui/input.h"
|
2013-12-04 15:20:05 +01:00
|
|
|
#include "ui/console.h"
|
2015-09-17 18:25:24 +02:00
|
|
|
#include "sysemu/replay.h"
|
2013-11-27 10:35:26 +01:00
|
|
|
|
|
|
|
struct QemuInputHandlerState {
|
|
|
|
DeviceState *dev;
|
|
|
|
QemuInputHandler *handler;
|
|
|
|
int id;
|
|
|
|
int events;
|
2014-05-19 15:18:37 +02:00
|
|
|
QemuConsole *con;
|
2013-11-27 10:35:26 +01:00
|
|
|
QTAILQ_ENTRY(QemuInputHandlerState) node;
|
|
|
|
};
|
2014-05-28 13:02:40 +02:00
|
|
|
|
|
|
|
typedef struct QemuInputEventQueue QemuInputEventQueue;
|
|
|
|
struct QemuInputEventQueue {
|
|
|
|
enum {
|
|
|
|
QEMU_INPUT_QUEUE_DELAY = 1,
|
|
|
|
QEMU_INPUT_QUEUE_EVENT,
|
|
|
|
QEMU_INPUT_QUEUE_SYNC,
|
|
|
|
} type;
|
|
|
|
QEMUTimer *timer;
|
|
|
|
uint32_t delay_ms;
|
|
|
|
QemuConsole *src;
|
|
|
|
InputEvent *evt;
|
|
|
|
QTAILQ_ENTRY(QemuInputEventQueue) node;
|
|
|
|
};
|
|
|
|
|
2013-11-27 10:35:26 +01:00
|
|
|
static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(handlers);
|
2013-12-05 11:23:42 +01:00
|
|
|
static NotifierList mouse_mode_notifiers =
|
|
|
|
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
|
2013-11-27 10:35:26 +01:00
|
|
|
|
2014-05-28 13:02:40 +02:00
|
|
|
static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(kbd_queue);
|
|
|
|
static QEMUTimer *kbd_timer;
|
|
|
|
static uint32_t kbd_default_delay_ms = 10;
|
|
|
|
|
2013-11-27 10:35:26 +01:00
|
|
|
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
|
|
|
|
QemuInputHandler *handler)
|
|
|
|
{
|
|
|
|
QemuInputHandlerState *s = g_new0(QemuInputHandlerState, 1);
|
|
|
|
static int id = 1;
|
|
|
|
|
|
|
|
s->dev = dev;
|
|
|
|
s->handler = handler;
|
|
|
|
s->id = id++;
|
|
|
|
QTAILQ_INSERT_TAIL(&handlers, s, node);
|
2013-12-05 11:23:42 +01:00
|
|
|
|
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 10:35:26 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_handler_activate(QemuInputHandlerState *s)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&handlers, s, node);
|
|
|
|
QTAILQ_INSERT_HEAD(&handlers, s, node);
|
2013-12-05 11:23:42 +01:00
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 10:35:26 +01:00
|
|
|
}
|
|
|
|
|
2014-03-16 00:38:45 +01:00
|
|
|
void qemu_input_handler_deactivate(QemuInputHandlerState *s)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&handlers, s, node);
|
|
|
|
QTAILQ_INSERT_TAIL(&handlers, s, node);
|
|
|
|
qemu_input_check_mode_change();
|
|
|
|
}
|
|
|
|
|
2013-11-27 10:35:26 +01:00
|
|
|
void qemu_input_handler_unregister(QemuInputHandlerState *s)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&handlers, s, node);
|
|
|
|
g_free(s);
|
2013-12-05 11:23:42 +01:00
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 10:35:26 +01:00
|
|
|
}
|
|
|
|
|
2014-05-19 15:18:37 +02:00
|
|
|
void qemu_input_handler_bind(QemuInputHandlerState *s,
|
|
|
|
const char *device_id, int head,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
DeviceState *dev;
|
|
|
|
QemuConsole *con;
|
|
|
|
|
|
|
|
dev = qdev_find_recursive(sysbus_get_default(), device_id);
|
|
|
|
if (dev == NULL) {
|
2015-03-16 08:57:47 +01:00
|
|
|
error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
|
|
|
|
"Device '%s' not found", device_id);
|
2014-05-19 15:18:37 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
con = qemu_console_lookup_by_device(dev, head);
|
|
|
|
if (con == NULL) {
|
|
|
|
error_setg(errp, "Device %s is not bound to a QemuConsole", device_id);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->con = con;
|
|
|
|
}
|
|
|
|
|
2013-11-27 10:35:26 +01:00
|
|
|
static QemuInputHandlerState*
|
2014-05-19 15:18:37 +02:00
|
|
|
qemu_input_find_handler(uint32_t mask, QemuConsole *con)
|
2013-11-27 10:35:26 +01:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
2014-05-19 15:18:37 +02:00
|
|
|
if (s->con == NULL || s->con != con) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mask & s->handler->mask) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
|
|
|
if (s->con != NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-27 10:35:26 +01:00
|
|
|
if (mask & s->handler->mask) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-11-25 14:54:17 +01:00
|
|
|
void qmp_x_input_send_event(bool has_console, int64_t console,
|
|
|
|
InputEventList *events, Error **errp)
|
2014-09-30 23:10:17 +02:00
|
|
|
{
|
|
|
|
InputEventList *e;
|
|
|
|
QemuConsole *con;
|
|
|
|
|
QMP/input-send-event: make console parameter optional
The 'QemuConsole' is the input source for handler, we share some
input handlers to process the input events from different QemuConsole.
Normally we only have one set of keyboard, mouse, usbtablet, etc.
The devices have different mask, it's fine to just checking mask to
insure that the handler has the ability to process the event.
I saw we try to bind console to handler in usb/dev-hid.c, but display
always isn't available at that time.
If we have multiseat setup (as Gerd said), we only have 'problem' in
this case. Actually event from different devices have the same effect
for system, it's fine to always use the first available handler
without caring about the console.
For send-key command, we just pass a NULL for console parameter in
calling qemu_input_event_send_key(NULL, ..), but 'input-send-event'
needs to care more devices.
Conclusion:
Generally assigning the special console is meanless, and we can't
directly remove the QMP parameter for compatibility.
So we can make the parameter optional. The parameter might be useful
for some special condition: we have multiple devices without binding
console and they all have the ability(mask) to process events, and
we don't want to use the first one.
Cc: Gerd Hoffmann <kraxel@redhat.com>
Cc: Markus Armbruster <armbru@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Amos Kong <akong@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2014-11-07 05:41:25 +01:00
|
|
|
con = NULL;
|
|
|
|
if (has_console) {
|
|
|
|
con = qemu_console_lookup_by_index(console);
|
|
|
|
if (!con) {
|
|
|
|
error_setg(errp, "console %" PRId64 " not found", console);
|
|
|
|
return;
|
|
|
|
}
|
2014-09-30 23:10:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
error_setg(errp, "VM not running");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (e = events; e != NULL; e = e->next) {
|
|
|
|
InputEvent *event = e->value;
|
|
|
|
|
2015-10-26 23:34:58 +01:00
|
|
|
if (!qemu_input_find_handler(1 << event->type, con)) {
|
2014-09-30 23:10:17 +02:00
|
|
|
error_setg(errp, "Input handler not found for "
|
|
|
|
"event type %s",
|
2015-10-26 23:34:58 +01:00
|
|
|
InputEventKind_lookup[event->type]);
|
2014-09-30 23:10:17 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (e = events; e != NULL; e = e->next) {
|
|
|
|
InputEvent *event = e->value;
|
|
|
|
|
|
|
|
qemu_input_event_send(con, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
qemu_input_event_sync();
|
|
|
|
}
|
|
|
|
|
2013-11-28 11:29:33 +01:00
|
|
|
static void qemu_input_transform_abs_rotate(InputEvent *evt)
|
|
|
|
{
|
|
|
|
switch (graphic_rotate) {
|
|
|
|
case 90:
|
2015-10-26 23:34:58 +01:00
|
|
|
if (evt->u.abs->axis == INPUT_AXIS_X) {
|
|
|
|
evt->u.abs->axis = INPUT_AXIS_Y;
|
|
|
|
} else if (evt->u.abs->axis == INPUT_AXIS_Y) {
|
|
|
|
evt->u.abs->axis = INPUT_AXIS_X;
|
|
|
|
evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
|
2013-11-28 11:29:33 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 180:
|
2015-10-26 23:34:58 +01:00
|
|
|
evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
|
2013-11-28 11:29:33 +01:00
|
|
|
break;
|
|
|
|
case 270:
|
2015-10-26 23:34:58 +01:00
|
|
|
if (evt->u.abs->axis == INPUT_AXIS_X) {
|
|
|
|
evt->u.abs->axis = INPUT_AXIS_Y;
|
|
|
|
evt->u.abs->value = INPUT_EVENT_ABS_SIZE - 1 - evt->u.abs->value;
|
|
|
|
} else if (evt->u.abs->axis == INPUT_AXIS_Y) {
|
|
|
|
evt->u.abs->axis = INPUT_AXIS_X;
|
2013-11-28 11:29:33 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-04 15:20:05 +01:00
|
|
|
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
|
|
|
|
{
|
|
|
|
const char *name;
|
2014-05-21 13:49:59 +02:00
|
|
|
int qcode, idx = -1;
|
2013-12-04 15:20:05 +01:00
|
|
|
|
|
|
|
if (src) {
|
|
|
|
idx = qemu_console_get_index(src);
|
|
|
|
}
|
2015-10-26 23:34:58 +01:00
|
|
|
switch (evt->type) {
|
2013-12-04 15:20:05 +01:00
|
|
|
case INPUT_EVENT_KIND_KEY:
|
2015-10-26 23:34:58 +01:00
|
|
|
switch (evt->u.key->key->type) {
|
2013-12-04 15:20:05 +01:00
|
|
|
case KEY_VALUE_KIND_NUMBER:
|
2015-10-26 23:34:58 +01:00
|
|
|
qcode = qemu_input_key_number_to_qcode(evt->u.key->key->u.number);
|
2014-05-21 13:49:59 +02:00
|
|
|
name = QKeyCode_lookup[qcode];
|
2015-10-26 23:34:58 +01:00
|
|
|
trace_input_event_key_number(idx, evt->u.key->key->u.number,
|
|
|
|
name, evt->u.key->down);
|
2013-12-04 15:20:05 +01:00
|
|
|
break;
|
|
|
|
case KEY_VALUE_KIND_QCODE:
|
2015-10-26 23:34:58 +01:00
|
|
|
name = QKeyCode_lookup[evt->u.key->key->u.qcode];
|
|
|
|
trace_input_event_key_qcode(idx, name, evt->u.key->down);
|
2013-12-04 15:20:05 +01:00
|
|
|
break;
|
|
|
|
case KEY_VALUE_KIND_MAX:
|
|
|
|
/* keep gcc happy */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_BTN:
|
2015-10-26 23:34:58 +01:00
|
|
|
name = InputButton_lookup[evt->u.btn->button];
|
|
|
|
trace_input_event_btn(idx, name, evt->u.btn->down);
|
2013-12-04 15:20:05 +01:00
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_REL:
|
2015-10-26 23:34:58 +01:00
|
|
|
name = InputAxis_lookup[evt->u.rel->axis];
|
|
|
|
trace_input_event_rel(idx, name, evt->u.rel->value);
|
2013-12-04 15:20:05 +01:00
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_ABS:
|
2015-10-26 23:34:58 +01:00
|
|
|
name = InputAxis_lookup[evt->u.abs->axis];
|
|
|
|
trace_input_event_abs(idx, name, evt->u.abs->value);
|
2013-12-04 15:20:05 +01:00
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_MAX:
|
|
|
|
/* keep gcc happy */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 13:02:40 +02:00
|
|
|
static void qemu_input_queue_process(void *opaque)
|
|
|
|
{
|
|
|
|
struct QemuInputEventQueueHead *queue = opaque;
|
|
|
|
QemuInputEventQueue *item;
|
|
|
|
|
|
|
|
g_assert(!QTAILQ_EMPTY(queue));
|
|
|
|
item = QTAILQ_FIRST(queue);
|
|
|
|
g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
|
|
|
|
QTAILQ_REMOVE(queue, item, node);
|
|
|
|
g_free(item);
|
|
|
|
|
|
|
|
while (!QTAILQ_EMPTY(queue)) {
|
|
|
|
item = QTAILQ_FIRST(queue);
|
|
|
|
switch (item->type) {
|
|
|
|
case QEMU_INPUT_QUEUE_DELAY:
|
|
|
|
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
|
|
|
+ item->delay_ms);
|
|
|
|
return;
|
|
|
|
case QEMU_INPUT_QUEUE_EVENT:
|
|
|
|
qemu_input_event_send(item->src, item->evt);
|
|
|
|
qapi_free_InputEvent(item->evt);
|
|
|
|
break;
|
|
|
|
case QEMU_INPUT_QUEUE_SYNC:
|
|
|
|
qemu_input_event_sync();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
QTAILQ_REMOVE(queue, item, node);
|
|
|
|
g_free(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
|
|
|
|
QEMUTimer *timer, uint32_t delay_ms)
|
|
|
|
{
|
|
|
|
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
|
|
|
bool start_timer = QTAILQ_EMPTY(queue);
|
|
|
|
|
|
|
|
item->type = QEMU_INPUT_QUEUE_DELAY;
|
|
|
|
item->delay_ms = delay_ms;
|
|
|
|
item->timer = timer;
|
|
|
|
QTAILQ_INSERT_TAIL(queue, item, node);
|
|
|
|
|
|
|
|
if (start_timer) {
|
|
|
|
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
|
|
|
+ item->delay_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
|
|
|
|
QemuConsole *src, InputEvent *evt)
|
|
|
|
{
|
|
|
|
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
|
|
|
|
|
|
|
item->type = QEMU_INPUT_QUEUE_EVENT;
|
|
|
|
item->src = src;
|
|
|
|
item->evt = evt;
|
|
|
|
QTAILQ_INSERT_TAIL(queue, item, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
|
|
|
|
{
|
|
|
|
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
|
|
|
|
|
|
|
item->type = QEMU_INPUT_QUEUE_SYNC;
|
|
|
|
QTAILQ_INSERT_TAIL(queue, item, node);
|
|
|
|
}
|
|
|
|
|
2015-09-17 18:25:24 +02:00
|
|
|
void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
|
2013-11-27 10:35:26 +01:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2013-12-04 15:20:05 +01:00
|
|
|
qemu_input_event_trace(src, evt);
|
|
|
|
|
2013-11-28 11:29:33 +01:00
|
|
|
/* pre processing */
|
2015-10-26 23:34:58 +01:00
|
|
|
if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
|
2013-11-28 11:29:33 +01:00
|
|
|
qemu_input_transform_abs_rotate(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send event */
|
2015-10-26 23:34:58 +01:00
|
|
|
s = qemu_input_find_handler(1 << evt->type, src);
|
2014-03-31 16:07:30 +02:00
|
|
|
if (!s) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-27 10:35:26 +01:00
|
|
|
s->handler->event(s->dev, src, evt);
|
|
|
|
s->events++;
|
|
|
|
}
|
|
|
|
|
2015-09-17 18:25:24 +02:00
|
|
|
void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
|
2013-11-27 10:35:26 +01:00
|
|
|
{
|
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-17 18:25:24 +02:00
|
|
|
replay_input_event(src, evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_sync_impl(void)
|
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2013-12-04 15:20:05 +01:00
|
|
|
trace_input_event_sync();
|
|
|
|
|
2013-11-27 10:35:26 +01:00
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
|
|
|
if (!s->events) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (s->handler->sync) {
|
|
|
|
s->handler->sync(s->dev);
|
|
|
|
}
|
|
|
|
s->events = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-11-27 11:38:47 +01:00
|
|
|
|
2015-09-17 18:25:24 +02:00
|
|
|
void qemu_input_event_sync(void)
|
|
|
|
{
|
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
replay_input_sync_event();
|
|
|
|
}
|
|
|
|
|
2013-11-27 11:38:47 +01:00
|
|
|
InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
|
|
|
|
{
|
|
|
|
InputEvent *evt = g_new0(InputEvent, 1);
|
2015-10-26 23:34:58 +01:00
|
|
|
evt->u.key = g_new0(InputKeyEvent, 1);
|
|
|
|
evt->type = INPUT_EVENT_KIND_KEY;
|
|
|
|
evt->u.key->key = key;
|
|
|
|
evt->u.key->down = down;
|
2013-11-27 11:38:47 +01:00
|
|
|
return evt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
|
|
|
|
{
|
|
|
|
InputEvent *evt;
|
|
|
|
evt = qemu_input_event_new_key(key, down);
|
2014-05-28 13:02:40 +02:00
|
|
|
if (QTAILQ_EMPTY(&kbd_queue)) {
|
|
|
|
qemu_input_event_send(src, evt);
|
|
|
|
qemu_input_event_sync();
|
|
|
|
qapi_free_InputEvent(evt);
|
|
|
|
} else {
|
|
|
|
qemu_input_queue_event(&kbd_queue, src, evt);
|
|
|
|
qemu_input_queue_sync(&kbd_queue);
|
|
|
|
}
|
2013-11-27 11:38:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
|
|
|
|
{
|
|
|
|
KeyValue *key = g_new0(KeyValue, 1);
|
2015-10-26 23:34:58 +01:00
|
|
|
key->type = KEY_VALUE_KIND_NUMBER;
|
|
|
|
key->u.number = num;
|
2013-11-27 11:38:47 +01:00
|
|
|
qemu_input_event_send_key(src, key, down);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
|
|
|
|
{
|
|
|
|
KeyValue *key = g_new0(KeyValue, 1);
|
2015-10-26 23:34:58 +01:00
|
|
|
key->type = KEY_VALUE_KIND_QCODE;
|
|
|
|
key->u.qcode = q;
|
2013-11-27 11:38:47 +01:00
|
|
|
qemu_input_event_send_key(src, key, down);
|
|
|
|
}
|
2013-11-27 18:24:29 +01:00
|
|
|
|
2014-05-28 13:02:40 +02:00
|
|
|
void qemu_input_event_send_key_delay(uint32_t delay_ms)
|
|
|
|
{
|
|
|
|
if (!kbd_timer) {
|
|
|
|
kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
|
|
|
|
&kbd_queue);
|
|
|
|
}
|
|
|
|
qemu_input_queue_delay(&kbd_queue, kbd_timer,
|
|
|
|
delay_ms ? delay_ms : kbd_default_delay_ms);
|
|
|
|
}
|
|
|
|
|
2013-11-27 18:24:29 +01:00
|
|
|
InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
|
|
|
|
{
|
|
|
|
InputEvent *evt = g_new0(InputEvent, 1);
|
2015-10-26 23:34:58 +01:00
|
|
|
evt->u.btn = g_new0(InputBtnEvent, 1);
|
|
|
|
evt->type = INPUT_EVENT_KIND_BTN;
|
|
|
|
evt->u.btn->button = btn;
|
|
|
|
evt->u.btn->down = down;
|
2013-11-27 18:24:29 +01:00
|
|
|
return evt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
|
|
|
|
{
|
|
|
|
InputEvent *evt;
|
|
|
|
evt = qemu_input_event_new_btn(btn, down);
|
|
|
|
qemu_input_event_send(src, evt);
|
|
|
|
qapi_free_InputEvent(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
|
|
|
|
uint32_t button_old, uint32_t button_new)
|
|
|
|
{
|
|
|
|
InputButton btn;
|
|
|
|
uint32_t mask;
|
|
|
|
|
|
|
|
for (btn = 0; btn < INPUT_BUTTON_MAX; btn++) {
|
|
|
|
mask = button_map[btn];
|
|
|
|
if ((button_old & mask) == (button_new & mask)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
qemu_input_queue_btn(src, btn, button_new & mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 11:31:09 +01:00
|
|
|
bool qemu_input_is_absolute(void)
|
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2014-05-19 15:18:37 +02:00
|
|
|
s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
|
|
|
|
NULL);
|
2013-11-28 11:31:09 +01:00
|
|
|
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
|
|
|
|
}
|
|
|
|
|
2013-11-27 18:24:29 +01:00
|
|
|
int qemu_input_scale_axis(int value, int size_in, int size_out)
|
|
|
|
{
|
|
|
|
if (size_in < 2) {
|
|
|
|
return size_out / 2;
|
|
|
|
}
|
|
|
|
return (int64_t)value * (size_out - 1) / (size_in - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
InputEvent *qemu_input_event_new_move(InputEventKind kind,
|
|
|
|
InputAxis axis, int value)
|
|
|
|
{
|
|
|
|
InputEvent *evt = g_new0(InputEvent, 1);
|
|
|
|
InputMoveEvent *move = g_new0(InputMoveEvent, 1);
|
|
|
|
|
2015-10-26 23:34:58 +01:00
|
|
|
evt->type = kind;
|
|
|
|
evt->u.data = move;
|
2013-11-27 18:24:29 +01:00
|
|
|
move->axis = axis;
|
|
|
|
move->value = value;
|
|
|
|
return evt;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
|
|
|
|
{
|
|
|
|
InputEvent *evt;
|
|
|
|
evt = qemu_input_event_new_move(INPUT_EVENT_KIND_REL, axis, value);
|
|
|
|
qemu_input_event_send(src, evt);
|
|
|
|
qapi_free_InputEvent(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value, int size)
|
|
|
|
{
|
|
|
|
InputEvent *evt;
|
|
|
|
int scaled = qemu_input_scale_axis(value, size, INPUT_EVENT_ABS_SIZE);
|
|
|
|
evt = qemu_input_event_new_move(INPUT_EVENT_KIND_ABS, axis, scaled);
|
|
|
|
qemu_input_event_send(src, evt);
|
|
|
|
qapi_free_InputEvent(evt);
|
|
|
|
}
|
2013-12-05 11:23:42 +01:00
|
|
|
|
|
|
|
void qemu_input_check_mode_change(void)
|
|
|
|
{
|
|
|
|
static int current_is_absolute;
|
|
|
|
int is_absolute;
|
|
|
|
|
|
|
|
is_absolute = qemu_input_is_absolute();
|
|
|
|
|
|
|
|
if (is_absolute != current_is_absolute) {
|
2013-12-05 11:24:14 +01:00
|
|
|
trace_input_mouse_mode(is_absolute);
|
2013-12-05 11:23:42 +01:00
|
|
|
notifier_list_notify(&mouse_mode_notifiers, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
current_is_absolute = is_absolute;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_add_mouse_mode_change_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_list_add(&mouse_mode_notifiers, notify);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_remove_mouse_mode_change_notifier(Notifier *notify)
|
|
|
|
{
|
|
|
|
notifier_remove(notify);
|
|
|
|
}
|
2013-12-10 17:09:36 +01:00
|
|
|
|
|
|
|
MouseInfoList *qmp_query_mice(Error **errp)
|
|
|
|
{
|
|
|
|
MouseInfoList *mice_list = NULL;
|
|
|
|
MouseInfoList *info;
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
bool current = true;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
|
|
|
if (!(s->handler->mask &
|
|
|
|
(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
info = g_new0(MouseInfoList, 1);
|
|
|
|
info->value = g_new0(MouseInfo, 1);
|
|
|
|
info->value->index = s->id;
|
|
|
|
info->value->name = g_strdup(s->handler->name);
|
|
|
|
info->value->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
|
|
|
|
info->value->current = current;
|
|
|
|
|
|
|
|
current = false;
|
|
|
|
info->next = mice_list;
|
|
|
|
mice_list = info;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mice_list;
|
|
|
|
}
|
2013-12-10 17:16:03 +01:00
|
|
|
|
hmp: Name HMP command handler functions hmp_COMMAND()
Some are called do_COMMAND() (old ones, usually), some hmp_COMMAND(),
and sometimes COMMAND pointlessly differs in spelling.
Normalize to hmp_COMMAND(), where COMMAND is exactly the command name
with '-' replaced by '_'.
Exceptions:
* do_device_add() and client_migrate_info() *not* renamed to
hmp_device_add(), hmp_client_migrate_info(), because they're also
QMP handlers. They still need to be converted to QAPI.
* do_memory_dump(), do_physical_memory_dump(), do_ioport_read(),
do_ioport_write() renamed do hmp_* instead of hmp_x(), hmp_xp(),
hmp_i(), hmp_o(), because those names are too cryptic for my taste.
* do_info_help() renamed to hmp_info_help() instead of hmp_info(),
because it only covers help.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-02-06 13:55:43 +01:00
|
|
|
void hmp_mouse_set(Monitor *mon, const QDict *qdict)
|
2013-12-10 17:16:03 +01:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
int index = qdict_get_int(qdict, "index");
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
2014-04-01 00:09:06 +02:00
|
|
|
if (s->id != index) {
|
|
|
|
continue;
|
2013-12-10 17:16:03 +01:00
|
|
|
}
|
2014-04-01 00:09:06 +02:00
|
|
|
if (!(s->handler->mask & (INPUT_EVENT_MASK_REL |
|
|
|
|
INPUT_EVENT_MASK_ABS))) {
|
|
|
|
error_report("Input device '%s' is not a mouse", s->handler->name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
found = 1;
|
|
|
|
qemu_input_handler_activate(s);
|
|
|
|
break;
|
2013-12-10 17:16:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
2014-04-01 00:09:06 +02:00
|
|
|
error_report("Mouse at index '%d' not found", index);
|
2013-12-10 17:16:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
qemu_input_check_mode_change();
|
|
|
|
}
|