Patchwork [V2] qemu, qmp: add keydown and keyup command for qmp

login
register
mail settings
Submitter Lai Jiangshan
Date March 9, 2011, 8:24 a.m.
Message ID <4D773943.60803@cn.fujitsu.com>
Download mbox | patch
Permalink /patch/86071/
State New
Headers show

Comments

Lai Jiangshan - March 9, 2011, 8:24 a.m.
sendkey is a very good command for human using it in their monitor,
but it is not a good idea to port it to qmp, because qmp is a machine
protocol. So we introduce keydown and keyup command for qmp, they
simulate the events that keyboard send to the system.

Example, simulates ctrl+alt+f1:
{ "execute": "keydown", "arguments": { "keycode": 29 } }  #press down ctrl
{ "execute": "keydown", "arguments": { "keycode": 56 } }  #press down alt
{ "execute": "keydown", "arguments": { "keycode": 59 } }  #press down f1
{ "execute": "keyup", "arguments": { "keycode": 59 } }    #release f1
{ "execute": "keyup", "arguments": { "keycode": 56 } }    #release alt
{ "execute": "keyup", "arguments": { "keycode": 29 } }    #release ctrl

Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com>
---
Anthony Liguori - March 9, 2011, 1:11 p.m.
On 03/09/2011 02:24 AM, Lai Jiangshan wrote:
> sendkey is a very good command for human using it in their monitor,
> but it is not a good idea to port it to qmp, because qmp is a machine
> protocol. So we introduce keydown and keyup command for qmp, they
> simulate the events that keyboard send to the system.
>
> Example, simulates ctrl+alt+f1:
> { "execute": "keydown", "arguments": { "keycode": 29 } }  #press down ctrl
> { "execute": "keydown", "arguments": { "keycode": 56 } }  #press down alt
> { "execute": "keydown", "arguments": { "keycode": 59 } }  #press down f1
> { "execute": "keyup", "arguments": { "keycode": 59 } }    #release f1
> { "execute": "keyup", "arguments": { "keycode": 56 } }    #release alt
> { "execute": "keyup", "arguments": { "keycode": 29 } }    #release ctrl
>
> Signed-off-by: Lai Jiangshan<laijs@cn.fujitsu.com>


> ---
> diff --git a/monitor.c b/monitor.c
> index 22ae3bb..725df83 100644
> --- a/monitor.c
> +++ b/monitor.c
> @@ -1810,16 +1810,25 @@ static uint8_t keycodes[MAX_KEYCODES];
>   static int nb_pending_keycodes;
>   static QEMUTimer *key_timer;
>
> -static void release_keys(void *opaque)
> +static void keydown(uint8_t keycode)
>   {
> -    int keycode;
> +    if (keycode&  0x80)
> +        kbd_put_keycode(0xe0);
> +    kbd_put_keycode(keycode&  0x7f);
> +}
>
> +static void keyup(uint8_t keycode)
> +{
> +    if (keycode&  0x80)
> +        kbd_put_keycode(0xe0);
> +    kbd_put_keycode(keycode | 0x80);
> +}
> +
> +static void release_keys(void *opaque)
> +{
>       while (nb_pending_keycodes>  0) {
>           nb_pending_keycodes--;
> -        keycode = keycodes[nb_pending_keycodes];
> -        if (keycode&  0x80)
> -            kbd_put_keycode(0xe0);
> -        kbd_put_keycode(keycode | 0x80);
> +        keyup(keycodes[nb_pending_keycodes]);
>       }
>   }
>
> @@ -1866,17 +1875,41 @@ static void do_sendkey(Monitor *mon, const QDict *qdict)
>       }
>       nb_pending_keycodes = i;
>       /* key down events */
> -    for (i = 0; i<  nb_pending_keycodes; i++) {
> -        keycode = keycodes[i];
> -        if (keycode&  0x80)
> -            kbd_put_keycode(0xe0);
> -        kbd_put_keycode(keycode&  0x7f);
> -    }
> +    for (i = 0; i<  nb_pending_keycodes; i++)
> +        keydown(keycodes[i]);
>       /* delayed key up events */
>       qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) +
>                      muldiv64(get_ticks_per_sec(), hold_time, 1000));
>   }
>
> +static int qmp_keyaction(const QDict *qdict, int down)
> +{
> +    int keycode = qdict_get_int(qdict, "keycode");
> +
> +    if (keycode<  0 || keycode>= 256) {
> +        qerror_report(QERR_INVALID_PARAMETER_VALUE, "keycode",
> +                      "a valid keycode");
> +        return -1;
> +    }
> +
> +    if (down)
> +        keydown(keycode);
> +    else
> +        keyup(keycode);
> +
> +    return 0;
> +}
> +
> +static int qmp_keydown(Monitor *mon, const QDict *qdict, QObject **ret_data)
> +{
> +    return qmp_keyaction(qdict, 1);
> +}
> +
> +static int qmp_keyup(Monitor *mon, const QDict *qdict, QObject **ret_data)
> +{
> +    return qmp_keyaction(qdict, 0);
> +}
> +
>   static int mouse_button_state;
>
>   static void do_mouse_move(Monitor *mon, const QDict *qdict)
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index df40a3d..4c449bb 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -338,6 +338,58 @@ Example:
>   EQMP
>
>       {
> +        .name       = "keydown",
> +        .args_type  = "keycode:i",
> +        .params     = "keycode",
> +        .help       = "press down a key",
> +        .user_print = monitor_user_noop,
> +        .mhandler.cmd_new = qmp_keydown,
> +    },
> +
> +SQMP
> +keydown
> +---
> +
> +Press down a key.
> +
> +Arguments:
> +
> +- "keycode": the code of the key to press down (json-int)
> +
> +Example:
> +
> +->  { "execute": "keydown", "arguments": { "keycode": 16 } }
> +<- { "return": {} }
> +
> +EQMP
> +
> +    {
> +        .name       = "keyup",
> +        .args_type  = "keycode:i",
> +        .params     = "keycode",
> +        .help       = "release a key",
> +        .user_print = monitor_user_noop,
> +        .mhandler.cmd_new = qmp_keyup,
> +    },
> +
> +SQMP
> +keyup
> +---
> +
> +Release a key.
> +
> +Arguments:
> +
> +- "keycode": the code of the key to release (json-int)

What is the value of "keycode" and what happens if you pass an invalid 
keycode?

This interface uses QEMU-style compressed XT scan codes.  I'd suggest 
making the interface take two optional arguments one being the an 
integer keycode and then another being a symbolic name where the 
symbolic name used the current keymap to translate the keycode.

For the XT scan code, I wouldn't use the one-byte encoding.  I'd use a 
32-bit encoding.

Regards,

Anthony Liguori

> +Example:
> +
> +->  { "execute": "keyup", "arguments": { "keycode": 16 } }
> +<- { "return": {} }
> +
> +EQMP
> +
> +    {
>           .name       = "cpu",
>           .args_type  = "index:i",
>           .params     = "index",
>

Patch

diff --git a/monitor.c b/monitor.c
index 22ae3bb..725df83 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1810,16 +1810,25 @@  static uint8_t keycodes[MAX_KEYCODES];
 static int nb_pending_keycodes;
 static QEMUTimer *key_timer;
 
-static void release_keys(void *opaque)
+static void keydown(uint8_t keycode)
 {
-    int keycode;
+    if (keycode & 0x80)
+        kbd_put_keycode(0xe0);
+    kbd_put_keycode(keycode & 0x7f);
+}
 
+static void keyup(uint8_t keycode)
+{
+    if (keycode & 0x80)
+        kbd_put_keycode(0xe0);
+    kbd_put_keycode(keycode | 0x80);
+}
+
+static void release_keys(void *opaque)
+{
     while (nb_pending_keycodes > 0) {
         nb_pending_keycodes--;
-        keycode = keycodes[nb_pending_keycodes];
-        if (keycode & 0x80)
-            kbd_put_keycode(0xe0);
-        kbd_put_keycode(keycode | 0x80);
+        keyup(keycodes[nb_pending_keycodes]);
     }
 }
 
@@ -1866,17 +1875,41 @@  static void do_sendkey(Monitor *mon, const QDict *qdict)
     }
     nb_pending_keycodes = i;
     /* key down events */
-    for (i = 0; i < nb_pending_keycodes; i++) {
-        keycode = keycodes[i];
-        if (keycode & 0x80)
-            kbd_put_keycode(0xe0);
-        kbd_put_keycode(keycode & 0x7f);
-    }
+    for (i = 0; i < nb_pending_keycodes; i++)
+        keydown(keycodes[i]);
     /* delayed key up events */
     qemu_mod_timer(key_timer, qemu_get_clock(vm_clock) +
                    muldiv64(get_ticks_per_sec(), hold_time, 1000));
 }
 
+static int qmp_keyaction(const QDict *qdict, int down)
+{
+    int keycode = qdict_get_int(qdict, "keycode");
+
+    if (keycode < 0 || keycode >= 256) {
+        qerror_report(QERR_INVALID_PARAMETER_VALUE, "keycode",
+                      "a valid keycode");
+        return -1;
+    }
+
+    if (down)
+        keydown(keycode);
+    else
+        keyup(keycode);
+
+    return 0;
+}
+
+static int qmp_keydown(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    return qmp_keyaction(qdict, 1);
+}
+
+static int qmp_keyup(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    return qmp_keyaction(qdict, 0);
+}
+
 static int mouse_button_state;
 
 static void do_mouse_move(Monitor *mon, const QDict *qdict)
diff --git a/qmp-commands.hx b/qmp-commands.hx
index df40a3d..4c449bb 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -338,6 +338,58 @@  Example:
 EQMP
 
     {
+        .name       = "keydown",
+        .args_type  = "keycode:i",
+        .params     = "keycode",
+        .help       = "press down a key",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = qmp_keydown,
+    },
+
+SQMP
+keydown
+---
+
+Press down a key.
+
+Arguments:
+
+- "keycode": the code of the key to press down (json-int)
+
+Example:
+
+-> { "execute": "keydown", "arguments": { "keycode": 16 } }
+<- { "return": {} }
+
+EQMP
+
+    {
+        .name       = "keyup",
+        .args_type  = "keycode:i",
+        .params     = "keycode",
+        .help       = "release a key",
+        .user_print = monitor_user_noop,
+        .mhandler.cmd_new = qmp_keyup,
+    },
+
+SQMP
+keyup
+---
+
+Release a key.
+
+Arguments:
+
+- "keycode": the code of the key to release (json-int)
+
+Example:
+
+-> { "execute": "keyup", "arguments": { "keycode": 16 } }
+<- { "return": {} }
+
+EQMP
+
+    {
         .name       = "cpu",
         .args_type  = "index:i",
         .params     = "index",