Merge remote-tracking branch 'remotes/kraxel/tags/pull-input-20141002-1' into staging input monitor patches: fix send-key release ordering and new input-send-event command # gpg: Signature made Thu 02 Oct 2014 09:10:44 BST using RSA key ID D3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" * remotes/kraxel/tags/pull-input-20141002-1: add input-send-event command input: fix send-key monitor command release event ordering Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/qapi-schema.json b/qapi-schema.json index 4bfaf20..2e9e261 100644 --- a/qapi-schema.json +++ b/qapi-schema.json
@@ -3233,6 +3233,23 @@ 'abs' : 'InputMoveEvent' } } ## +# @input-send-event +# +# Send input event(s) to guest. +# +# @console: Which console to send event(s) to. +# +# @events: List of InputEvent union. +# +# Returns: Nothing on success. +# +# Since: 2.2 +# +## +{ 'command': 'input-send-event', + 'data': { 'console':'int', 'events': [ 'InputEvent' ] } } + +## # @NumaOptions # # A discriminated record of NUMA options. (for OptsVisitor)
diff --git a/qmp-commands.hx b/qmp-commands.hx index f581813..1abd619 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx
@@ -3789,3 +3789,66 @@ -> { "execute": "trace-event-set-state", "arguments": { "name": "qemu_memalign", "enable": "true" } } <- { "return": {} } EQMP + + { + .name = "input-send-event", + .args_type = "console:i,events:q", + .mhandler.cmd_new = qmp_marshal_input_input_send_event, + }, + +SQMP +@input-send-event +----------------- + +Send input event to guest. + +Arguments: + +- "console": console index. +- "events": list of input events. + +The consoles are visible in the qom tree, under +/backend/console[$index]. They have a device link and head property, so +it is possible to map which console belongs to which device and display. + +Example (1): + +Press left mouse button. + +-> { "execute": "input-send-event", + "arguments": { "console": 0, + "events": [ { "type": "btn", + "data" : { "down": true, "button": "Left" } } } } +<- { "return": {} } + +-> { "execute": "input-send-event", + "arguments": { "console": 0, + "events": [ { "type": "btn", + "data" : { "down": false, "button": "Left" } } } } +<- { "return": {} } + +Example (2): + +Press ctrl-alt-del. + +-> { "execute": "input-send-event", + "arguments": { "console": 0, "events": [ + { "type": "key", "data" : { "down": true, + "key": {"type": "qcode", "data": "ctrl" } } }, + { "type": "key", "data" : { "down": true, + "key": {"type": "qcode", "data": "alt" } } }, + { "type": "key", "data" : { "down": true, + "key": {"type": "qcode", "data": "delete" } } } ] } } +<- { "return": {} } + +Example (3): + +Move mouse pointer to absolute coordinates (20000, 400). + +-> { "execute": "input-send-event" , + "arguments": { "console": 0, "events": [ + { "type": "abs", "data" : { "axis": "X", "value" : 20000 } }, + { "type": "abs", "data" : { "axis": "Y", "value" : 400 } } ] } } +<- { "return": {} } + +EQMP
diff --git a/ui/input-legacy.c b/ui/input-legacy.c index 3025f50..a698a34 100644 --- a/ui/input-legacy.c +++ b/ui/input-legacy.c
@@ -85,6 +85,8 @@ Error **errp) { KeyValueList *p; + KeyValue **up = NULL; + int count = 0; if (!has_hold_time) { hold_time = 0; /* use default */ @@ -93,11 +95,16 @@ for (p = keys; p != NULL; p = p->next) { qemu_input_event_send_key(NULL, copy_key_value(p->value), true); qemu_input_event_send_key_delay(hold_time); + up = g_realloc(up, sizeof(*up) * (count+1)); + up[count] = copy_key_value(p->value); + count++; } - for (p = keys; p != NULL; p = p->next) { - qemu_input_event_send_key(NULL, copy_key_value(p->value), false); + while (count) { + count--; + qemu_input_event_send_key(NULL, up[count], false); qemu_input_event_send_key_delay(hold_time); } + g_free(up); } static void legacy_kbd_event(DeviceState *dev, QemuConsole *src,
diff --git a/ui/input.c b/ui/input.c index 89d9db7..002831e 100644 --- a/ui/input.c +++ b/ui/input.c
@@ -122,6 +122,43 @@ return NULL; } +void qmp_input_send_event(int64_t console, InputEventList *events, + Error **errp) +{ + InputEventList *e; + QemuConsole *con; + + con = qemu_console_lookup_by_index(console); + if (!con) { + error_setg(errp, "console %" PRId64 " not found", console); + return; + } + + 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; + + if (!qemu_input_find_handler(1 << event->kind, con)) { + error_setg(errp, "Input handler not found for " + "event type %s", + InputEventKind_lookup[event->kind]); + return; + } + } + + for (e = events; e != NULL; e = e->next) { + InputEvent *event = e->value; + + qemu_input_event_send(con, event); + } + + qemu_input_event_sync(); +} + static void qemu_input_transform_abs_rotate(InputEvent *evt) { switch (graphic_rotate) {