2016-01-29 20:49:51 +03:00
|
|
|
#include "qemu/osdep.h"
|
2013-11-27 13:35:26 +04:00
|
|
|
#include "sysemu/sysemu.h"
|
2018-02-01 14:18:31 +03:00
|
|
|
#include "qapi/error.h"
|
2018-02-11 12:36:01 +03:00
|
|
|
#include "qapi/qapi-commands-ui.h"
|
2018-02-01 14:18:39 +03:00
|
|
|
#include "qapi/qmp/qdict.h"
|
2015-03-17 20:29:20 +03:00
|
|
|
#include "qemu/error-report.h"
|
2013-12-04 18:20:05 +04:00
|
|
|
#include "trace.h"
|
2013-11-27 13:35:26 +04:00
|
|
|
#include "ui/input.h"
|
2013-12-04 18:20:05 +04:00
|
|
|
#include "ui/console.h"
|
2015-09-17 19:25:24 +03:00
|
|
|
#include "sysemu/replay.h"
|
2019-08-12 08:23:59 +03:00
|
|
|
#include "sysemu/runstate.h"
|
2013-11-27 13:35:26 +04:00
|
|
|
|
|
|
|
struct QemuInputHandlerState {
|
|
|
|
DeviceState *dev;
|
|
|
|
QemuInputHandler *handler;
|
|
|
|
int id;
|
|
|
|
int events;
|
2014-05-19 17:18:37 +04:00
|
|
|
QemuConsole *con;
|
2013-11-27 13:35:26 +04:00
|
|
|
QTAILQ_ENTRY(QemuInputHandlerState) node;
|
|
|
|
};
|
2014-05-28 15:02:40 +04:00
|
|
|
|
|
|
|
typedef struct QemuInputEventQueue QemuInputEventQueue;
|
2018-12-06 13:56:15 +03:00
|
|
|
typedef QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue)
|
|
|
|
QemuInputEventQueueHead;
|
|
|
|
|
2014-05-28 15:02:40 +04:00
|
|
|
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 13:35:26 +04:00
|
|
|
static QTAILQ_HEAD(, QemuInputHandlerState) handlers =
|
|
|
|
QTAILQ_HEAD_INITIALIZER(handlers);
|
2013-12-05 14:23:42 +04:00
|
|
|
static NotifierList mouse_mode_notifiers =
|
|
|
|
NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers);
|
2013-11-27 13:35:26 +04:00
|
|
|
|
2018-12-06 13:56:15 +03:00
|
|
|
static QemuInputEventQueueHead kbd_queue = QTAILQ_HEAD_INITIALIZER(kbd_queue);
|
2014-05-28 15:02:40 +04:00
|
|
|
static QEMUTimer *kbd_timer;
|
|
|
|
static uint32_t kbd_default_delay_ms = 10;
|
2017-04-28 11:42:37 +03:00
|
|
|
static uint32_t queue_count;
|
|
|
|
static uint32_t queue_limit = 1024;
|
2014-05-28 15:02:40 +04:00
|
|
|
|
2013-11-27 13:35:26 +04: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 14:23:42 +04:00
|
|
|
|
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 13:35:26 +04:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_handler_activate(QemuInputHandlerState *s)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&handlers, s, node);
|
|
|
|
QTAILQ_INSERT_HEAD(&handlers, s, node);
|
2013-12-05 14:23:42 +04:00
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 13:35:26 +04:00
|
|
|
}
|
|
|
|
|
2014-03-16 03:38:45 +04: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 13:35:26 +04:00
|
|
|
void qemu_input_handler_unregister(QemuInputHandlerState *s)
|
|
|
|
{
|
|
|
|
QTAILQ_REMOVE(&handlers, s, node);
|
|
|
|
g_free(s);
|
2013-12-05 14:23:42 +04:00
|
|
|
qemu_input_check_mode_change();
|
2013-11-27 13:35:26 +04:00
|
|
|
}
|
|
|
|
|
2014-05-19 17:18:37 +04:00
|
|
|
void qemu_input_handler_bind(QemuInputHandlerState *s,
|
|
|
|
const char *device_id, int head,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
QemuConsole *con;
|
2016-01-12 13:45:43 +03:00
|
|
|
Error *err = NULL;
|
2014-05-19 17:18:37 +04:00
|
|
|
|
2016-01-12 13:45:43 +03:00
|
|
|
con = qemu_console_lookup_by_device_name(device_id, head, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
2014-05-19 17:18:37 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
s->con = con;
|
|
|
|
}
|
|
|
|
|
2013-11-27 13:35:26 +04:00
|
|
|
static QemuInputHandlerState*
|
2014-05-19 17:18:37 +04:00
|
|
|
qemu_input_find_handler(uint32_t mask, QemuConsole *con)
|
2013-11-27 13:35:26 +04:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
2014-05-19 17:18:37 +04: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 13:35:26 +04:00
|
|
|
if (mask & s->handler->mask) {
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-11-04 19:07:09 +03:00
|
|
|
void qmp_input_send_event(const char *device,
|
2016-01-12 14:39:33 +03:00
|
|
|
bool has_head, int64_t head,
|
|
|
|
InputEventList *events, Error **errp)
|
2014-10-01 01:10:17 +04:00
|
|
|
{
|
|
|
|
InputEventList *e;
|
|
|
|
QemuConsole *con;
|
2016-01-12 14:11:14 +03:00
|
|
|
Error *err = NULL;
|
2014-10-01 01:10:17 +04:00
|
|
|
|
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 07:41:25 +03:00
|
|
|
con = NULL;
|
2022-11-04 19:07:09 +03:00
|
|
|
if (device) {
|
2016-01-12 14:11:14 +03:00
|
|
|
if (!has_head) {
|
|
|
|
head = 0;
|
|
|
|
}
|
|
|
|
con = qemu_console_lookup_by_device_name(device, head, &err);
|
|
|
|
if (err) {
|
|
|
|
error_propagate(errp, err);
|
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 07:41:25 +03:00
|
|
|
return;
|
|
|
|
}
|
2014-10-01 01:10:17 +04: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-27 01:34:58 +03:00
|
|
|
if (!qemu_input_find_handler(1 << event->type, con)) {
|
2014-10-01 01:10:17 +04:00
|
|
|
error_setg(errp, "Input handler not found for "
|
|
|
|
"event type %s",
|
2017-08-24 11:46:08 +03:00
|
|
|
InputEventKind_str(event->type));
|
2014-10-01 01:10:17 +04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (e = events; e != NULL; e = e->next) {
|
2017-09-29 13:12:00 +03:00
|
|
|
InputEvent *evt = e->value;
|
|
|
|
|
|
|
|
if (evt->type == INPUT_EVENT_KIND_KEY &&
|
|
|
|
evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER) {
|
|
|
|
KeyValue *key = evt->u.key.data->key;
|
2017-10-19 17:28:42 +03:00
|
|
|
QKeyCode code = qemu_input_key_number_to_qcode(key->u.number.data);
|
2017-09-29 13:12:00 +03:00
|
|
|
qemu_input_event_send_key_qcode(con, code, evt->u.key.data->down);
|
|
|
|
} else {
|
|
|
|
qemu_input_event_send(con, evt);
|
|
|
|
}
|
2014-10-01 01:10:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
qemu_input_event_sync();
|
|
|
|
}
|
|
|
|
|
2017-05-05 16:39:52 +03:00
|
|
|
static int qemu_input_transform_invert_abs_value(int value)
|
|
|
|
{
|
|
|
|
return (int64_t)INPUT_EVENT_ABS_MAX - value + INPUT_EVENT_ABS_MIN;
|
|
|
|
}
|
|
|
|
|
2013-11-28 14:29:33 +04:00
|
|
|
static void qemu_input_transform_abs_rotate(InputEvent *evt)
|
|
|
|
{
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
InputMoveEvent *move = evt->u.abs.data;
|
2013-11-28 14:29:33 +04:00
|
|
|
switch (graphic_rotate) {
|
|
|
|
case 90:
|
2016-03-03 19:16:49 +03:00
|
|
|
if (move->axis == INPUT_AXIS_X) {
|
|
|
|
move->axis = INPUT_AXIS_Y;
|
|
|
|
} else if (move->axis == INPUT_AXIS_Y) {
|
|
|
|
move->axis = INPUT_AXIS_X;
|
2017-05-05 16:39:52 +03:00
|
|
|
move->value = qemu_input_transform_invert_abs_value(move->value);
|
2013-11-28 14:29:33 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 180:
|
2017-05-05 16:39:52 +03:00
|
|
|
move->value = qemu_input_transform_invert_abs_value(move->value);
|
2013-11-28 14:29:33 +04:00
|
|
|
break;
|
|
|
|
case 270:
|
2016-03-03 19:16:49 +03:00
|
|
|
if (move->axis == INPUT_AXIS_X) {
|
|
|
|
move->axis = INPUT_AXIS_Y;
|
2017-05-05 16:39:52 +03:00
|
|
|
move->value = qemu_input_transform_invert_abs_value(move->value);
|
2016-03-03 19:16:49 +03:00
|
|
|
} else if (move->axis == INPUT_AXIS_Y) {
|
|
|
|
move->axis = INPUT_AXIS_X;
|
2013-11-28 14:29:33 +04:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-04 18:20:05 +04:00
|
|
|
static void qemu_input_event_trace(QemuConsole *src, InputEvent *evt)
|
|
|
|
{
|
|
|
|
const char *name;
|
2014-05-21 15:49:59 +04:00
|
|
|
int qcode, idx = -1;
|
2016-03-03 19:16:49 +03:00
|
|
|
InputKeyEvent *key;
|
|
|
|
InputBtnEvent *btn;
|
|
|
|
InputMoveEvent *move;
|
2013-12-04 18:20:05 +04:00
|
|
|
|
|
|
|
if (src) {
|
|
|
|
idx = qemu_console_get_index(src);
|
|
|
|
}
|
2015-10-27 01:34:58 +03:00
|
|
|
switch (evt->type) {
|
2013-12-04 18:20:05 +04:00
|
|
|
case INPUT_EVENT_KIND_KEY:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
key = evt->u.key.data;
|
2016-03-03 19:16:49 +03:00
|
|
|
switch (key->key->type) {
|
2013-12-04 18:20:05 +04:00
|
|
|
case KEY_VALUE_KIND_NUMBER:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
qcode = qemu_input_key_number_to_qcode(key->key->u.number.data);
|
2017-08-24 11:46:08 +03:00
|
|
|
name = QKeyCode_str(qcode);
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
trace_input_event_key_number(idx, key->key->u.number.data,
|
2016-03-03 19:16:49 +03:00
|
|
|
name, key->down);
|
2013-12-04 18:20:05 +04:00
|
|
|
break;
|
|
|
|
case KEY_VALUE_KIND_QCODE:
|
2017-08-24 11:46:08 +03:00
|
|
|
name = QKeyCode_str(key->key->u.qcode.data);
|
2016-03-03 19:16:49 +03:00
|
|
|
trace_input_event_key_qcode(idx, name, key->down);
|
2013-12-04 18:20:05 +04:00
|
|
|
break;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 11:52:57 +03:00
|
|
|
case KEY_VALUE_KIND__MAX:
|
2013-12-04 18:20:05 +04:00
|
|
|
/* keep gcc happy */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_BTN:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
btn = evt->u.btn.data;
|
2017-08-24 11:46:08 +03:00
|
|
|
name = InputButton_str(btn->button);
|
2016-03-03 19:16:49 +03:00
|
|
|
trace_input_event_btn(idx, name, btn->down);
|
2013-12-04 18:20:05 +04:00
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_REL:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
move = evt->u.rel.data;
|
2017-08-24 11:46:08 +03:00
|
|
|
name = InputAxis_str(move->axis);
|
2016-03-03 19:16:49 +03:00
|
|
|
trace_input_event_rel(idx, name, move->value);
|
2013-12-04 18:20:05 +04:00
|
|
|
break;
|
|
|
|
case INPUT_EVENT_KIND_ABS:
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
move = evt->u.abs.data;
|
2017-08-24 11:46:08 +03:00
|
|
|
name = InputAxis_str(move->axis);
|
2016-03-03 19:16:49 +03:00
|
|
|
trace_input_event_abs(idx, name, move->value);
|
2013-12-04 18:20:05 +04:00
|
|
|
break;
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 11:52:57 +03:00
|
|
|
case INPUT_EVENT_KIND__MAX:
|
2013-12-04 18:20:05 +04:00
|
|
|
/* keep gcc happy */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-28 15:02:40 +04:00
|
|
|
static void qemu_input_queue_process(void *opaque)
|
|
|
|
{
|
2018-12-06 13:56:15 +03:00
|
|
|
QemuInputEventQueueHead *queue = opaque;
|
2014-05-28 15:02:40 +04:00
|
|
|
QemuInputEventQueue *item;
|
|
|
|
|
|
|
|
g_assert(!QTAILQ_EMPTY(queue));
|
|
|
|
item = QTAILQ_FIRST(queue);
|
|
|
|
g_assert(item->type == QEMU_INPUT_QUEUE_DELAY);
|
|
|
|
QTAILQ_REMOVE(queue, item, node);
|
2017-06-22 10:41:58 +03:00
|
|
|
queue_count--;
|
2014-05-28 15:02:40 +04:00
|
|
|
g_free(item);
|
|
|
|
|
|
|
|
while (!QTAILQ_EMPTY(queue)) {
|
|
|
|
item = QTAILQ_FIRST(queue);
|
|
|
|
switch (item->type) {
|
|
|
|
case QEMU_INPUT_QUEUE_DELAY:
|
2018-10-17 11:24:18 +03:00
|
|
|
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
2014-05-28 15:02:40 +04:00
|
|
|
+ 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);
|
2017-04-28 11:42:37 +03:00
|
|
|
queue_count--;
|
2014-05-28 15:02:40 +04:00
|
|
|
g_free(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 13:56:15 +03:00
|
|
|
static void qemu_input_queue_delay(QemuInputEventQueueHead *queue,
|
2014-05-28 15:02:40 +04:00
|
|
|
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);
|
2017-04-28 11:42:37 +03:00
|
|
|
queue_count++;
|
2014-05-28 15:02:40 +04:00
|
|
|
|
|
|
|
if (start_timer) {
|
2018-10-17 11:24:18 +03:00
|
|
|
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
|
2014-05-28 15:02:40 +04:00
|
|
|
+ item->delay_ms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-06 13:56:15 +03:00
|
|
|
static void qemu_input_queue_event(QemuInputEventQueueHead *queue,
|
2014-05-28 15:02:40 +04:00
|
|
|
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);
|
2017-04-28 11:42:37 +03:00
|
|
|
queue_count++;
|
2014-05-28 15:02:40 +04:00
|
|
|
}
|
|
|
|
|
2018-12-06 13:56:15 +03:00
|
|
|
static void qemu_input_queue_sync(QemuInputEventQueueHead *queue)
|
2014-05-28 15:02:40 +04:00
|
|
|
{
|
|
|
|
QemuInputEventQueue *item = g_new0(QemuInputEventQueue, 1);
|
|
|
|
|
|
|
|
item->type = QEMU_INPUT_QUEUE_SYNC;
|
|
|
|
QTAILQ_INSERT_TAIL(queue, item, node);
|
2017-04-28 11:42:37 +03:00
|
|
|
queue_count++;
|
2014-05-28 15:02:40 +04:00
|
|
|
}
|
|
|
|
|
2015-09-17 19:25:24 +03:00
|
|
|
void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
|
2013-11-27 13:35:26 +04:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2013-12-04 18:20:05 +04:00
|
|
|
qemu_input_event_trace(src, evt);
|
|
|
|
|
2013-11-28 14:29:33 +04:00
|
|
|
/* pre processing */
|
2015-10-27 01:34:58 +03:00
|
|
|
if (graphic_rotate && (evt->type == INPUT_EVENT_KIND_ABS)) {
|
2013-11-28 14:29:33 +04:00
|
|
|
qemu_input_transform_abs_rotate(evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* send event */
|
2015-10-27 01:34:58 +03:00
|
|
|
s = qemu_input_find_handler(1 << evt->type, src);
|
2014-03-31 18:07:30 +04:00
|
|
|
if (!s) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-27 13:35:26 +04:00
|
|
|
s->handler->event(s->dev, src, evt);
|
|
|
|
s->events++;
|
|
|
|
}
|
|
|
|
|
2015-09-17 19:25:24 +03:00
|
|
|
void qemu_input_event_send(QemuConsole *src, InputEvent *evt)
|
2013-11-27 13:35:26 +04:00
|
|
|
{
|
2017-09-29 13:12:00 +03:00
|
|
|
/* Expect all parts of QEMU to send events with QCodes exclusively.
|
|
|
|
* Key numbers are only supported as end-user input via QMP */
|
|
|
|
assert(!(evt->type == INPUT_EVENT_KIND_KEY &&
|
|
|
|
evt->u.key.data->key->type == KEY_VALUE_KIND_NUMBER));
|
|
|
|
|
2017-10-19 17:28:47 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 'sysrq' was mistakenly added to hack around the fact that
|
|
|
|
* the ps2 driver was not generating correct scancodes sequences
|
|
|
|
* when 'alt+print' was pressed. This flaw is now fixed and the
|
|
|
|
* 'sysrq' key serves no further purpose. We normalize it to
|
|
|
|
* 'print', so that downstream receivers of the event don't
|
2022-06-14 13:40:44 +03:00
|
|
|
* need to deal with this mistake
|
2017-10-19 17:28:47 +03:00
|
|
|
*/
|
|
|
|
if (evt->type == INPUT_EVENT_KIND_KEY &&
|
|
|
|
evt->u.key.data->key->u.qcode.data == Q_KEY_CODE_SYSRQ) {
|
|
|
|
evt->u.key.data->key->u.qcode.data = Q_KEY_CODE_PRINT;
|
|
|
|
}
|
|
|
|
|
2013-11-27 13:35:26 +04:00
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-09-17 19:25:24 +03:00
|
|
|
replay_input_event(src, evt);
|
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_sync_impl(void)
|
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2013-12-04 18:20:05 +04:00
|
|
|
trace_input_event_sync();
|
|
|
|
|
2013-11-27 13:35:26 +04: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 14:38:47 +04:00
|
|
|
|
2015-09-17 19:25:24 +03:00
|
|
|
void qemu_input_event_sync(void)
|
|
|
|
{
|
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
replay_input_sync_event();
|
|
|
|
}
|
|
|
|
|
2017-09-29 13:12:01 +03:00
|
|
|
static InputEvent *qemu_input_event_new_key(KeyValue *key, bool down)
|
2013-11-27 14:38:47 +04:00
|
|
|
{
|
|
|
|
InputEvent *evt = g_new0(InputEvent, 1);
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
evt->u.key.data = g_new0(InputKeyEvent, 1);
|
2015-10-27 01:34:58 +03:00
|
|
|
evt->type = INPUT_EVENT_KIND_KEY;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
evt->u.key.data->key = key;
|
|
|
|
evt->u.key.data->down = down;
|
2013-11-27 14:38:47 +04: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 15:02:40 +04:00
|
|
|
if (QTAILQ_EMPTY(&kbd_queue)) {
|
|
|
|
qemu_input_event_send(src, evt);
|
|
|
|
qemu_input_event_sync();
|
|
|
|
qapi_free_InputEvent(evt);
|
2017-04-28 11:42:37 +03:00
|
|
|
} else if (queue_count < queue_limit) {
|
2014-05-28 15:02:40 +04:00
|
|
|
qemu_input_queue_event(&kbd_queue, src, evt);
|
|
|
|
qemu_input_queue_sync(&kbd_queue);
|
2017-12-25 05:37:30 +03:00
|
|
|
} else {
|
|
|
|
qapi_free_InputEvent(evt);
|
2014-05-28 15:02:40 +04:00
|
|
|
}
|
2013-11-27 14:38:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_send_key_number(QemuConsole *src, int num, bool down)
|
|
|
|
{
|
2017-09-29 13:12:00 +03:00
|
|
|
QKeyCode code = qemu_input_key_number_to_qcode(num);
|
|
|
|
qemu_input_event_send_key_qcode(src, code, down);
|
2013-11-27 14:38:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
|
|
|
|
{
|
|
|
|
KeyValue *key = g_new0(KeyValue, 1);
|
2015-10-27 01:34:58 +03:00
|
|
|
key->type = KEY_VALUE_KIND_QCODE;
|
qapi: Don't special-case simple union wrappers
Simple unions were carrying a special case that hid their 'data'
QMP member from the resulting C struct, via the hack method
QAPISchemaObjectTypeVariant.simple_union_type(). But by using
the work we started by unboxing flat union and alternate
branches, coupled with the ability to visit the members of an
implicit type, we can now expose the simple union's implicit
type in qapi-types.h:
| struct q_obj_ImageInfoSpecificQCow2_wrapper {
| ImageInfoSpecificQCow2 *data;
| };
|
| struct q_obj_ImageInfoSpecificVmdk_wrapper {
| ImageInfoSpecificVmdk *data;
| };
...
| struct ImageInfoSpecific {
| ImageInfoSpecificKind type;
| union { /* union tag is @type */
| void *data;
|- ImageInfoSpecificQCow2 *qcow2;
|- ImageInfoSpecificVmdk *vmdk;
|+ q_obj_ImageInfoSpecificQCow2_wrapper qcow2;
|+ q_obj_ImageInfoSpecificVmdk_wrapper vmdk;
| } u;
| };
Doing this removes asymmetry between QAPI's QMP side and its
C side (both sides now expose 'data'), and means that the
treatment of a simple union as sugar for a flat union is now
equivalent in both languages (previously the two approaches used
a different layer of dereferencing, where the simple union could
be converted to a flat union with equivalent C layout but
different {} on the wire, or to an equivalent QMP wire form
but with different C representation). Using the implicit type
also lets us get rid of the simple_union_type() hack.
Of course, now all clients of simple unions have to adjust from
using su->u.member to using su->u.member.data; while this touches
a number of files in the tree, some earlier cleanup patches
helped minimize the change to the initialization of a temporary
variable rather than every single member access. The generated
qapi-visit.c code is also affected by the layout change:
|@@ -7393,10 +7393,10 @@ void visit_type_ImageInfoSpecific_member
| }
| switch (obj->type) {
| case IMAGE_INFO_SPECIFIC_KIND_QCOW2:
|- visit_type_ImageInfoSpecificQCow2(v, "data", &obj->u.qcow2, &err);
|+ visit_type_q_obj_ImageInfoSpecificQCow2_wrapper_members(v, &obj->u.qcow2, &err);
| break;
| case IMAGE_INFO_SPECIFIC_KIND_VMDK:
|- visit_type_ImageInfoSpecificVmdk(v, "data", &obj->u.vmdk, &err);
|+ visit_type_q_obj_ImageInfoSpecificVmdk_wrapper_members(v, &obj->u.vmdk, &err);
| break;
| default:
| abort();
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1458254921-17042-13-git-send-email-eblake@redhat.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2016-03-18 01:48:37 +03:00
|
|
|
key->u.qcode.data = q;
|
2013-11-27 14:38:47 +04:00
|
|
|
qemu_input_event_send_key(src, key, down);
|
|
|
|
}
|
2013-11-27 21:24:29 +04:00
|
|
|
|
2014-05-28 15:02:40 +04:00
|
|
|
void qemu_input_event_send_key_delay(uint32_t delay_ms)
|
|
|
|
{
|
2017-04-25 16:05:20 +03:00
|
|
|
if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-05-28 15:02:40 +04:00
|
|
|
if (!kbd_timer) {
|
2018-10-17 11:24:20 +03:00
|
|
|
kbd_timer = timer_new_full(NULL, QEMU_CLOCK_VIRTUAL,
|
|
|
|
SCALE_MS, QEMU_TIMER_ATTR_EXTERNAL,
|
|
|
|
qemu_input_queue_process, &kbd_queue);
|
2014-05-28 15:02:40 +04:00
|
|
|
}
|
2017-04-28 11:42:37 +03:00
|
|
|
if (queue_count < queue_limit) {
|
|
|
|
qemu_input_queue_delay(&kbd_queue, kbd_timer,
|
|
|
|
delay_ms ? delay_ms : kbd_default_delay_ms);
|
|
|
|
}
|
2014-05-28 15:02:40 +04:00
|
|
|
}
|
|
|
|
|
2013-11-27 21:24:29 +04:00
|
|
|
void qemu_input_queue_btn(QemuConsole *src, InputButton btn, bool down)
|
|
|
|
{
|
2018-12-10 17:08:08 +03:00
|
|
|
InputBtnEvent bevt = {
|
|
|
|
.button = btn,
|
|
|
|
.down = down,
|
|
|
|
};
|
|
|
|
InputEvent evt = {
|
|
|
|
.type = INPUT_EVENT_KIND_BTN,
|
|
|
|
.u.btn.data = &bevt,
|
|
|
|
};
|
|
|
|
|
|
|
|
qemu_input_event_send(src, &evt);
|
2013-11-27 21:24:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_update_buttons(QemuConsole *src, uint32_t *button_map,
|
|
|
|
uint32_t button_old, uint32_t button_new)
|
|
|
|
{
|
|
|
|
InputButton btn;
|
|
|
|
uint32_t mask;
|
|
|
|
|
qapi: Don't let implicit enum MAX member collide
Now that we guarantee the user doesn't have any enum values
beginning with a single underscore, we can use that for our
own purposes. Renaming ENUM_MAX to ENUM__MAX makes it obvious
that the sentinel is generated.
This patch was mostly generated by applying a temporary patch:
|diff --git a/scripts/qapi.py b/scripts/qapi.py
|index e6d014b..b862ec9 100644
|--- a/scripts/qapi.py
|+++ b/scripts/qapi.py
|@@ -1570,6 +1570,7 @@ const char *const %(c_name)s_lookup[] = {
| max_index = c_enum_const(name, 'MAX', prefix)
| ret += mcgen('''
| [%(max_index)s] = NULL,
|+// %(max_index)s
| };
| ''',
| max_index=max_index)
then running:
$ cat qapi-{types,event}.c tests/test-qapi-types.c |
sed -n 's,^// \(.*\)MAX,s|\1MAX|\1_MAX|g,p' > list
$ git grep -l _MAX | xargs sed -i -f list
The only things not generated are the changes in scripts/qapi.py.
Rejecting enum members named 'MAX' is now useless, and will be dropped
in the next patch.
Signed-off-by: Eric Blake <eblake@redhat.com>
Message-Id: <1447836791-369-23-git-send-email-eblake@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
[Rebased to current master, commit message tweaked]
Signed-off-by: Markus Armbruster <armbru@redhat.com>
2015-11-18 11:52:57 +03:00
|
|
|
for (btn = 0; btn < INPUT_BUTTON__MAX; btn++) {
|
2013-11-27 21:24:29 +04:00
|
|
|
mask = button_map[btn];
|
|
|
|
if ((button_old & mask) == (button_new & mask)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
qemu_input_queue_btn(src, btn, button_new & mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-28 14:31:09 +04:00
|
|
|
bool qemu_input_is_absolute(void)
|
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
|
2014-05-19 17:18:37 +04:00
|
|
|
s = qemu_input_find_handler(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS,
|
|
|
|
NULL);
|
2013-11-28 14:31:09 +04:00
|
|
|
return (s != NULL) && (s->handler->mask & INPUT_EVENT_MASK_ABS);
|
|
|
|
}
|
|
|
|
|
2017-05-05 16:39:52 +03:00
|
|
|
int qemu_input_scale_axis(int value,
|
|
|
|
int min_in, int max_in,
|
|
|
|
int min_out, int max_out)
|
2013-11-27 21:24:29 +04:00
|
|
|
{
|
2017-05-05 16:39:52 +03:00
|
|
|
int64_t range_in = (int64_t)max_in - min_in;
|
|
|
|
int64_t range_out = (int64_t)max_out - min_out;
|
|
|
|
|
|
|
|
if (range_in < 1) {
|
|
|
|
return min_out + range_out / 2;
|
2013-11-27 21:24:29 +04:00
|
|
|
}
|
2017-05-05 16:39:52 +03:00
|
|
|
return ((int64_t)value - min_in) * range_out / range_in + min_out;
|
2013-11-27 21:24:29 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void qemu_input_queue_rel(QemuConsole *src, InputAxis axis, int value)
|
|
|
|
{
|
2018-12-10 17:08:08 +03:00
|
|
|
InputMoveEvent move = {
|
|
|
|
.axis = axis,
|
|
|
|
.value = value,
|
|
|
|
};
|
|
|
|
InputEvent evt = {
|
|
|
|
.type = INPUT_EVENT_KIND_REL,
|
|
|
|
.u.rel.data = &move,
|
|
|
|
};
|
|
|
|
|
|
|
|
qemu_input_event_send(src, &evt);
|
2013-11-27 21:24:29 +04:00
|
|
|
}
|
|
|
|
|
2017-05-05 16:39:52 +03:00
|
|
|
void qemu_input_queue_abs(QemuConsole *src, InputAxis axis, int value,
|
|
|
|
int min_in, int max_in)
|
2013-11-27 21:24:29 +04:00
|
|
|
{
|
2018-12-10 17:08:08 +03:00
|
|
|
InputMoveEvent move = {
|
|
|
|
.axis = axis,
|
|
|
|
.value = qemu_input_scale_axis(value, min_in, max_in,
|
2017-05-05 16:39:52 +03:00
|
|
|
INPUT_EVENT_ABS_MIN,
|
2018-12-10 17:08:08 +03:00
|
|
|
INPUT_EVENT_ABS_MAX),
|
|
|
|
};
|
|
|
|
InputEvent evt = {
|
|
|
|
.type = INPUT_EVENT_KIND_ABS,
|
|
|
|
.u.abs.data = &move,
|
|
|
|
};
|
|
|
|
|
|
|
|
qemu_input_event_send(src, &evt);
|
2013-11-27 21:24:29 +04:00
|
|
|
}
|
2013-12-05 14:23:42 +04: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 14:24:14 +04:00
|
|
|
trace_input_mouse_mode(is_absolute);
|
2013-12-05 14:23:42 +04: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 20:09:36 +04:00
|
|
|
|
|
|
|
MouseInfoList *qmp_query_mice(Error **errp)
|
|
|
|
{
|
|
|
|
MouseInfoList *mice_list = NULL;
|
2020-11-13 04:13:37 +03:00
|
|
|
MouseInfo *info;
|
2013-12-10 20:09:36 +04:00
|
|
|
QemuInputHandlerState *s;
|
|
|
|
bool current = true;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
|
|
|
if (!(s->handler->mask &
|
|
|
|
(INPUT_EVENT_MASK_REL | INPUT_EVENT_MASK_ABS))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-13 04:13:37 +03:00
|
|
|
info = g_new0(MouseInfo, 1);
|
|
|
|
info->index = s->id;
|
|
|
|
info->name = g_strdup(s->handler->name);
|
|
|
|
info->absolute = s->handler->mask & INPUT_EVENT_MASK_ABS;
|
|
|
|
info->current = current;
|
2013-12-10 20:09:36 +04:00
|
|
|
|
|
|
|
current = false;
|
2020-11-13 04:13:37 +03:00
|
|
|
QAPI_LIST_PREPEND(mice_list, info);
|
2013-12-10 20:09:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return mice_list;
|
|
|
|
}
|
2013-12-10 20:16:03 +04: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 15:55:43 +03:00
|
|
|
void hmp_mouse_set(Monitor *mon, const QDict *qdict)
|
2013-12-10 20:16:03 +04:00
|
|
|
{
|
|
|
|
QemuInputHandlerState *s;
|
|
|
|
int index = qdict_get_int(qdict, "index");
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
QTAILQ_FOREACH(s, &handlers, node) {
|
2014-04-01 02:09:06 +04:00
|
|
|
if (s->id != index) {
|
|
|
|
continue;
|
2013-12-10 20:16:03 +04:00
|
|
|
}
|
2014-04-01 02:09:06 +04: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 20:16:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!found) {
|
2014-04-01 02:09:06 +04:00
|
|
|
error_report("Mouse at index '%d' not found", index);
|
2013-12-10 20:16:03 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
qemu_input_check_mode_change();
|
|
|
|
}
|