* [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi @ 2012-07-26 4:48 Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 1/6] fix doc of using raw values with sendkey Amos Kong ` (5 more replies) 0 siblings, 6 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:48 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino This series converted 'sendkey' command to qapi. The raw value in hexadecimal format is not supported by 'send-key' of qmp. Amos Kong (6): fix doc of using raw values with sendkey monitor: rename keyname '<' to 'less' hmp: rename arguments qapi: generate list struct and visit_list for enum ps2: output warning when event queue full qapi: convert sendkey console.h | 5 + hmp-commands.hx | 10 +- hmp.c | 55 +++++++++++ hmp.h | 1 + hw/ps2.c | 4 +- input.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 251 ++----------------------------------------------- qapi-schema.json | 46 +++++++++ qmp-commands.hx | 28 ++++++ scripts/qapi-types.py | 16 +++- scripts/qapi-visit.py | 14 +++- 11 files changed, 428 insertions(+), 251 deletions(-) --- Changes from v1: - using a JSON array for the key names - rename new error to 'QERR_OVERFLOW' - fix command descriptions - qapi: generate list struct for enum - add '<' fixing Changes from v2: - fix support of raw value in hexadecimal format - fix bug in processing of '<-x' - don't generate useless cleanup functions for enum - introduced two functions for enum in qapi scripts - fix command description - drop keys number limitation in sendkey - drop patch: qerror: add QERR_OVERFLOW Changes from v3: - move key_defs[] to console.h - link mapping tables by enum values - rename 'sendkey' to 'send-key' for qmp Changes from v4: - rename 'KeyCodes' to 'QKeyCode' - fix default hold-time - move qmp_send_key(), key_defs to input.c - duplicate the keylist in qmp_send_key() - drop struct KeyDef - handle invalid key/index in hmp_send_key() ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 1/6] fix doc of using raw values with sendkey 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong @ 2012-07-26 4:48 ` Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 2/6] monitor: rename keyname '<' to 'less' Amos Kong ` (4 subsequent siblings) 5 siblings, 0 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:48 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino (qemu) sendkey a (qemu) sendkey 0x1e (qemu) sendkey #0x1e unknown key: '#0x1e' The last command doesn't work, '#' is not requested before raw values. And the raw value in decimal format is also not supported. Signed-off-by: Amos Kong <akong@redhat.com> --- hmp-commands.hx | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index eea8b32..4041a9b 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -512,9 +512,9 @@ STEXI @item sendkey @var{keys} @findex sendkey -Send @var{keys} to the emulator. @var{keys} could be the name of the -key or @code{#} followed by the raw value in either decimal or hexadecimal -format. Use @code{-} to press several keys simultaneously. Example: +Send @var{keys} to the guest. @var{keys} could be the name of the +key or the raw value in hexadecimal format. Use @code{-} to press +several keys simultaneously. Example: @example sendkey ctrl-alt-f1 @end example -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 2/6] monitor: rename keyname '<' to 'less' 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 1/6] fix doc of using raw values with sendkey Amos Kong @ 2012-07-26 4:48 ` Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 3/6] hmp: rename arguments Amos Kong ` (3 subsequent siblings) 5 siblings, 0 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:48 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino There are many maps of keycode 0x56 in pc-bios/keymaps/* pc-bios/keymaps/common:less 0x56 pc-bios/keymaps/common:greater 0x56 shift pc-bios/keymaps/common:bar 0x56 altgr pc-bios/keymaps/common:brokenbar 0x56 shift altgr This patch just renames '<' to 'less', QAPI would add new variable by adding a prefix to keyname, '$PREFIX_<' is not available, '$PREFIX_less' is ok. For compatibility, convert user inputted '<' to 'less'. Signed-off-by: Amos Kong <akong@redhat.com> --- monitor.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-) diff --git a/monitor.c b/monitor.c index 49dccfe..ffec616 100644 --- a/monitor.c +++ b/monitor.c @@ -1403,7 +1403,7 @@ static const KeyDef key_defs[] = { { 0x48, "kp_8" }, { 0x49, "kp_9" }, - { 0x56, "<" }, + { 0x56, "less" }, { 0x57, "f11" }, { 0x58, "f12" }, @@ -1507,6 +1507,13 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) monitor_printf(mon, "too many keys\n"); return; } + + /* Be compatible with old interface, convert user inputted "<" */ + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); + keyname_len = 4; + } + keyname_buf[keyname_len] = 0; keycode = get_keycode(keyname_buf); if (keycode < 0) { -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 3/6] hmp: rename arguments 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 1/6] fix doc of using raw values with sendkey Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 2/6] monitor: rename keyname '<' to 'less' Amos Kong @ 2012-07-26 4:48 ` Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 4/6] qapi: generate list struct and visit_list for enum Amos Kong ` (2 subsequent siblings) 5 siblings, 0 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:48 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino Rename 'string' to 'keys', rename 'hold_time' to 'hold-time'. Signed-off-by: Amos Kong <akong@redhat.com> --- hmp-commands.hx | 2 +- monitor.c | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/hmp-commands.hx b/hmp-commands.hx index 4041a9b..2891d48 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -502,7 +502,7 @@ ETEXI { .name = "sendkey", - .args_type = "string:s,hold_time:i?", + .args_type = "keys:s,hold-time:i?", .params = "keys [hold_ms]", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", .mhandler.cmd = do_sendkey, diff --git a/monitor.c b/monitor.c index ffec616..4db0c1e 100644 --- a/monitor.c +++ b/monitor.c @@ -1483,9 +1483,9 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) char keyname_buf[16]; char *separator; int keyname_len, keycode, i; - const char *string = qdict_get_str(qdict, "string"); - int has_hold_time = qdict_haskey(qdict, "hold_time"); - int hold_time = qdict_get_try_int(qdict, "hold_time", -1); + const char *keys = qdict_get_str(qdict, "keys"); + int has_hold_time = qdict_haskey(qdict, "hold-time"); + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); if (nb_pending_keycodes > 0) { qemu_del_timer(key_timer); @@ -1495,10 +1495,10 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) hold_time = 100; i = 0; while (1) { - separator = strchr(string, '-'); - keyname_len = separator ? separator - string : strlen(string); + separator = strchr(keys, '-'); + keyname_len = separator ? separator - keys : strlen(keys); if (keyname_len > 0) { - pstrcpy(keyname_buf, sizeof(keyname_buf), string); + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); if (keyname_len > sizeof(keyname_buf) - 1) { monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); return; @@ -1524,7 +1524,7 @@ static void do_sendkey(Monitor *mon, const QDict *qdict) } if (!separator) break; - string = separator + 1; + keys = separator + 1; } nb_pending_keycodes = i; /* key down events */ -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 4/6] qapi: generate list struct and visit_list for enum 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong ` (2 preceding siblings ...) 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 3/6] hmp: rename arguments Amos Kong @ 2012-07-26 4:48 ` Amos Kong 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full Amos Kong 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey Amos Kong 5 siblings, 0 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:48 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino Currently, if define an 'enum' and use it in one command's data, List struct for enum could not be generated, but it's used in qmp function. For example: KeyCodesList could not be generated. >>> qapi-schema.json: { 'enum': 'KeyCodes', 'data': [ 'shift', 'alt' ... ] } { 'command': 'sendkey', 'data': { 'keys': ['KeyCodes'], '*hold-time': 'int' } } >>> qmp-command.h: void qmp_sendkey(KeyCodesList * keys, bool has_hold_time, int64_t hold_time, Error **errp); This patch lets qapi generate List struct for enum. Signed-off-by: Amos Kong <akong@redhat.com> --- scripts/qapi-types.py | 16 +++++++++++++++- scripts/qapi-visit.py | 14 +++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/scripts/qapi-types.py b/scripts/qapi-types.py index 4a734f5..648eac7 100644 --- a/scripts/qapi-types.py +++ b/scripts/qapi-types.py @@ -28,6 +28,16 @@ typedef struct %(name)sList ''', name=name) +def generate_fwd_enum_struct(name, members): + return mcgen(''' +typedef struct %(name)sList +{ + %(name)s value; + struct %(name)sList *next; +} %(name)sList; +''', + name=name) + def generate_struct(structname, fieldname, members): ret = mcgen(''' struct %(name)s @@ -265,7 +275,8 @@ for expr in exprs: if expr.has_key('type'): ret += generate_fwd_struct(expr['type'], expr['data']) elif expr.has_key('enum'): - ret += generate_enum(expr['enum'], expr['data']) + ret += generate_enum(expr['enum'], expr['data']) + "\n" + ret += generate_fwd_enum_struct(expr['enum'], expr['data']) fdef.write(generate_enum_lookup(expr['enum'], expr['data'])) elif expr.has_key('union'): ret += generate_fwd_struct(expr['union'], expr['data']) + "\n" @@ -289,6 +300,9 @@ for expr in exprs: fdef.write(generate_type_cleanup(expr['union'] + "List") + "\n") ret += generate_type_cleanup_decl(expr['union']) fdef.write(generate_type_cleanup(expr['union']) + "\n") + elif expr.has_key('enum'): + ret += generate_type_cleanup_decl(expr['enum'] + "List") + fdef.write(generate_type_cleanup(expr['enum'] + "List") + "\n") else: continue fdecl.write(ret) diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py index 04ef7c4..cbec24d 100644 --- a/scripts/qapi-visit.py +++ b/scripts/qapi-visit.py @@ -217,6 +217,16 @@ void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, return ret +def generate_enum_declaration(name, members, genlist=True): + ret = "" + if genlist: + ret += mcgen(''' +void visit_type_%(name)sList(Visitor *m, %(name)sList ** obj, const char *name, Error **errp); +''', + name=name) + + return ret + def generate_decl_enum(name, members, genlist=True): return mcgen(''' @@ -335,10 +345,12 @@ for expr in exprs: ret += generate_declaration(expr['union'], expr['data']) fdecl.write(ret) elif expr.has_key('enum'): - ret = generate_visit_enum(expr['enum'], expr['data']) + ret = generate_visit_list(expr['enum'], expr['data']) + ret += generate_visit_enum(expr['enum'], expr['data']) fdef.write(ret) ret = generate_decl_enum(expr['enum'], expr['data']) + ret += generate_enum_declaration(expr['enum'], expr['data']) fdecl.write(ret) fdecl.write(''' -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong ` (3 preceding siblings ...) 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 4/6] qapi: generate list struct and visit_list for enum Amos Kong @ 2012-07-26 4:49 ` Amos Kong 2012-07-27 19:24 ` Blue Swirl 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey Amos Kong 5 siblings, 1 reply; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:49 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino Event would be ignored if ps2 queue is full, this patch added a warning in ignore path. Signed-off-by: Amos Kong <akong@redhat.com> --- hw/ps2.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) diff --git a/hw/ps2.c b/hw/ps2.c index f93cd24..799c36b 100644 --- a/hw/ps2.c +++ b/hw/ps2.c @@ -137,8 +137,10 @@ void ps2_queue(void *opaque, int b) PS2State *s = (PS2State *)opaque; PS2Queue *q = &s->queue; - if (q->count >= PS2_QUEUE_SIZE) + if (q->count >= PS2_QUEUE_SIZE) { + fprintf(stderr, "ps2: warning: event queue full\n"); return; + } q->data[q->wptr] = b; if (++q->wptr == PS2_QUEUE_SIZE) q->wptr = 0; -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full Amos Kong @ 2012-07-27 19:24 ` Blue Swirl 0 siblings, 0 replies; 12+ messages in thread From: Blue Swirl @ 2012-07-27 19:24 UTC (permalink / raw) To: Amos Kong; +Cc: aliguori, eblake, qemu-devel, lcapitulino On Thu, Jul 26, 2012 at 4:49 AM, Amos Kong <akong@redhat.com> wrote: > Event would be ignored if ps2 queue is full, this patch > added a warning in ignore path. > > Signed-off-by: Amos Kong <akong@redhat.com> > --- > hw/ps2.c | 4 +++- > 1 files changed, 3 insertions(+), 1 deletions(-) > > diff --git a/hw/ps2.c b/hw/ps2.c > index f93cd24..799c36b 100644 > --- a/hw/ps2.c > +++ b/hw/ps2.c > @@ -137,8 +137,10 @@ void ps2_queue(void *opaque, int b) > PS2State *s = (PS2State *)opaque; > PS2Queue *q = &s->queue; > > - if (q->count >= PS2_QUEUE_SIZE) > + if (q->count >= PS2_QUEUE_SIZE) { > + fprintf(stderr, "ps2: warning: event queue full\n"); This spams console at guest's will. Please use DPRINTF. > return; > + } > q->data[q->wptr] = b; > if (++q->wptr == PS2_QUEUE_SIZE) > q->wptr = 0; > -- > 1.7.1 > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong ` (4 preceding siblings ...) 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full Amos Kong @ 2012-07-26 4:49 ` Amos Kong 2012-07-26 21:22 ` Eric Blake 2012-08-02 19:57 ` Luiz Capitulino 5 siblings, 2 replies; 12+ messages in thread From: Amos Kong @ 2012-07-26 4:49 UTC (permalink / raw) To: qemu-devel; +Cc: aliguori, Amos Kong, eblake, lcapitulino Convert 'sendkey' to use QAPI. Keys' indexes in the enmu are same as keycodes' indexes in the key_defs[], index_from_code() and index_from_key() will return Q_KEY_CODE_MAX if the code/key is invalid. For qmp, QAPI would check invalid key and raise error. For hmp, invalid key is checked in hmp_send_key(). 'send-key' of QMP doesn't support key in hexadecimal format. Signed-off-by: Amos Kong <akong@redhat.com> --- console.h | 5 + hmp-commands.hx | 2 +- hmp.c | 55 ++++++++++++ hmp.h | 1 + input.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++ monitor.c | 258 ++---------------------------------------------------- qapi-schema.json | 46 ++++++++++ qmp-commands.hx | 28 ++++++ 8 files changed, 393 insertions(+), 251 deletions(-) diff --git a/console.h b/console.h index 4334db5..b2d7af6 100644 --- a/console.h +++ b/console.h @@ -6,6 +6,7 @@ #include "notify.h" #include "monitor.h" #include "trace.h" +#include "qapi-types.h" /* keyboard/mouse support */ @@ -397,4 +398,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) /* curses.c */ void curses_display_init(DisplayState *ds, int full_screen); +/* input.c */ +extern const int key_defs[]; +int index_from_key(const char *key); +int index_from_keycode(int code); #endif diff --git a/hmp-commands.hx b/hmp-commands.hx index 2891d48..8c2be24 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -505,7 +505,7 @@ ETEXI .args_type = "keys:s,hold-time:i?", .params = "keys [hold_ms]", .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", - .mhandler.cmd = do_sendkey, + .mhandler.cmd = hmp_send_key, }, STEXI diff --git a/hmp.c b/hmp.c index 6b72a64..041555a 100644 --- a/hmp.c +++ b/hmp.c @@ -19,6 +19,7 @@ #include "qemu-timer.h" #include "qmp-commands.h" #include "monitor.h" +#include "console.h" static void hmp_handle_error(Monitor *mon, Error **errp) { @@ -1020,3 +1021,57 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) qmp_closefd(fdname, &errp); hmp_handle_error(mon, &errp); } + +void hmp_send_key(Monitor *mon, const QDict *qdict) +{ + const char *keys = qdict_get_str(qdict, "keys"); + QKeyCodeList *keylist, *head = NULL, *tmp = NULL; + int has_hold_time = qdict_haskey(qdict, "hold-time"); + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); + Error *err = NULL; + char keyname_buf[16]; + char *separator; + int keyname_len, idx; + + while (1) { + separator = strchr(keys, '-'); + keyname_len = separator ? separator - keys : strlen(keys); + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); + + /* Be compatible with old interface, convert user inputted "<" */ + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); + keyname_len = 4; + } + keyname_buf[keyname_len] = 0; + + idx = index_from_key(keyname_buf); + if (idx == Q_KEY_CODE_MAX) { + error_set(&err, QERR_INVALID_PARAMETER, keyname_buf); + break; + } + + keylist = g_malloc0(sizeof(*keylist)); + keylist->value = idx; + keylist->next = NULL; + + if (!head) { + head = keylist; + } + if (tmp) { + tmp->next = keylist; + } + tmp = keylist; + + if (!separator) { + break; + } + keys = separator + 1; + } + + if (idx != Q_KEY_CODE_MAX) { + qmp_send_key(head, has_hold_time, hold_time, &err); + } + hmp_handle_error(mon, &err); + qapi_free_QKeyCodeList(head); +} diff --git a/hmp.h b/hmp.h index 8d2b0d7..56d67a3 100644 --- a/hmp.h +++ b/hmp.h @@ -66,5 +66,6 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); void hmp_netdev_del(Monitor *mon, const QDict *qdict); void hmp_getfd(Monitor *mon, const QDict *qdict); void hmp_closefd(Monitor *mon, const QDict *qdict); +void hmp_send_key(Monitor *mon, const QDict *qdict); #endif diff --git a/input.c b/input.c index 6968b31..2286581 100644 --- a/input.c +++ b/input.c @@ -28,6 +28,7 @@ #include "console.h" #include "error.h" #include "qmp-commands.h" +#include "qapi-types.h" static QEMUPutKBDEvent *qemu_put_kbd_event; static void *qemu_put_kbd_event_opaque; @@ -37,6 +38,254 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = static NotifierList mouse_mode_notifiers = NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); +const int key_defs[] = { + [Q_KEY_CODE_SHIFT] = 0x2a, + [Q_KEY_CODE_SHIFT_R] = 0x36, + + [Q_KEY_CODE_ALT] = 0x38, + [Q_KEY_CODE_ALT_R] = 0xb8, + [Q_KEY_CODE_ALTGR] = 0x64, + [Q_KEY_CODE_ALTGR_R] = 0xe4, + [Q_KEY_CODE_CTRL] = 0x1d, + [Q_KEY_CODE_CTRL_R] = 0x9d, + + [Q_KEY_CODE_MENU] = 0xdd, + + [Q_KEY_CODE_ESC] = 0x01, + + [Q_KEY_CODE_1] = 0x02, + [Q_KEY_CODE_2] = 0x03, + [Q_KEY_CODE_3] = 0x04, + [Q_KEY_CODE_4] = 0x05, + [Q_KEY_CODE_5] = 0x06, + [Q_KEY_CODE_6] = 0x07, + [Q_KEY_CODE_7] = 0x08, + [Q_KEY_CODE_8] = 0x09, + [Q_KEY_CODE_9] = 0x0a, + [Q_KEY_CODE_0] = 0x0b, + [Q_KEY_CODE_MINUS] = 0x0c, + [Q_KEY_CODE_EQUAL] = 0x0d, + [Q_KEY_CODE_BACKSPACE] = 0x0e, + + [Q_KEY_CODE_TAB] = 0x0f, + [Q_KEY_CODE_Q] = 0x10, + [Q_KEY_CODE_W] = 0x11, + [Q_KEY_CODE_E] = 0x12, + [Q_KEY_CODE_R] = 0x13, + [Q_KEY_CODE_T] = 0x14, + [Q_KEY_CODE_Y] = 0x15, + [Q_KEY_CODE_U] = 0x16, + [Q_KEY_CODE_I] = 0x17, + [Q_KEY_CODE_O] = 0x18, + [Q_KEY_CODE_P] = 0x19, + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, + [Q_KEY_CODE_RET] = 0x1c, + + [Q_KEY_CODE_A] = 0x1e, + [Q_KEY_CODE_S] = 0x1f, + [Q_KEY_CODE_D] = 0x20, + [Q_KEY_CODE_F] = 0x21, + [Q_KEY_CODE_G] = 0x22, + [Q_KEY_CODE_H] = 0x23, + [Q_KEY_CODE_J] = 0x24, + [Q_KEY_CODE_K] = 0x25, + [Q_KEY_CODE_L] = 0x26, + [Q_KEY_CODE_SEMICOLON] = 0x27, + [Q_KEY_CODE_APOSTROPHE] = 0x28, + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, + + [Q_KEY_CODE_BACKSLASH] = 0x2b, + [Q_KEY_CODE_Z] = 0x2c, + [Q_KEY_CODE_X] = 0x2d, + [Q_KEY_CODE_C] = 0x2e, + [Q_KEY_CODE_V] = 0x2f, + [Q_KEY_CODE_B] = 0x30, + [Q_KEY_CODE_N] = 0x31, + [Q_KEY_CODE_M] = 0x32, + [Q_KEY_CODE_COMMA] = 0x33, + [Q_KEY_CODE_DOT] = 0x34, + [Q_KEY_CODE_SLASH] = 0x35, + + [Q_KEY_CODE_ASTERISK] = 0x37, + + [Q_KEY_CODE_SPC] = 0x39, + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, + [Q_KEY_CODE_F1] = 0x3b, + [Q_KEY_CODE_F2] = 0x3c, + [Q_KEY_CODE_F3] = 0x3d, + [Q_KEY_CODE_F4] = 0x3e, + [Q_KEY_CODE_F5] = 0x3f, + [Q_KEY_CODE_F6] = 0x40, + [Q_KEY_CODE_F7] = 0x41, + [Q_KEY_CODE_F8] = 0x42, + [Q_KEY_CODE_F9] = 0x43, + [Q_KEY_CODE_F10] = 0x44, + [Q_KEY_CODE_NUM_LOCK] = 0x45, + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, + + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, + [Q_KEY_CODE_KP_ADD] = 0x4e, + [Q_KEY_CODE_KP_ENTER] = 0x9c, + [Q_KEY_CODE_KP_DECIMAL] = 0x53, + [Q_KEY_CODE_SYSRQ] = 0x54, + + [Q_KEY_CODE_KP_0] = 0x52, + [Q_KEY_CODE_KP_1] = 0x4f, + [Q_KEY_CODE_KP_2] = 0x50, + [Q_KEY_CODE_KP_3] = 0x51, + [Q_KEY_CODE_KP_4] = 0x4b, + [Q_KEY_CODE_KP_5] = 0x4c, + [Q_KEY_CODE_KP_6] = 0x4d, + [Q_KEY_CODE_KP_7] = 0x47, + [Q_KEY_CODE_KP_8] = 0x48, + [Q_KEY_CODE_KP_9] = 0x49, + + [Q_KEY_CODE_LESS] = 0x56, + + [Q_KEY_CODE_F11] = 0x57, + [Q_KEY_CODE_F12] = 0x58, + + [Q_KEY_CODE_PRINT] = 0xb7, + + [Q_KEY_CODE_HOME] = 0xc7, + [Q_KEY_CODE_PGUP] = 0xc9, + [Q_KEY_CODE_PGDN] = 0xd1, + [Q_KEY_CODE_END] = 0xcf, + + [Q_KEY_CODE_LEFT] = 0xcb, + [Q_KEY_CODE_UP] = 0xc8, + [Q_KEY_CODE_DOWN] = 0xd0, + [Q_KEY_CODE_RIGHT] = 0xcd, + + [Q_KEY_CODE_INSERT] = 0xd2, + [Q_KEY_CODE_DELETE] = 0xd3, +#ifdef NEED_CPU_H +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) + [Q_KEY_CODE_STOP] = 0xf0, + [Q_KEY_CODE_AGAIN] = 0xf1, + [Q_KEY_CODE_PROPS] = 0xf2, + [Q_KEY_CODE_UNDO] = 0xf3, + [Q_KEY_CODE_FRONT] = 0xf4, + [Q_KEY_CODE_COPY] = 0xf5, + [Q_KEY_CODE_OPEN] = 0xf6, + [Q_KEY_CODE_PASTE] = 0xf7, + [Q_KEY_CODE_FIND] = 0xf8, + [Q_KEY_CODE_CUT] = 0xf9, + [Q_KEY_CODE_LF] = 0xfa, + [Q_KEY_CODE_HELP] = 0xfb, + [Q_KEY_CODE_META_L] = 0xfc, + [Q_KEY_CODE_META_R] = 0xfd, + [Q_KEY_CODE_COMPOSE] = 0xfe, +#endif +#endif + [Q_KEY_CODE_MAX] = 0, +}; + +int index_from_key(const char *key) +{ + int i, keycode; + char *endp; + + for (i = 0; QKeyCode_lookup[i] != NULL; i++) { + if (!strcmp(key, QKeyCode_lookup[i])) { + break; + } + } + + if (strstart(key, "0x", NULL)) { + keycode = strtoul(key, &endp, 0); + if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) { + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + if (keycode == key_defs[i]) { + break; + } + } + } + } + + /* Return Q_KEY_CODE_MAX if the key is invalid */ + return i; +} + +int index_from_keycode(int code) +{ + int i; + for (i = 0; i < Q_KEY_CODE_MAX; i++) { + if (key_defs[i] == code) { + break; + } + } + /* Return Q_KEY_CODE_MAX if the code is invalid */ + return i; +} + +static QKeyCodeList *keycodes; +static QEMUTimer *key_timer; + +static void release_keys(void *opaque) +{ + int keycode; + QKeyCodeList *p; + + for (p = keycodes; p != NULL; p = p->next) { + keycode = key_defs[p->value]; + if (keycode & 0x80) { + kbd_put_keycode(0xe0); + } + kbd_put_keycode(keycode | 0x80); + } + qapi_free_QKeyCodeList(keycodes); + keycodes = NULL; +} + +void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t hold_time, + Error **errp) +{ + int keycode; + QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL; + + if (!key_timer) { + key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); + } + + if (keycodes != NULL) { + qemu_del_timer(key_timer); + release_keys(NULL); + } + if (!has_hold_time) { + hold_time = 100; + } + + for (p = keys; p != NULL; p = p->next) { + keylist = g_malloc0(sizeof(*keylist)); + keylist->value = p->value; + keylist->next = NULL; + + if (!head) { + head = keylist; + } + if (tmp) { + tmp->next = keylist; + } + tmp = keylist; + + /* key down events */ + keycode = key_defs[p->value]; + if (keycode & 0x80) { + kbd_put_keycode(0xe0); + } + kbd_put_keycode(keycode & 0x7f); + } + keycodes = head; + + /* delayed key up events */ + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + + muldiv64(get_ticks_per_sec(), hold_time, 1000)); +} + void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) { qemu_put_kbd_event_opaque = opaque; diff --git a/monitor.c b/monitor.c index 4db0c1e..e3a2023 100644 --- a/monitor.c +++ b/monitor.c @@ -1293,252 +1293,6 @@ static void do_sum(Monitor *mon, const QDict *qdict) monitor_printf(mon, "%05d\n", sum); } -typedef struct { - int keycode; - const char *name; -} KeyDef; - -static const KeyDef key_defs[] = { - { 0x2a, "shift" }, - { 0x36, "shift_r" }, - - { 0x38, "alt" }, - { 0xb8, "alt_r" }, - { 0x64, "altgr" }, - { 0xe4, "altgr_r" }, - { 0x1d, "ctrl" }, - { 0x9d, "ctrl_r" }, - - { 0xdd, "menu" }, - - { 0x01, "esc" }, - - { 0x02, "1" }, - { 0x03, "2" }, - { 0x04, "3" }, - { 0x05, "4" }, - { 0x06, "5" }, - { 0x07, "6" }, - { 0x08, "7" }, - { 0x09, "8" }, - { 0x0a, "9" }, - { 0x0b, "0" }, - { 0x0c, "minus" }, - { 0x0d, "equal" }, - { 0x0e, "backspace" }, - - { 0x0f, "tab" }, - { 0x10, "q" }, - { 0x11, "w" }, - { 0x12, "e" }, - { 0x13, "r" }, - { 0x14, "t" }, - { 0x15, "y" }, - { 0x16, "u" }, - { 0x17, "i" }, - { 0x18, "o" }, - { 0x19, "p" }, - { 0x1a, "bracket_left" }, - { 0x1b, "bracket_right" }, - { 0x1c, "ret" }, - - { 0x1e, "a" }, - { 0x1f, "s" }, - { 0x20, "d" }, - { 0x21, "f" }, - { 0x22, "g" }, - { 0x23, "h" }, - { 0x24, "j" }, - { 0x25, "k" }, - { 0x26, "l" }, - { 0x27, "semicolon" }, - { 0x28, "apostrophe" }, - { 0x29, "grave_accent" }, - - { 0x2b, "backslash" }, - { 0x2c, "z" }, - { 0x2d, "x" }, - { 0x2e, "c" }, - { 0x2f, "v" }, - { 0x30, "b" }, - { 0x31, "n" }, - { 0x32, "m" }, - { 0x33, "comma" }, - { 0x34, "dot" }, - { 0x35, "slash" }, - - { 0x37, "asterisk" }, - - { 0x39, "spc" }, - { 0x3a, "caps_lock" }, - { 0x3b, "f1" }, - { 0x3c, "f2" }, - { 0x3d, "f3" }, - { 0x3e, "f4" }, - { 0x3f, "f5" }, - { 0x40, "f6" }, - { 0x41, "f7" }, - { 0x42, "f8" }, - { 0x43, "f9" }, - { 0x44, "f10" }, - { 0x45, "num_lock" }, - { 0x46, "scroll_lock" }, - - { 0xb5, "kp_divide" }, - { 0x37, "kp_multiply" }, - { 0x4a, "kp_subtract" }, - { 0x4e, "kp_add" }, - { 0x9c, "kp_enter" }, - { 0x53, "kp_decimal" }, - { 0x54, "sysrq" }, - - { 0x52, "kp_0" }, - { 0x4f, "kp_1" }, - { 0x50, "kp_2" }, - { 0x51, "kp_3" }, - { 0x4b, "kp_4" }, - { 0x4c, "kp_5" }, - { 0x4d, "kp_6" }, - { 0x47, "kp_7" }, - { 0x48, "kp_8" }, - { 0x49, "kp_9" }, - - { 0x56, "less" }, - - { 0x57, "f11" }, - { 0x58, "f12" }, - - { 0xb7, "print" }, - - { 0xc7, "home" }, - { 0xc9, "pgup" }, - { 0xd1, "pgdn" }, - { 0xcf, "end" }, - - { 0xcb, "left" }, - { 0xc8, "up" }, - { 0xd0, "down" }, - { 0xcd, "right" }, - - { 0xd2, "insert" }, - { 0xd3, "delete" }, -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) - { 0xf0, "stop" }, - { 0xf1, "again" }, - { 0xf2, "props" }, - { 0xf3, "undo" }, - { 0xf4, "front" }, - { 0xf5, "copy" }, - { 0xf6, "open" }, - { 0xf7, "paste" }, - { 0xf8, "find" }, - { 0xf9, "cut" }, - { 0xfa, "lf" }, - { 0xfb, "help" }, - { 0xfc, "meta_l" }, - { 0xfd, "meta_r" }, - { 0xfe, "compose" }, -#endif - { 0, NULL }, -}; - -static int get_keycode(const char *key) -{ - const KeyDef *p; - char *endp; - int ret; - - for(p = key_defs; p->name != NULL; p++) { - if (!strcmp(key, p->name)) - return p->keycode; - } - if (strstart(key, "0x", NULL)) { - ret = strtoul(key, &endp, 0); - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) - return ret; - } - return -1; -} - -#define MAX_KEYCODES 16 -static uint8_t keycodes[MAX_KEYCODES]; -static int nb_pending_keycodes; -static QEMUTimer *key_timer; - -static void release_keys(void *opaque) -{ - int keycode; - - 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); - } -} - -static void do_sendkey(Monitor *mon, const QDict *qdict) -{ - char keyname_buf[16]; - char *separator; - int keyname_len, keycode, i; - const char *keys = qdict_get_str(qdict, "keys"); - int has_hold_time = qdict_haskey(qdict, "hold-time"); - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); - - if (nb_pending_keycodes > 0) { - qemu_del_timer(key_timer); - release_keys(NULL); - } - if (!has_hold_time) - hold_time = 100; - i = 0; - while (1) { - separator = strchr(keys, '-'); - keyname_len = separator ? separator - keys : strlen(keys); - if (keyname_len > 0) { - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); - if (keyname_len > sizeof(keyname_buf) - 1) { - monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); - return; - } - if (i == MAX_KEYCODES) { - monitor_printf(mon, "too many keys\n"); - return; - } - - /* Be compatible with old interface, convert user inputted "<" */ - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); - keyname_len = 4; - } - - keyname_buf[keyname_len] = 0; - keycode = get_keycode(keyname_buf); - if (keycode < 0) { - monitor_printf(mon, "unknown key: '%s'\n", keyname_buf); - return; - } - keycodes[i++] = keycode; - } - if (!separator) - break; - keys = separator + 1; - } - 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); - } - /* delayed key up events */ - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + - muldiv64(get_ticks_per_sec(), hold_time, 1000)); -} - static int mouse_button_state; static void do_mouse_move(Monitor *mon, const QDict *qdict) @@ -4077,7 +3831,7 @@ static void monitor_find_completion(const char *cmdline) int nb_args, i, len; const char *ptype, *str; const mon_cmd_t *cmd; - const KeyDef *key; + const int *code; parse_cmdline(cmdline, &nb_args, args); #ifdef DEBUG_COMPLETION @@ -4151,9 +3905,14 @@ static void monitor_find_completion(const char *cmdline) if (sep) str = sep + 1; readline_set_completion_index(cur_mon->rs, strlen(str)); - for(key = key_defs; key->name != NULL; key++) { - cmd_completion(str, key->name); + for (code = key_defs; code != NULL; code++) { + int idx; + idx = index_from_keycode(*code); + if (idx != Q_KEY_CODE_MAX) { + cmd_completion(str, QKeyCode_lookup[idx]); + } } + } else if (!strcmp(cmd->name, "help|?")) { readline_set_completion_index(cur_mon->rs, strlen(str)); for (cmd = mon_cmds; cmd->name != NULL; cmd++) { @@ -4681,7 +4440,6 @@ void monitor_init(CharDriverState *chr, int flags) Monitor *mon; if (is_first_init) { - key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); monitor_protocol_event_init(); is_first_init = 0; } diff --git a/qapi-schema.json b/qapi-schema.json index bc55ed2..3a562d8 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -2183,3 +2183,49 @@ # Since: 0.14.0 ## { 'command': 'closefd', 'data': {'fdname': 'str'} } + +## +# @QKeyCode: +# +# An enumeration of key name. +# +# This is used by the send-key command. +# +# Since: 1.2 +## +{ 'enum': 'QKeyCode', + 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', + 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', + '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', + 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', + 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon', + 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b', + 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock', + 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', + 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', + 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0', + 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8', + 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', + 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', + 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', + 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } + +## +# @send-key: +# +# Send keys to guest. +# +# @keys: key sequence. 'keys' is the name of the key. Use a JSON array to +# press several keys simultaneously. +# +# @hold-time: #optional time to delay key up events, milliseconds. Defaults +# to 100 +# +# Returns: Nothing on success +# If key is unknown or redundant, InvalidParameter +# +# Since: 1.2 +# +## +{ 'command': 'send-key', + 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } diff --git a/qmp-commands.hx b/qmp-commands.hx index e3cf3c5..3c1e646 100644 --- a/qmp-commands.hx +++ b/qmp-commands.hx @@ -335,6 +335,34 @@ Example: EQMP { + .name = "send-key", + .args_type = "keys:O,hold-time:i?", + .mhandler.cmd_new = qmp_marshal_input_send_key, + }, + +SQMP +send-key +---------- + +Send keys to VM. + +Arguments: + +keys array: + - "key": key sequence (a json-array of key enum values) + +- hold-time: time to delay key up events, milliseconds. Defaults to 100 + (json-int, optional) + +Example: + +-> { "execute": "send-key", + "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } } +<- { "return": {} } + +EQMP + + { .name = "cpu", .args_type = "index:i", .mhandler.cmd_new = qmp_marshal_input_cpu, -- 1.7.1 ^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey Amos Kong @ 2012-07-26 21:22 ` Eric Blake 2012-08-02 19:57 ` Luiz Capitulino 1 sibling, 0 replies; 12+ messages in thread From: Eric Blake @ 2012-07-26 21:22 UTC (permalink / raw) To: Amos Kong; +Cc: aliguori, qemu-devel, lcapitulino [-- Attachment #1: Type: text/plain, Size: 787 bytes --] On 07/25/2012 10:49 PM, Amos Kong wrote: > Convert 'sendkey' to use QAPI. > > Keys' indexes in the enmu are same as keycodes' indexes in the s/enmu/enum/ > key_defs[], index_from_code() and index_from_key() will return > Q_KEY_CODE_MAX if the code/key is invalid. > > For qmp, QAPI would check invalid key and raise error. > For hmp, invalid key is checked in hmp_send_key(). > > 'send-key' of QMP doesn't support key in hexadecimal format. > > Signed-off-by: Amos Kong <akong@redhat.com> I glanced through the series, and didn't see anything else suspicious from my point of view. The QMP interface which libvirt will be using appears to be sane. -- Eric Blake eblake@redhat.com +1-919-301-3266 Libvirt virtualization library http://libvirt.org [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 620 bytes --] ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey Amos Kong 2012-07-26 21:22 ` Eric Blake @ 2012-08-02 19:57 ` Luiz Capitulino 2012-08-03 1:38 ` Amos Kong 1 sibling, 1 reply; 12+ messages in thread From: Luiz Capitulino @ 2012-08-02 19:57 UTC (permalink / raw) To: Amos Kong; +Cc: aliguori, eblake, qemu-devel On Thu, 26 Jul 2012 12:49:01 +0800 Amos Kong <akong@redhat.com> wrote: > Convert 'sendkey' to use QAPI. > > Keys' indexes in the enmu are same as keycodes' indexes in the > key_defs[], index_from_code() and index_from_key() will return > Q_KEY_CODE_MAX if the code/key is invalid. > > For qmp, QAPI would check invalid key and raise error. > For hmp, invalid key is checked in hmp_send_key(). > > 'send-key' of QMP doesn't support key in hexadecimal format. > > Signed-off-by: Amos Kong <akong@redhat.com> I've some review comments below, besides I'd like to ask you to split the addition of the QKeyCode enum and the key_defs table moving to a different patch. Other than that this looks quite better, hopefully v6 will be the last one. > --- > console.h | 5 + > hmp-commands.hx | 2 +- > hmp.c | 55 ++++++++++++ > hmp.h | 1 + > input.c | 249 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > monitor.c | 258 ++---------------------------------------------------- > qapi-schema.json | 46 ++++++++++ > qmp-commands.hx | 28 ++++++ > 8 files changed, 393 insertions(+), 251 deletions(-) > > diff --git a/console.h b/console.h > index 4334db5..b2d7af6 100644 > --- a/console.h > +++ b/console.h > @@ -6,6 +6,7 @@ > #include "notify.h" > #include "monitor.h" > #include "trace.h" > +#include "qapi-types.h" > > /* keyboard/mouse support */ > > @@ -397,4 +398,8 @@ static inline int vnc_display_pw_expire(DisplayState *ds, time_t expires) > /* curses.c */ > void curses_display_init(DisplayState *ds, int full_screen); > > +/* input.c */ > +extern const int key_defs[]; > +int index_from_key(const char *key); > +int index_from_keycode(int code); > #endif > diff --git a/hmp-commands.hx b/hmp-commands.hx > index 2891d48..8c2be24 100644 > --- a/hmp-commands.hx > +++ b/hmp-commands.hx > @@ -505,7 +505,7 @@ ETEXI > .args_type = "keys:s,hold-time:i?", > .params = "keys [hold_ms]", > .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", > - .mhandler.cmd = do_sendkey, > + .mhandler.cmd = hmp_send_key, > }, > > STEXI > diff --git a/hmp.c b/hmp.c > index 6b72a64..041555a 100644 > --- a/hmp.c > +++ b/hmp.c > @@ -19,6 +19,7 @@ > #include "qemu-timer.h" > #include "qmp-commands.h" > #include "monitor.h" > +#include "console.h" > > static void hmp_handle_error(Monitor *mon, Error **errp) > { > @@ -1020,3 +1021,57 @@ void hmp_closefd(Monitor *mon, const QDict *qdict) > qmp_closefd(fdname, &errp); > hmp_handle_error(mon, &errp); > } > + > +void hmp_send_key(Monitor *mon, const QDict *qdict) > +{ > + const char *keys = qdict_get_str(qdict, "keys"); > + QKeyCodeList *keylist, *head = NULL, *tmp = NULL; > + int has_hold_time = qdict_haskey(qdict, "hold-time"); > + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > + Error *err = NULL; > + char keyname_buf[16]; > + char *separator; > + int keyname_len, idx; > + > + while (1) { > + separator = strchr(keys, '-'); > + keyname_len = separator ? separator - keys : strlen(keys); > + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > + > + /* Be compatible with old interface, convert user inputted "<" */ > + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { > + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > + keyname_len = 4; > + } > + keyname_buf[keyname_len] = 0; > + > + idx = index_from_key(keyname_buf); > + if (idx == Q_KEY_CODE_MAX) { > + error_set(&err, QERR_INVALID_PARAMETER, keyname_buf); No need to use error_set(), you can call monitor_printf() directly. > + break; > + } > + > + keylist = g_malloc0(sizeof(*keylist)); > + keylist->value = idx; > + keylist->next = NULL; > + > + if (!head) { > + head = keylist; > + } > + if (tmp) { > + tmp->next = keylist; > + } > + tmp = keylist; > + > + if (!separator) { > + break; > + } > + keys = separator + 1; > + } > + > + if (idx != Q_KEY_CODE_MAX) { > + qmp_send_key(head, has_hold_time, hold_time, &err); > + } > + hmp_handle_error(mon, &err); > + qapi_free_QKeyCodeList(head); > +} > diff --git a/hmp.h b/hmp.h > index 8d2b0d7..56d67a3 100644 > --- a/hmp.h > +++ b/hmp.h > @@ -66,5 +66,6 @@ void hmp_netdev_add(Monitor *mon, const QDict *qdict); > void hmp_netdev_del(Monitor *mon, const QDict *qdict); > void hmp_getfd(Monitor *mon, const QDict *qdict); > void hmp_closefd(Monitor *mon, const QDict *qdict); > +void hmp_send_key(Monitor *mon, const QDict *qdict); > > #endif > diff --git a/input.c b/input.c > index 6968b31..2286581 100644 > --- a/input.c > +++ b/input.c > @@ -28,6 +28,7 @@ > #include "console.h" > #include "error.h" > #include "qmp-commands.h" > +#include "qapi-types.h" > > static QEMUPutKBDEvent *qemu_put_kbd_event; > static void *qemu_put_kbd_event_opaque; > @@ -37,6 +38,254 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) mouse_handlers = > static NotifierList mouse_mode_notifiers = > NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); > > +const int key_defs[] = { Please, make key_defs static. > + [Q_KEY_CODE_SHIFT] = 0x2a, > + [Q_KEY_CODE_SHIFT_R] = 0x36, > + > + [Q_KEY_CODE_ALT] = 0x38, > + [Q_KEY_CODE_ALT_R] = 0xb8, > + [Q_KEY_CODE_ALTGR] = 0x64, > + [Q_KEY_CODE_ALTGR_R] = 0xe4, > + [Q_KEY_CODE_CTRL] = 0x1d, > + [Q_KEY_CODE_CTRL_R] = 0x9d, > + > + [Q_KEY_CODE_MENU] = 0xdd, > + > + [Q_KEY_CODE_ESC] = 0x01, > + > + [Q_KEY_CODE_1] = 0x02, > + [Q_KEY_CODE_2] = 0x03, > + [Q_KEY_CODE_3] = 0x04, > + [Q_KEY_CODE_4] = 0x05, > + [Q_KEY_CODE_5] = 0x06, > + [Q_KEY_CODE_6] = 0x07, > + [Q_KEY_CODE_7] = 0x08, > + [Q_KEY_CODE_8] = 0x09, > + [Q_KEY_CODE_9] = 0x0a, > + [Q_KEY_CODE_0] = 0x0b, > + [Q_KEY_CODE_MINUS] = 0x0c, > + [Q_KEY_CODE_EQUAL] = 0x0d, > + [Q_KEY_CODE_BACKSPACE] = 0x0e, > + > + [Q_KEY_CODE_TAB] = 0x0f, > + [Q_KEY_CODE_Q] = 0x10, > + [Q_KEY_CODE_W] = 0x11, > + [Q_KEY_CODE_E] = 0x12, > + [Q_KEY_CODE_R] = 0x13, > + [Q_KEY_CODE_T] = 0x14, > + [Q_KEY_CODE_Y] = 0x15, > + [Q_KEY_CODE_U] = 0x16, > + [Q_KEY_CODE_I] = 0x17, > + [Q_KEY_CODE_O] = 0x18, > + [Q_KEY_CODE_P] = 0x19, > + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, > + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, > + [Q_KEY_CODE_RET] = 0x1c, > + > + [Q_KEY_CODE_A] = 0x1e, > + [Q_KEY_CODE_S] = 0x1f, > + [Q_KEY_CODE_D] = 0x20, > + [Q_KEY_CODE_F] = 0x21, > + [Q_KEY_CODE_G] = 0x22, > + [Q_KEY_CODE_H] = 0x23, > + [Q_KEY_CODE_J] = 0x24, > + [Q_KEY_CODE_K] = 0x25, > + [Q_KEY_CODE_L] = 0x26, > + [Q_KEY_CODE_SEMICOLON] = 0x27, > + [Q_KEY_CODE_APOSTROPHE] = 0x28, > + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, > + > + [Q_KEY_CODE_BACKSLASH] = 0x2b, > + [Q_KEY_CODE_Z] = 0x2c, > + [Q_KEY_CODE_X] = 0x2d, > + [Q_KEY_CODE_C] = 0x2e, > + [Q_KEY_CODE_V] = 0x2f, > + [Q_KEY_CODE_B] = 0x30, > + [Q_KEY_CODE_N] = 0x31, > + [Q_KEY_CODE_M] = 0x32, > + [Q_KEY_CODE_COMMA] = 0x33, > + [Q_KEY_CODE_DOT] = 0x34, > + [Q_KEY_CODE_SLASH] = 0x35, > + > + [Q_KEY_CODE_ASTERISK] = 0x37, > + > + [Q_KEY_CODE_SPC] = 0x39, > + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, > + [Q_KEY_CODE_F1] = 0x3b, > + [Q_KEY_CODE_F2] = 0x3c, > + [Q_KEY_CODE_F3] = 0x3d, > + [Q_KEY_CODE_F4] = 0x3e, > + [Q_KEY_CODE_F5] = 0x3f, > + [Q_KEY_CODE_F6] = 0x40, > + [Q_KEY_CODE_F7] = 0x41, > + [Q_KEY_CODE_F8] = 0x42, > + [Q_KEY_CODE_F9] = 0x43, > + [Q_KEY_CODE_F10] = 0x44, > + [Q_KEY_CODE_NUM_LOCK] = 0x45, > + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, > + > + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, > + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, > + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, > + [Q_KEY_CODE_KP_ADD] = 0x4e, > + [Q_KEY_CODE_KP_ENTER] = 0x9c, > + [Q_KEY_CODE_KP_DECIMAL] = 0x53, > + [Q_KEY_CODE_SYSRQ] = 0x54, > + > + [Q_KEY_CODE_KP_0] = 0x52, > + [Q_KEY_CODE_KP_1] = 0x4f, > + [Q_KEY_CODE_KP_2] = 0x50, > + [Q_KEY_CODE_KP_3] = 0x51, > + [Q_KEY_CODE_KP_4] = 0x4b, > + [Q_KEY_CODE_KP_5] = 0x4c, > + [Q_KEY_CODE_KP_6] = 0x4d, > + [Q_KEY_CODE_KP_7] = 0x47, > + [Q_KEY_CODE_KP_8] = 0x48, > + [Q_KEY_CODE_KP_9] = 0x49, > + > + [Q_KEY_CODE_LESS] = 0x56, > + > + [Q_KEY_CODE_F11] = 0x57, > + [Q_KEY_CODE_F12] = 0x58, > + > + [Q_KEY_CODE_PRINT] = 0xb7, > + > + [Q_KEY_CODE_HOME] = 0xc7, > + [Q_KEY_CODE_PGUP] = 0xc9, > + [Q_KEY_CODE_PGDN] = 0xd1, > + [Q_KEY_CODE_END] = 0xcf, > + > + [Q_KEY_CODE_LEFT] = 0xcb, > + [Q_KEY_CODE_UP] = 0xc8, > + [Q_KEY_CODE_DOWN] = 0xd0, > + [Q_KEY_CODE_RIGHT] = 0xcd, > + > + [Q_KEY_CODE_INSERT] = 0xd2, > + [Q_KEY_CODE_DELETE] = 0xd3, > +#ifdef NEED_CPU_H > +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > + [Q_KEY_CODE_STOP] = 0xf0, > + [Q_KEY_CODE_AGAIN] = 0xf1, > + [Q_KEY_CODE_PROPS] = 0xf2, > + [Q_KEY_CODE_UNDO] = 0xf3, > + [Q_KEY_CODE_FRONT] = 0xf4, > + [Q_KEY_CODE_COPY] = 0xf5, > + [Q_KEY_CODE_OPEN] = 0xf6, > + [Q_KEY_CODE_PASTE] = 0xf7, > + [Q_KEY_CODE_FIND] = 0xf8, > + [Q_KEY_CODE_CUT] = 0xf9, > + [Q_KEY_CODE_LF] = 0xfa, > + [Q_KEY_CODE_HELP] = 0xfb, > + [Q_KEY_CODE_META_L] = 0xfc, > + [Q_KEY_CODE_META_R] = 0xfd, > + [Q_KEY_CODE_COMPOSE] = 0xfe, > +#endif > +#endif > + [Q_KEY_CODE_MAX] = 0, > +}; > + > +int index_from_key(const char *key) keycode_from_key() is better. > +{ > + int i, keycode; > + char *endp; > + > + for (i = 0; QKeyCode_lookup[i] != NULL; i++) { > + if (!strcmp(key, QKeyCode_lookup[i])) { > + break; > + } > + } > + > + if (strstart(key, "0x", NULL)) { > + keycode = strtoul(key, &endp, 0); > + if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) { > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > + if (keycode == key_defs[i]) { > + break; > + } > + } > + } > + } > + > + /* Return Q_KEY_CODE_MAX if the key is invalid */ > + return i; > +} > + > +int index_from_keycode(int code) keycode_from_code() > +{ > + int i; > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > + if (key_defs[i] == code) { > + break; > + } > + } > + /* Return Q_KEY_CODE_MAX if the code is invalid */ > + return i; > +} > + > +static QKeyCodeList *keycodes; > +static QEMUTimer *key_timer; > + > +static void release_keys(void *opaque) > +{ > + int keycode; > + QKeyCodeList *p; > + > + for (p = keycodes; p != NULL; p = p->next) { > + keycode = key_defs[p->value]; > + if (keycode & 0x80) { > + kbd_put_keycode(0xe0); > + } > + kbd_put_keycode(keycode | 0x80); > + } > + qapi_free_QKeyCodeList(keycodes); > + keycodes = NULL; > +} > + > +void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t hold_time, > + Error **errp) > +{ > + int keycode; > + QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL; > + > + if (!key_timer) { > + key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); > + } > + > + if (keycodes != NULL) { > + qemu_del_timer(key_timer); > + release_keys(NULL); > + } > + if (!has_hold_time) { > + hold_time = 100; > + } > + > + for (p = keys; p != NULL; p = p->next) { > + keylist = g_malloc0(sizeof(*keylist)); > + keylist->value = p->value; > + keylist->next = NULL; > + > + if (!head) { > + head = keylist; > + } > + if (tmp) { > + tmp->next = keylist; > + } > + tmp = keylist; > + > + /* key down events */ > + keycode = key_defs[p->value]; > + if (keycode & 0x80) { > + kbd_put_keycode(0xe0); > + } > + kbd_put_keycode(keycode & 0x7f); > + } > + keycodes = head; > + > + /* delayed key up events */ > + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > + muldiv64(get_ticks_per_sec(), hold_time, 1000)); > +} > + > void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void *opaque) > { > qemu_put_kbd_event_opaque = opaque; > diff --git a/monitor.c b/monitor.c > index 4db0c1e..e3a2023 100644 > --- a/monitor.c > +++ b/monitor.c > @@ -1293,252 +1293,6 @@ static void do_sum(Monitor *mon, const QDict *qdict) > monitor_printf(mon, "%05d\n", sum); > } > > -typedef struct { > - int keycode; > - const char *name; > -} KeyDef; > - > -static const KeyDef key_defs[] = { > - { 0x2a, "shift" }, > - { 0x36, "shift_r" }, > - > - { 0x38, "alt" }, > - { 0xb8, "alt_r" }, > - { 0x64, "altgr" }, > - { 0xe4, "altgr_r" }, > - { 0x1d, "ctrl" }, > - { 0x9d, "ctrl_r" }, > - > - { 0xdd, "menu" }, > - > - { 0x01, "esc" }, > - > - { 0x02, "1" }, > - { 0x03, "2" }, > - { 0x04, "3" }, > - { 0x05, "4" }, > - { 0x06, "5" }, > - { 0x07, "6" }, > - { 0x08, "7" }, > - { 0x09, "8" }, > - { 0x0a, "9" }, > - { 0x0b, "0" }, > - { 0x0c, "minus" }, > - { 0x0d, "equal" }, > - { 0x0e, "backspace" }, > - > - { 0x0f, "tab" }, > - { 0x10, "q" }, > - { 0x11, "w" }, > - { 0x12, "e" }, > - { 0x13, "r" }, > - { 0x14, "t" }, > - { 0x15, "y" }, > - { 0x16, "u" }, > - { 0x17, "i" }, > - { 0x18, "o" }, > - { 0x19, "p" }, > - { 0x1a, "bracket_left" }, > - { 0x1b, "bracket_right" }, > - { 0x1c, "ret" }, > - > - { 0x1e, "a" }, > - { 0x1f, "s" }, > - { 0x20, "d" }, > - { 0x21, "f" }, > - { 0x22, "g" }, > - { 0x23, "h" }, > - { 0x24, "j" }, > - { 0x25, "k" }, > - { 0x26, "l" }, > - { 0x27, "semicolon" }, > - { 0x28, "apostrophe" }, > - { 0x29, "grave_accent" }, > - > - { 0x2b, "backslash" }, > - { 0x2c, "z" }, > - { 0x2d, "x" }, > - { 0x2e, "c" }, > - { 0x2f, "v" }, > - { 0x30, "b" }, > - { 0x31, "n" }, > - { 0x32, "m" }, > - { 0x33, "comma" }, > - { 0x34, "dot" }, > - { 0x35, "slash" }, > - > - { 0x37, "asterisk" }, > - > - { 0x39, "spc" }, > - { 0x3a, "caps_lock" }, > - { 0x3b, "f1" }, > - { 0x3c, "f2" }, > - { 0x3d, "f3" }, > - { 0x3e, "f4" }, > - { 0x3f, "f5" }, > - { 0x40, "f6" }, > - { 0x41, "f7" }, > - { 0x42, "f8" }, > - { 0x43, "f9" }, > - { 0x44, "f10" }, > - { 0x45, "num_lock" }, > - { 0x46, "scroll_lock" }, > - > - { 0xb5, "kp_divide" }, > - { 0x37, "kp_multiply" }, > - { 0x4a, "kp_subtract" }, > - { 0x4e, "kp_add" }, > - { 0x9c, "kp_enter" }, > - { 0x53, "kp_decimal" }, > - { 0x54, "sysrq" }, > - > - { 0x52, "kp_0" }, > - { 0x4f, "kp_1" }, > - { 0x50, "kp_2" }, > - { 0x51, "kp_3" }, > - { 0x4b, "kp_4" }, > - { 0x4c, "kp_5" }, > - { 0x4d, "kp_6" }, > - { 0x47, "kp_7" }, > - { 0x48, "kp_8" }, > - { 0x49, "kp_9" }, > - > - { 0x56, "less" }, > - > - { 0x57, "f11" }, > - { 0x58, "f12" }, > - > - { 0xb7, "print" }, > - > - { 0xc7, "home" }, > - { 0xc9, "pgup" }, > - { 0xd1, "pgdn" }, > - { 0xcf, "end" }, > - > - { 0xcb, "left" }, > - { 0xc8, "up" }, > - { 0xd0, "down" }, > - { 0xcd, "right" }, > - > - { 0xd2, "insert" }, > - { 0xd3, "delete" }, > -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > - { 0xf0, "stop" }, > - { 0xf1, "again" }, > - { 0xf2, "props" }, > - { 0xf3, "undo" }, > - { 0xf4, "front" }, > - { 0xf5, "copy" }, > - { 0xf6, "open" }, > - { 0xf7, "paste" }, > - { 0xf8, "find" }, > - { 0xf9, "cut" }, > - { 0xfa, "lf" }, > - { 0xfb, "help" }, > - { 0xfc, "meta_l" }, > - { 0xfd, "meta_r" }, > - { 0xfe, "compose" }, > -#endif > - { 0, NULL }, > -}; > - > -static int get_keycode(const char *key) > -{ > - const KeyDef *p; > - char *endp; > - int ret; > - > - for(p = key_defs; p->name != NULL; p++) { > - if (!strcmp(key, p->name)) > - return p->keycode; > - } > - if (strstart(key, "0x", NULL)) { > - ret = strtoul(key, &endp, 0); > - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) > - return ret; > - } > - return -1; > -} > - > -#define MAX_KEYCODES 16 > -static uint8_t keycodes[MAX_KEYCODES]; > -static int nb_pending_keycodes; > -static QEMUTimer *key_timer; > - > -static void release_keys(void *opaque) > -{ > - int keycode; > - > - 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); > - } > -} > - > -static void do_sendkey(Monitor *mon, const QDict *qdict) > -{ > - char keyname_buf[16]; > - char *separator; > - int keyname_len, keycode, i; > - const char *keys = qdict_get_str(qdict, "keys"); > - int has_hold_time = qdict_haskey(qdict, "hold-time"); > - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > - > - if (nb_pending_keycodes > 0) { > - qemu_del_timer(key_timer); > - release_keys(NULL); > - } > - if (!has_hold_time) > - hold_time = 100; > - i = 0; > - while (1) { > - separator = strchr(keys, '-'); > - keyname_len = separator ? separator - keys : strlen(keys); > - if (keyname_len > 0) { > - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > - if (keyname_len > sizeof(keyname_buf) - 1) { > - monitor_printf(mon, "invalid key: '%s...'\n", keyname_buf); > - return; > - } > - if (i == MAX_KEYCODES) { > - monitor_printf(mon, "too many keys\n"); > - return; > - } > - > - /* Be compatible with old interface, convert user inputted "<" */ > - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { > - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > - keyname_len = 4; > - } > - > - keyname_buf[keyname_len] = 0; > - keycode = get_keycode(keyname_buf); > - if (keycode < 0) { > - monitor_printf(mon, "unknown key: '%s'\n", keyname_buf); > - return; > - } > - keycodes[i++] = keycode; > - } > - if (!separator) > - break; > - keys = separator + 1; > - } > - 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); > - } > - /* delayed key up events */ > - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > - muldiv64(get_ticks_per_sec(), hold_time, 1000)); > -} > - > static int mouse_button_state; > > static void do_mouse_move(Monitor *mon, const QDict *qdict) > @@ -4077,7 +3831,7 @@ static void monitor_find_completion(const char *cmdline) > int nb_args, i, len; > const char *ptype, *str; > const mon_cmd_t *cmd; > - const KeyDef *key; > + const int *code; > > parse_cmdline(cmdline, &nb_args, args); > #ifdef DEBUG_COMPLETION > @@ -4151,9 +3905,14 @@ static void monitor_find_completion(const char *cmdline) > if (sep) > str = sep + 1; > readline_set_completion_index(cur_mon->rs, strlen(str)); > - for(key = key_defs; key->name != NULL; key++) { > - cmd_completion(str, key->name); You can do: cmd_completion(str, KeyCodes_lookup[i]); The loop below is not needed. > + for (code = key_defs; code != NULL; code++) { > + int idx; > + idx = index_from_keycode(*code); > + if (idx != Q_KEY_CODE_MAX) { > + cmd_completion(str, QKeyCode_lookup[idx]); > + } > } > + > } else if (!strcmp(cmd->name, "help|?")) { > readline_set_completion_index(cur_mon->rs, strlen(str)); > for (cmd = mon_cmds; cmd->name != NULL; cmd++) { > @@ -4681,7 +4440,6 @@ void monitor_init(CharDriverState *chr, int flags) > Monitor *mon; > > if (is_first_init) { > - key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL); > monitor_protocol_event_init(); > is_first_init = 0; > } > diff --git a/qapi-schema.json b/qapi-schema.json > index bc55ed2..3a562d8 100644 > --- a/qapi-schema.json > +++ b/qapi-schema.json > @@ -2183,3 +2183,49 @@ > # Since: 0.14.0 > ## > { 'command': 'closefd', 'data': {'fdname': 'str'} } > + > +## > +# @QKeyCode: > +# > +# An enumeration of key name. > +# > +# This is used by the send-key command. > +# > +# Since: 1.2 > +## > +{ 'enum': 'QKeyCode', > + 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', 'altgr_r', 'ctrl', > + 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', '7', '8', > + '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', 'w', 'e', > + 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', 'bracket_right', > + 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'semicolon', > + 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', 'c', 'v', 'b', > + 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', 'caps_lock', > + 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', > + 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', > + 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', 'sysrq', 'kp_0', > + 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', 'kp_7', 'kp_8', > + 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', 'pgdn', 'end', > + 'left', 'up', 'down', 'right', 'insert', 'delete', 'stop', 'again', > + 'props', 'undo', 'front', 'copy', 'open', 'paste', 'find', 'cut', > + 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } > + > +## > +# @send-key: > +# > +# Send keys to guest. > +# > +# @keys: key sequence. 'keys' is the name of the key. Use a JSON array to > +# press several keys simultaneously. > +# > +# @hold-time: #optional time to delay key up events, milliseconds. Defaults > +# to 100 > +# > +# Returns: Nothing on success > +# If key is unknown or redundant, InvalidParameter > +# > +# Since: 1.2 > +# > +## > +{ 'command': 'send-key', > + 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } > diff --git a/qmp-commands.hx b/qmp-commands.hx > index e3cf3c5..3c1e646 100644 > --- a/qmp-commands.hx > +++ b/qmp-commands.hx > @@ -335,6 +335,34 @@ Example: > EQMP > > { > + .name = "send-key", > + .args_type = "keys:O,hold-time:i?", > + .mhandler.cmd_new = qmp_marshal_input_send_key, > + }, > + > +SQMP > +send-key > +---------- > + > +Send keys to VM. > + > +Arguments: > + > +keys array: > + - "key": key sequence (a json-array of key enum values) > + > +- hold-time: time to delay key up events, milliseconds. Defaults to 100 > + (json-int, optional) > + > +Example: > + > +-> { "execute": "send-key", > + "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } } > +<- { "return": {} } > + > +EQMP > + > + { > .name = "cpu", > .args_type = "index:i", > .mhandler.cmd_new = qmp_marshal_input_cpu, ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey 2012-08-02 19:57 ` Luiz Capitulino @ 2012-08-03 1:38 ` Amos Kong 2012-08-03 13:23 ` Luiz Capitulino 0 siblings, 1 reply; 12+ messages in thread From: Amos Kong @ 2012-08-03 1:38 UTC (permalink / raw) To: Luiz Capitulino; +Cc: aliguori, eblake, qemu-devel ----- Original Message ----- > On Thu, 26 Jul 2012 12:49:01 +0800 > Amos Kong <akong@redhat.com> wrote: > > > Convert 'sendkey' to use QAPI. > > > > Keys' indexes in the enmu are same as keycodes' indexes in the > > key_defs[], index_from_code() and index_from_key() will return > > Q_KEY_CODE_MAX if the code/key is invalid. > > > > For qmp, QAPI would check invalid key and raise error. > > For hmp, invalid key is checked in hmp_send_key(). > > > > 'send-key' of QMP doesn't support key in hexadecimal format. > > > > Signed-off-by: Amos Kong <akong@redhat.com> > > I've some review comments below, besides I'd like to ask you to split > the addition of the QKeyCode enum and the key_defs table moving to a > different patch. Ok. > Other than that this looks quite better, hopefully v6 will be the > last one. Thanks for your time :) > > --- > > console.h | 5 + > > hmp-commands.hx | 2 +- > > hmp.c | 55 ++++++++++++ > > hmp.h | 1 + > > input.c | 249 > > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > > monitor.c | 258 > > ++---------------------------------------------------- > > qapi-schema.json | 46 ++++++++++ > > qmp-commands.hx | 28 ++++++ > > 8 files changed, 393 insertions(+), 251 deletions(-) > > > > diff --git a/console.h b/console.h > > index 4334db5..b2d7af6 100644 > > --- a/console.h > > +++ b/console.h > > @@ -6,6 +6,7 @@ > > #include "notify.h" > > #include "monitor.h" > > #include "trace.h" > > +#include "qapi-types.h" > > > > /* keyboard/mouse support */ > > > > @@ -397,4 +398,8 @@ static inline int > > vnc_display_pw_expire(DisplayState *ds, time_t expires) > > /* curses.c */ > > void curses_display_init(DisplayState *ds, int full_screen); > > > > +/* input.c */ > > +extern const int key_defs[]; > > +int index_from_key(const char *key); > > +int index_from_keycode(int code); > > #endif > > diff --git a/hmp-commands.hx b/hmp-commands.hx > > index 2891d48..8c2be24 100644 > > --- a/hmp-commands.hx > > +++ b/hmp-commands.hx > > @@ -505,7 +505,7 @@ ETEXI > > .args_type = "keys:s,hold-time:i?", > > .params = "keys [hold_ms]", > > .help = "send keys to the VM (e.g. 'sendkey > > ctrl-alt-f1', default hold time=100 ms)", > > - .mhandler.cmd = do_sendkey, > > + .mhandler.cmd = hmp_send_key, > > }, > > > > STEXI > > diff --git a/hmp.c b/hmp.c > > index 6b72a64..041555a 100644 > > --- a/hmp.c > > +++ b/hmp.c > > @@ -19,6 +19,7 @@ > > #include "qemu-timer.h" > > #include "qmp-commands.h" > > #include "monitor.h" > > +#include "console.h" > > > > static void hmp_handle_error(Monitor *mon, Error **errp) > > { > > @@ -1020,3 +1021,57 @@ void hmp_closefd(Monitor *mon, const QDict > > *qdict) > > qmp_closefd(fdname, &errp); > > hmp_handle_error(mon, &errp); > > } > > + > > +void hmp_send_key(Monitor *mon, const QDict *qdict) > > +{ > > + const char *keys = qdict_get_str(qdict, "keys"); > > + QKeyCodeList *keylist, *head = NULL, *tmp = NULL; > > + int has_hold_time = qdict_haskey(qdict, "hold-time"); > > + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > > + Error *err = NULL; > > + char keyname_buf[16]; > > + char *separator; > > + int keyname_len, idx; > > + > > + while (1) { > > + separator = strchr(keys, '-'); > > + keyname_len = separator ? separator - keys : strlen(keys); > > + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > > + > > + /* Be compatible with old interface, convert user inputted > > "<" */ > > + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { > > + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > > + keyname_len = 4; > > + } > > + keyname_buf[keyname_len] = 0; > > + > > + idx = index_from_key(keyname_buf); > > + if (idx == Q_KEY_CODE_MAX) { > > + error_set(&err, QERR_INVALID_PARAMETER, keyname_buf); > > No need to use error_set(), you can call monitor_printf() directly. Nod. > > + break; > > + } > > + > > + keylist = g_malloc0(sizeof(*keylist)); > > + keylist->value = idx; > > + keylist->next = NULL; > > + > > + if (!head) { > > + head = keylist; > > + } > > + if (tmp) { > > + tmp->next = keylist; > > + } > > + tmp = keylist; > > + > > + if (!separator) { > > + break; > > + } > > + keys = separator + 1; > > + } > > + > > + if (idx != Q_KEY_CODE_MAX) { > > + qmp_send_key(head, has_hold_time, hold_time, &err); > > + } > > + hmp_handle_error(mon, &err); > > + qapi_free_QKeyCodeList(head); > > +} > > diff --git a/hmp.h b/hmp.h > > index 8d2b0d7..56d67a3 100644 > > --- a/hmp.h > > +++ b/hmp.h > > @@ -66,5 +66,6 @@ void hmp_netdev_add(Monitor *mon, const QDict > > *qdict); > > void hmp_netdev_del(Monitor *mon, const QDict *qdict); > > void hmp_getfd(Monitor *mon, const QDict *qdict); > > void hmp_closefd(Monitor *mon, const QDict *qdict); > > +void hmp_send_key(Monitor *mon, const QDict *qdict); > > > > #endif > > diff --git a/input.c b/input.c > > index 6968b31..2286581 100644 > > --- a/input.c > > +++ b/input.c > > @@ -28,6 +28,7 @@ > > #include "console.h" > > #include "error.h" > > #include "qmp-commands.h" > > +#include "qapi-types.h" > > > > static QEMUPutKBDEvent *qemu_put_kbd_event; > > static void *qemu_put_kbd_event_opaque; > > @@ -37,6 +38,254 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) > > mouse_handlers = > > static NotifierList mouse_mode_notifiers = > > NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); > > > > +const int key_defs[] = { > > Please, make key_defs static. > > + [Q_KEY_CODE_SHIFT] = 0x2a, > > + [Q_KEY_CODE_SHIFT_R] = 0x36, > > + > > + [Q_KEY_CODE_ALT] = 0x38, > > + [Q_KEY_CODE_ALT_R] = 0xb8, > > + [Q_KEY_CODE_ALTGR] = 0x64, > > + [Q_KEY_CODE_ALTGR_R] = 0xe4, > > + [Q_KEY_CODE_CTRL] = 0x1d, > > + [Q_KEY_CODE_CTRL_R] = 0x9d, > > + > > + [Q_KEY_CODE_MENU] = 0xdd, > > + > > + [Q_KEY_CODE_ESC] = 0x01, > > + > > + [Q_KEY_CODE_1] = 0x02, > > + [Q_KEY_CODE_2] = 0x03, > > + [Q_KEY_CODE_3] = 0x04, > > + [Q_KEY_CODE_4] = 0x05, > > + [Q_KEY_CODE_5] = 0x06, > > + [Q_KEY_CODE_6] = 0x07, > > + [Q_KEY_CODE_7] = 0x08, > > + [Q_KEY_CODE_8] = 0x09, > > + [Q_KEY_CODE_9] = 0x0a, > > + [Q_KEY_CODE_0] = 0x0b, > > + [Q_KEY_CODE_MINUS] = 0x0c, > > + [Q_KEY_CODE_EQUAL] = 0x0d, > > + [Q_KEY_CODE_BACKSPACE] = 0x0e, > > + > > + [Q_KEY_CODE_TAB] = 0x0f, > > + [Q_KEY_CODE_Q] = 0x10, > > + [Q_KEY_CODE_W] = 0x11, > > + [Q_KEY_CODE_E] = 0x12, > > + [Q_KEY_CODE_R] = 0x13, > > + [Q_KEY_CODE_T] = 0x14, > > + [Q_KEY_CODE_Y] = 0x15, > > + [Q_KEY_CODE_U] = 0x16, > > + [Q_KEY_CODE_I] = 0x17, > > + [Q_KEY_CODE_O] = 0x18, > > + [Q_KEY_CODE_P] = 0x19, > > + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, > > + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, > > + [Q_KEY_CODE_RET] = 0x1c, > > + > > + [Q_KEY_CODE_A] = 0x1e, > > + [Q_KEY_CODE_S] = 0x1f, > > + [Q_KEY_CODE_D] = 0x20, > > + [Q_KEY_CODE_F] = 0x21, > > + [Q_KEY_CODE_G] = 0x22, > > + [Q_KEY_CODE_H] = 0x23, > > + [Q_KEY_CODE_J] = 0x24, > > + [Q_KEY_CODE_K] = 0x25, > > + [Q_KEY_CODE_L] = 0x26, > > + [Q_KEY_CODE_SEMICOLON] = 0x27, > > + [Q_KEY_CODE_APOSTROPHE] = 0x28, > > + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, > > + > > + [Q_KEY_CODE_BACKSLASH] = 0x2b, > > + [Q_KEY_CODE_Z] = 0x2c, > > + [Q_KEY_CODE_X] = 0x2d, > > + [Q_KEY_CODE_C] = 0x2e, > > + [Q_KEY_CODE_V] = 0x2f, > > + [Q_KEY_CODE_B] = 0x30, > > + [Q_KEY_CODE_N] = 0x31, > > + [Q_KEY_CODE_M] = 0x32, > > + [Q_KEY_CODE_COMMA] = 0x33, > > + [Q_KEY_CODE_DOT] = 0x34, > > + [Q_KEY_CODE_SLASH] = 0x35, > > + > > + [Q_KEY_CODE_ASTERISK] = 0x37, > > + > > + [Q_KEY_CODE_SPC] = 0x39, > > + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, > > + [Q_KEY_CODE_F1] = 0x3b, > > + [Q_KEY_CODE_F2] = 0x3c, > > + [Q_KEY_CODE_F3] = 0x3d, > > + [Q_KEY_CODE_F4] = 0x3e, > > + [Q_KEY_CODE_F5] = 0x3f, > > + [Q_KEY_CODE_F6] = 0x40, > > + [Q_KEY_CODE_F7] = 0x41, > > + [Q_KEY_CODE_F8] = 0x42, > > + [Q_KEY_CODE_F9] = 0x43, > > + [Q_KEY_CODE_F10] = 0x44, > > + [Q_KEY_CODE_NUM_LOCK] = 0x45, > > + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, > > + > > + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, > > + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, > > + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, > > + [Q_KEY_CODE_KP_ADD] = 0x4e, > > + [Q_KEY_CODE_KP_ENTER] = 0x9c, > > + [Q_KEY_CODE_KP_DECIMAL] = 0x53, > > + [Q_KEY_CODE_SYSRQ] = 0x54, > > + > > + [Q_KEY_CODE_KP_0] = 0x52, > > + [Q_KEY_CODE_KP_1] = 0x4f, > > + [Q_KEY_CODE_KP_2] = 0x50, > > + [Q_KEY_CODE_KP_3] = 0x51, > > + [Q_KEY_CODE_KP_4] = 0x4b, > > + [Q_KEY_CODE_KP_5] = 0x4c, > > + [Q_KEY_CODE_KP_6] = 0x4d, > > + [Q_KEY_CODE_KP_7] = 0x47, > > + [Q_KEY_CODE_KP_8] = 0x48, > > + [Q_KEY_CODE_KP_9] = 0x49, > > + > > + [Q_KEY_CODE_LESS] = 0x56, > > + > > + [Q_KEY_CODE_F11] = 0x57, > > + [Q_KEY_CODE_F12] = 0x58, > > + > > + [Q_KEY_CODE_PRINT] = 0xb7, > > + > > + [Q_KEY_CODE_HOME] = 0xc7, > > + [Q_KEY_CODE_PGUP] = 0xc9, > > + [Q_KEY_CODE_PGDN] = 0xd1, > > + [Q_KEY_CODE_END] = 0xcf, > > + > > + [Q_KEY_CODE_LEFT] = 0xcb, > > + [Q_KEY_CODE_UP] = 0xc8, > > + [Q_KEY_CODE_DOWN] = 0xd0, > > + [Q_KEY_CODE_RIGHT] = 0xcd, > > + > > + [Q_KEY_CODE_INSERT] = 0xd2, > > + [Q_KEY_CODE_DELETE] = 0xd3, > > +#ifdef NEED_CPU_H > > +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > > + [Q_KEY_CODE_STOP] = 0xf0, > > + [Q_KEY_CODE_AGAIN] = 0xf1, > > + [Q_KEY_CODE_PROPS] = 0xf2, > > + [Q_KEY_CODE_UNDO] = 0xf3, > > + [Q_KEY_CODE_FRONT] = 0xf4, > > + [Q_KEY_CODE_COPY] = 0xf5, > > + [Q_KEY_CODE_OPEN] = 0xf6, > > + [Q_KEY_CODE_PASTE] = 0xf7, > > + [Q_KEY_CODE_FIND] = 0xf8, > > + [Q_KEY_CODE_CUT] = 0xf9, > > + [Q_KEY_CODE_LF] = 0xfa, > > + [Q_KEY_CODE_HELP] = 0xfb, > > + [Q_KEY_CODE_META_L] = 0xfc, > > + [Q_KEY_CODE_META_R] = 0xfd, > > + [Q_KEY_CODE_COMPOSE] = 0xfe, > > +#endif > > +#endif > > + [Q_KEY_CODE_MAX] = 0, > > +}; > > + > > +int index_from_key(const char *key) > > keycode_from_key() is better. QAPI passes 'index' to qmp_send_key(), not value (keycode) So what those two functions return should be the 'index' of key_defs, not the value (keycode). 'Index' will be converted to 'keycode' insider qmp_send_key() > > +{ > > + int i, keycode; > > + char *endp; > > + > > + for (i = 0; QKeyCode_lookup[i] != NULL; i++) { > > + if (!strcmp(key, QKeyCode_lookup[i])) { > > + break; > > + } > > + } > > + > > + if (strstart(key, "0x", NULL)) { > > + keycode = strtoul(key, &endp, 0); > > + if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) { > > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > > + if (keycode == key_defs[i]) { > > + break; > > + } > > + } > > + } > > + } > > + > > + /* Return Q_KEY_CODE_MAX if the key is invalid */ > > + return i; > > +} > > + > > +int index_from_keycode(int code) > > keycode_from_code() > > > +{ > > + int i; > > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > > + if (key_defs[i] == code) { > > + break; > > + } > > + } > > + /* Return Q_KEY_CODE_MAX if the code is invalid */ > > + return i; > > +} > > + > > +static QKeyCodeList *keycodes; > > +static QEMUTimer *key_timer; > > + > > +static void release_keys(void *opaque) > > +{ > > + int keycode; > > + QKeyCodeList *p; > > + > > + for (p = keycodes; p != NULL; p = p->next) { > > + keycode = key_defs[p->value]; > > + if (keycode & 0x80) { > > + kbd_put_keycode(0xe0); > > + } > > + kbd_put_keycode(keycode | 0x80); > > + } > > + qapi_free_QKeyCodeList(keycodes); > > + keycodes = NULL; > > +} > > + > > +void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t > > hold_time, > > + Error **errp) > > +{ > > + int keycode; > > + QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL; > > + > > + if (!key_timer) { > > + key_timer = qemu_new_timer_ns(vm_clock, release_keys, > > NULL); > > + } > > + > > + if (keycodes != NULL) { > > + qemu_del_timer(key_timer); > > + release_keys(NULL); > > + } > > + if (!has_hold_time) { > > + hold_time = 100; > > + } > > + > > + for (p = keys; p != NULL; p = p->next) { > > + keylist = g_malloc0(sizeof(*keylist)); > > + keylist->value = p->value; > > + keylist->next = NULL; > > + > > + if (!head) { > > + head = keylist; > > + } > > + if (tmp) { > > + tmp->next = keylist; > > + } > > + tmp = keylist; > > + > > + /* key down events */ > > + keycode = key_defs[p->value]; > > + if (keycode & 0x80) { > > + kbd_put_keycode(0xe0); > > + } > > + kbd_put_keycode(keycode & 0x7f); > > + } > > + keycodes = head; > > + > > + /* delayed key up events */ > > + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > > + muldiv64(get_ticks_per_sec(), hold_time, > > 1000)); > > +} > > + > > void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void > > *opaque) > > { > > qemu_put_kbd_event_opaque = opaque; > > diff --git a/monitor.c b/monitor.c > > index 4db0c1e..e3a2023 100644 > > --- a/monitor.c > > +++ b/monitor.c > > @@ -1293,252 +1293,6 @@ static void do_sum(Monitor *mon, const > > QDict *qdict) > > monitor_printf(mon, "%05d\n", sum); > > } > > > > -typedef struct { > > - int keycode; > > - const char *name; > > -} KeyDef; > > - > > -static const KeyDef key_defs[] = { > > - { 0x2a, "shift" }, > > - { 0x36, "shift_r" }, > > - > > - { 0x38, "alt" }, > > - { 0xb8, "alt_r" }, > > - { 0x64, "altgr" }, > > - { 0xe4, "altgr_r" }, > > - { 0x1d, "ctrl" }, > > - { 0x9d, "ctrl_r" }, > > - > > - { 0xdd, "menu" }, > > - > > - { 0x01, "esc" }, > > - > > - { 0x02, "1" }, > > - { 0x03, "2" }, > > - { 0x04, "3" }, > > - { 0x05, "4" }, > > - { 0x06, "5" }, > > - { 0x07, "6" }, > > - { 0x08, "7" }, > > - { 0x09, "8" }, > > - { 0x0a, "9" }, > > - { 0x0b, "0" }, > > - { 0x0c, "minus" }, > > - { 0x0d, "equal" }, > > - { 0x0e, "backspace" }, > > - > > - { 0x0f, "tab" }, > > - { 0x10, "q" }, > > - { 0x11, "w" }, > > - { 0x12, "e" }, > > - { 0x13, "r" }, > > - { 0x14, "t" }, > > - { 0x15, "y" }, > > - { 0x16, "u" }, > > - { 0x17, "i" }, > > - { 0x18, "o" }, > > - { 0x19, "p" }, > > - { 0x1a, "bracket_left" }, > > - { 0x1b, "bracket_right" }, > > - { 0x1c, "ret" }, > > - > > - { 0x1e, "a" }, > > - { 0x1f, "s" }, > > - { 0x20, "d" }, > > - { 0x21, "f" }, > > - { 0x22, "g" }, > > - { 0x23, "h" }, > > - { 0x24, "j" }, > > - { 0x25, "k" }, > > - { 0x26, "l" }, > > - { 0x27, "semicolon" }, > > - { 0x28, "apostrophe" }, > > - { 0x29, "grave_accent" }, > > - > > - { 0x2b, "backslash" }, > > - { 0x2c, "z" }, > > - { 0x2d, "x" }, > > - { 0x2e, "c" }, > > - { 0x2f, "v" }, > > - { 0x30, "b" }, > > - { 0x31, "n" }, > > - { 0x32, "m" }, > > - { 0x33, "comma" }, > > - { 0x34, "dot" }, > > - { 0x35, "slash" }, > > - > > - { 0x37, "asterisk" }, > > - > > - { 0x39, "spc" }, > > - { 0x3a, "caps_lock" }, > > - { 0x3b, "f1" }, > > - { 0x3c, "f2" }, > > - { 0x3d, "f3" }, > > - { 0x3e, "f4" }, > > - { 0x3f, "f5" }, > > - { 0x40, "f6" }, > > - { 0x41, "f7" }, > > - { 0x42, "f8" }, > > - { 0x43, "f9" }, > > - { 0x44, "f10" }, > > - { 0x45, "num_lock" }, > > - { 0x46, "scroll_lock" }, > > - > > - { 0xb5, "kp_divide" }, > > - { 0x37, "kp_multiply" }, > > - { 0x4a, "kp_subtract" }, > > - { 0x4e, "kp_add" }, > > - { 0x9c, "kp_enter" }, > > - { 0x53, "kp_decimal" }, > > - { 0x54, "sysrq" }, > > - > > - { 0x52, "kp_0" }, > > - { 0x4f, "kp_1" }, > > - { 0x50, "kp_2" }, > > - { 0x51, "kp_3" }, > > - { 0x4b, "kp_4" }, > > - { 0x4c, "kp_5" }, > > - { 0x4d, "kp_6" }, > > - { 0x47, "kp_7" }, > > - { 0x48, "kp_8" }, > > - { 0x49, "kp_9" }, > > - > > - { 0x56, "less" }, > > - > > - { 0x57, "f11" }, > > - { 0x58, "f12" }, > > - > > - { 0xb7, "print" }, > > - > > - { 0xc7, "home" }, > > - { 0xc9, "pgup" }, > > - { 0xd1, "pgdn" }, > > - { 0xcf, "end" }, > > - > > - { 0xcb, "left" }, > > - { 0xc8, "up" }, > > - { 0xd0, "down" }, > > - { 0xcd, "right" }, > > - > > - { 0xd2, "insert" }, > > - { 0xd3, "delete" }, > > -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > > - { 0xf0, "stop" }, > > - { 0xf1, "again" }, > > - { 0xf2, "props" }, > > - { 0xf3, "undo" }, > > - { 0xf4, "front" }, > > - { 0xf5, "copy" }, > > - { 0xf6, "open" }, > > - { 0xf7, "paste" }, > > - { 0xf8, "find" }, > > - { 0xf9, "cut" }, > > - { 0xfa, "lf" }, > > - { 0xfb, "help" }, > > - { 0xfc, "meta_l" }, > > - { 0xfd, "meta_r" }, > > - { 0xfe, "compose" }, > > -#endif > > - { 0, NULL }, > > -}; > > - > > -static int get_keycode(const char *key) > > -{ > > - const KeyDef *p; > > - char *endp; > > - int ret; > > - > > - for(p = key_defs; p->name != NULL; p++) { > > - if (!strcmp(key, p->name)) > > - return p->keycode; > > - } > > - if (strstart(key, "0x", NULL)) { > > - ret = strtoul(key, &endp, 0); > > - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) > > - return ret; > > - } > > - return -1; > > -} > > - > > -#define MAX_KEYCODES 16 > > -static uint8_t keycodes[MAX_KEYCODES]; > > -static int nb_pending_keycodes; > > -static QEMUTimer *key_timer; > > - > > -static void release_keys(void *opaque) > > -{ > > - int keycode; > > - > > - 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); > > - } > > -} > > - > > -static void do_sendkey(Monitor *mon, const QDict *qdict) > > -{ > > - char keyname_buf[16]; > > - char *separator; > > - int keyname_len, keycode, i; > > - const char *keys = qdict_get_str(qdict, "keys"); > > - int has_hold_time = qdict_haskey(qdict, "hold-time"); > > - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > > - > > - if (nb_pending_keycodes > 0) { > > - qemu_del_timer(key_timer); > > - release_keys(NULL); > > - } > > - if (!has_hold_time) > > - hold_time = 100; > > - i = 0; > > - while (1) { > > - separator = strchr(keys, '-'); > > - keyname_len = separator ? separator - keys : strlen(keys); > > - if (keyname_len > 0) { > > - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > > - if (keyname_len > sizeof(keyname_buf) - 1) { > > - monitor_printf(mon, "invalid key: '%s...'\n", > > keyname_buf); > > - return; > > - } > > - if (i == MAX_KEYCODES) { > > - monitor_printf(mon, "too many keys\n"); > > - return; > > - } > > - > > - /* Be compatible with old interface, convert user > > inputted "<" */ > > - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) > > { > > - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > > - keyname_len = 4; > > - } > > - > > - keyname_buf[keyname_len] = 0; > > - keycode = get_keycode(keyname_buf); > > - if (keycode < 0) { > > - monitor_printf(mon, "unknown key: '%s'\n", > > keyname_buf); > > - return; > > - } > > - keycodes[i++] = keycode; > > - } > > - if (!separator) > > - break; > > - keys = separator + 1; > > - } > > - 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); > > - } > > - /* delayed key up events */ > > - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > > - muldiv64(get_ticks_per_sec(), hold_time, > > 1000)); > > -} > > - > > static int mouse_button_state; > > > > static void do_mouse_move(Monitor *mon, const QDict *qdict) > > @@ -4077,7 +3831,7 @@ static void monitor_find_completion(const > > char *cmdline) > > int nb_args, i, len; > > const char *ptype, *str; > > const mon_cmd_t *cmd; > > - const KeyDef *key; > > + const int *code; > > > > parse_cmdline(cmdline, &nb_args, args); > > #ifdef DEBUG_COMPLETION > > @@ -4151,9 +3905,14 @@ static void monitor_find_completion(const > > char *cmdline) > > if (sep) > > str = sep + 1; > > readline_set_completion_index(cur_mon->rs, > > strlen(str)); > > - for(key = key_defs; key->name != NULL; key++) { > > - cmd_completion(str, key->name); > > You can do: > > cmd_completion(str, KeyCodes_lookup[i]); > > The loop below is not needed. This is enough, then we can make key_defs static. for (i = 0; i < Q_KEY_CODE_MAX; i++) { cmd_completion(str, QKeyCode_lookup[i]); } > > + for (code = key_defs; code != NULL; code++) { > > + int idx; > > + idx = index_from_keycode(*code); > > + if (idx != Q_KEY_CODE_MAX) { > > + cmd_completion(str, QKeyCode_lookup[idx]); > > + } > > } > > + > > } else if (!strcmp(cmd->name, "help|?")) { > > readline_set_completion_index(cur_mon->rs, > > strlen(str)); > > for (cmd = mon_cmds; cmd->name != NULL; cmd++) { > > @@ -4681,7 +4440,6 @@ void monitor_init(CharDriverState *chr, int > > flags) > > Monitor *mon; > > > > if (is_first_init) { > > - key_timer = qemu_new_timer_ns(vm_clock, release_keys, > > NULL); > > monitor_protocol_event_init(); > > is_first_init = 0; > > } > > diff --git a/qapi-schema.json b/qapi-schema.json > > index bc55ed2..3a562d8 100644 > > --- a/qapi-schema.json > > +++ b/qapi-schema.json > > @@ -2183,3 +2183,49 @@ > > # Since: 0.14.0 > > ## > > { 'command': 'closefd', 'data': {'fdname': 'str'} } > > + > > +## > > +# @QKeyCode: > > +# > > +# An enumeration of key name. > > +# > > +# This is used by the send-key command. > > +# > > +# Since: 1.2 > > +## > > +{ 'enum': 'QKeyCode', > > + 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', > > 'altgr_r', 'ctrl', > > + 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', > > '7', '8', > > + '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', > > 'w', 'e', > > + 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', > > 'bracket_right', > > + 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', > > 'semicolon', > > + 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', > > 'c', 'v', 'b', > > + 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', > > 'caps_lock', > > + 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', > > 'f10', > > + 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', > > + 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', > > 'sysrq', 'kp_0', > > + 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', > > 'kp_7', 'kp_8', > > + 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', > > 'pgdn', 'end', > > + 'left', 'up', 'down', 'right', 'insert', 'delete', > > 'stop', 'again', > > + 'props', 'undo', 'front', 'copy', 'open', 'paste', > > 'find', 'cut', > > + 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } > > + > > +## > > +# @send-key: > > +# > > +# Send keys to guest. > > +# > > +# @keys: key sequence. 'keys' is the name of the key. Use a JSON > > array to > > +# press several keys simultaneously. > > +# > > +# @hold-time: #optional time to delay key up events, milliseconds. > > Defaults > > +# to 100 > > +# > > +# Returns: Nothing on success > > +# If key is unknown or redundant, InvalidParameter > > +# > > +# Since: 1.2 > > +# > > +## > > +{ 'command': 'send-key', > > + 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } > > diff --git a/qmp-commands.hx b/qmp-commands.hx > > index e3cf3c5..3c1e646 100644 > > --- a/qmp-commands.hx > > +++ b/qmp-commands.hx > > @@ -335,6 +335,34 @@ Example: > > EQMP > > > > { > > + .name = "send-key", > > + .args_type = "keys:O,hold-time:i?", > > + .mhandler.cmd_new = qmp_marshal_input_send_key, > > + }, > > + > > +SQMP > > +send-key > > +---------- > > + > > +Send keys to VM. > > + > > +Arguments: > > + > > +keys array: > > + - "key": key sequence (a json-array of key enum values) > > + > > +- hold-time: time to delay key up events, milliseconds. Defaults > > to 100 > > + (json-int, optional) > > + > > +Example: > > + > > +-> { "execute": "send-key", > > + "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } } > > +<- { "return": {} } > > + > > +EQMP > > + > > + { > > .name = "cpu", > > .args_type = "index:i", > > .mhandler.cmd_new = qmp_marshal_input_cpu, > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey 2012-08-03 1:38 ` Amos Kong @ 2012-08-03 13:23 ` Luiz Capitulino 0 siblings, 0 replies; 12+ messages in thread From: Luiz Capitulino @ 2012-08-03 13:23 UTC (permalink / raw) To: Amos Kong; +Cc: aliguori, eblake, qemu-devel On Thu, 2 Aug 2012 21:38:00 -0400 (EDT) Amos Kong <akong@redhat.com> wrote: > ----- Original Message ----- > > On Thu, 26 Jul 2012 12:49:01 +0800 > > Amos Kong <akong@redhat.com> wrote: > > > > > Convert 'sendkey' to use QAPI. > > > > > > Keys' indexes in the enmu are same as keycodes' indexes in the > > > key_defs[], index_from_code() and index_from_key() will return > > > Q_KEY_CODE_MAX if the code/key is invalid. > > > > > > For qmp, QAPI would check invalid key and raise error. > > > For hmp, invalid key is checked in hmp_send_key(). > > > > > > 'send-key' of QMP doesn't support key in hexadecimal format. > > > > > > Signed-off-by: Amos Kong <akong@redhat.com> > > > > I've some review comments below, besides I'd like to ask you to split > > the addition of the QKeyCode enum and the key_defs table moving to a > > different patch. > > Ok. > > > Other than that this looks quite better, hopefully v6 will be the > > last one. > > Thanks for your time :) > > > > --- > > > console.h | 5 + > > > hmp-commands.hx | 2 +- > > > hmp.c | 55 ++++++++++++ > > > hmp.h | 1 + > > > input.c | 249 > > > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > > > monitor.c | 258 > > > ++---------------------------------------------------- > > > qapi-schema.json | 46 ++++++++++ > > > qmp-commands.hx | 28 ++++++ > > > 8 files changed, 393 insertions(+), 251 deletions(-) > > > > > > diff --git a/console.h b/console.h > > > index 4334db5..b2d7af6 100644 > > > --- a/console.h > > > +++ b/console.h > > > @@ -6,6 +6,7 @@ > > > #include "notify.h" > > > #include "monitor.h" > > > #include "trace.h" > > > +#include "qapi-types.h" > > > > > > /* keyboard/mouse support */ > > > > > > @@ -397,4 +398,8 @@ static inline int > > > vnc_display_pw_expire(DisplayState *ds, time_t expires) > > > /* curses.c */ > > > void curses_display_init(DisplayState *ds, int full_screen); > > > > > > +/* input.c */ > > > +extern const int key_defs[]; > > > +int index_from_key(const char *key); > > > +int index_from_keycode(int code); > > > #endif > > > diff --git a/hmp-commands.hx b/hmp-commands.hx > > > index 2891d48..8c2be24 100644 > > > --- a/hmp-commands.hx > > > +++ b/hmp-commands.hx > > > @@ -505,7 +505,7 @@ ETEXI > > > .args_type = "keys:s,hold-time:i?", > > > .params = "keys [hold_ms]", > > > .help = "send keys to the VM (e.g. 'sendkey > > > ctrl-alt-f1', default hold time=100 ms)", > > > - .mhandler.cmd = do_sendkey, > > > + .mhandler.cmd = hmp_send_key, > > > }, > > > > > > STEXI > > > diff --git a/hmp.c b/hmp.c > > > index 6b72a64..041555a 100644 > > > --- a/hmp.c > > > +++ b/hmp.c > > > @@ -19,6 +19,7 @@ > > > #include "qemu-timer.h" > > > #include "qmp-commands.h" > > > #include "monitor.h" > > > +#include "console.h" > > > > > > static void hmp_handle_error(Monitor *mon, Error **errp) > > > { > > > @@ -1020,3 +1021,57 @@ void hmp_closefd(Monitor *mon, const QDict > > > *qdict) > > > qmp_closefd(fdname, &errp); > > > hmp_handle_error(mon, &errp); > > > } > > > + > > > +void hmp_send_key(Monitor *mon, const QDict *qdict) > > > +{ > > > + const char *keys = qdict_get_str(qdict, "keys"); > > > + QKeyCodeList *keylist, *head = NULL, *tmp = NULL; > > > + int has_hold_time = qdict_haskey(qdict, "hold-time"); > > > + int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > > > + Error *err = NULL; > > > + char keyname_buf[16]; > > > + char *separator; > > > + int keyname_len, idx; > > > + > > > + while (1) { > > > + separator = strchr(keys, '-'); > > > + keyname_len = separator ? separator - keys : strlen(keys); > > > + pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > > > + > > > + /* Be compatible with old interface, convert user inputted > > > "<" */ > > > + if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) { > > > + pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > > > + keyname_len = 4; > > > + } > > > + keyname_buf[keyname_len] = 0; > > > + > > > + idx = index_from_key(keyname_buf); > > > + if (idx == Q_KEY_CODE_MAX) { > > > + error_set(&err, QERR_INVALID_PARAMETER, keyname_buf); > > > > No need to use error_set(), you can call monitor_printf() directly. > > Nod. > > > > + break; > > > + } > > > + > > > + keylist = g_malloc0(sizeof(*keylist)); > > > + keylist->value = idx; > > > + keylist->next = NULL; > > > + > > > + if (!head) { > > > + head = keylist; > > > + } > > > + if (tmp) { > > > + tmp->next = keylist; > > > + } > > > + tmp = keylist; > > > + > > > + if (!separator) { > > > + break; > > > + } > > > + keys = separator + 1; > > > + } > > > + > > > + if (idx != Q_KEY_CODE_MAX) { > > > + qmp_send_key(head, has_hold_time, hold_time, &err); > > > + } > > > + hmp_handle_error(mon, &err); > > > + qapi_free_QKeyCodeList(head); > > > +} > > > diff --git a/hmp.h b/hmp.h > > > index 8d2b0d7..56d67a3 100644 > > > --- a/hmp.h > > > +++ b/hmp.h > > > @@ -66,5 +66,6 @@ void hmp_netdev_add(Monitor *mon, const QDict > > > *qdict); > > > void hmp_netdev_del(Monitor *mon, const QDict *qdict); > > > void hmp_getfd(Monitor *mon, const QDict *qdict); > > > void hmp_closefd(Monitor *mon, const QDict *qdict); > > > +void hmp_send_key(Monitor *mon, const QDict *qdict); > > > > > > #endif > > > diff --git a/input.c b/input.c > > > index 6968b31..2286581 100644 > > > --- a/input.c > > > +++ b/input.c > > > @@ -28,6 +28,7 @@ > > > #include "console.h" > > > #include "error.h" > > > #include "qmp-commands.h" > > > +#include "qapi-types.h" > > > > > > static QEMUPutKBDEvent *qemu_put_kbd_event; > > > static void *qemu_put_kbd_event_opaque; > > > @@ -37,6 +38,254 @@ static QTAILQ_HEAD(, QEMUPutMouseEntry) > > > mouse_handlers = > > > static NotifierList mouse_mode_notifiers = > > > NOTIFIER_LIST_INITIALIZER(mouse_mode_notifiers); > > > > > > +const int key_defs[] = { > > > > Please, make key_defs static. > > > > > > + [Q_KEY_CODE_SHIFT] = 0x2a, > > > + [Q_KEY_CODE_SHIFT_R] = 0x36, > > > + > > > + [Q_KEY_CODE_ALT] = 0x38, > > > + [Q_KEY_CODE_ALT_R] = 0xb8, > > > + [Q_KEY_CODE_ALTGR] = 0x64, > > > + [Q_KEY_CODE_ALTGR_R] = 0xe4, > > > + [Q_KEY_CODE_CTRL] = 0x1d, > > > + [Q_KEY_CODE_CTRL_R] = 0x9d, > > > + > > > + [Q_KEY_CODE_MENU] = 0xdd, > > > + > > > + [Q_KEY_CODE_ESC] = 0x01, > > > + > > > + [Q_KEY_CODE_1] = 0x02, > > > + [Q_KEY_CODE_2] = 0x03, > > > + [Q_KEY_CODE_3] = 0x04, > > > + [Q_KEY_CODE_4] = 0x05, > > > + [Q_KEY_CODE_5] = 0x06, > > > + [Q_KEY_CODE_6] = 0x07, > > > + [Q_KEY_CODE_7] = 0x08, > > > + [Q_KEY_CODE_8] = 0x09, > > > + [Q_KEY_CODE_9] = 0x0a, > > > + [Q_KEY_CODE_0] = 0x0b, > > > + [Q_KEY_CODE_MINUS] = 0x0c, > > > + [Q_KEY_CODE_EQUAL] = 0x0d, > > > + [Q_KEY_CODE_BACKSPACE] = 0x0e, > > > + > > > + [Q_KEY_CODE_TAB] = 0x0f, > > > + [Q_KEY_CODE_Q] = 0x10, > > > + [Q_KEY_CODE_W] = 0x11, > > > + [Q_KEY_CODE_E] = 0x12, > > > + [Q_KEY_CODE_R] = 0x13, > > > + [Q_KEY_CODE_T] = 0x14, > > > + [Q_KEY_CODE_Y] = 0x15, > > > + [Q_KEY_CODE_U] = 0x16, > > > + [Q_KEY_CODE_I] = 0x17, > > > + [Q_KEY_CODE_O] = 0x18, > > > + [Q_KEY_CODE_P] = 0x19, > > > + [Q_KEY_CODE_BRACKET_LEFT] = 0x1a, > > > + [Q_KEY_CODE_BRACKET_RIGHT] = 0x1b, > > > + [Q_KEY_CODE_RET] = 0x1c, > > > + > > > + [Q_KEY_CODE_A] = 0x1e, > > > + [Q_KEY_CODE_S] = 0x1f, > > > + [Q_KEY_CODE_D] = 0x20, > > > + [Q_KEY_CODE_F] = 0x21, > > > + [Q_KEY_CODE_G] = 0x22, > > > + [Q_KEY_CODE_H] = 0x23, > > > + [Q_KEY_CODE_J] = 0x24, > > > + [Q_KEY_CODE_K] = 0x25, > > > + [Q_KEY_CODE_L] = 0x26, > > > + [Q_KEY_CODE_SEMICOLON] = 0x27, > > > + [Q_KEY_CODE_APOSTROPHE] = 0x28, > > > + [Q_KEY_CODE_GRAVE_ACCENT] = 0x29, > > > + > > > + [Q_KEY_CODE_BACKSLASH] = 0x2b, > > > + [Q_KEY_CODE_Z] = 0x2c, > > > + [Q_KEY_CODE_X] = 0x2d, > > > + [Q_KEY_CODE_C] = 0x2e, > > > + [Q_KEY_CODE_V] = 0x2f, > > > + [Q_KEY_CODE_B] = 0x30, > > > + [Q_KEY_CODE_N] = 0x31, > > > + [Q_KEY_CODE_M] = 0x32, > > > + [Q_KEY_CODE_COMMA] = 0x33, > > > + [Q_KEY_CODE_DOT] = 0x34, > > > + [Q_KEY_CODE_SLASH] = 0x35, > > > + > > > + [Q_KEY_CODE_ASTERISK] = 0x37, > > > + > > > + [Q_KEY_CODE_SPC] = 0x39, > > > + [Q_KEY_CODE_CAPS_LOCK] = 0x3a, > > > + [Q_KEY_CODE_F1] = 0x3b, > > > + [Q_KEY_CODE_F2] = 0x3c, > > > + [Q_KEY_CODE_F3] = 0x3d, > > > + [Q_KEY_CODE_F4] = 0x3e, > > > + [Q_KEY_CODE_F5] = 0x3f, > > > + [Q_KEY_CODE_F6] = 0x40, > > > + [Q_KEY_CODE_F7] = 0x41, > > > + [Q_KEY_CODE_F8] = 0x42, > > > + [Q_KEY_CODE_F9] = 0x43, > > > + [Q_KEY_CODE_F10] = 0x44, > > > + [Q_KEY_CODE_NUM_LOCK] = 0x45, > > > + [Q_KEY_CODE_SCROLL_LOCK] = 0x46, > > > + > > > + [Q_KEY_CODE_KP_DIVIDE] = 0xb5, > > > + [Q_KEY_CODE_KP_MULTIPLY] = 0x37, > > > + [Q_KEY_CODE_KP_SUBTRACT] = 0x4a, > > > + [Q_KEY_CODE_KP_ADD] = 0x4e, > > > + [Q_KEY_CODE_KP_ENTER] = 0x9c, > > > + [Q_KEY_CODE_KP_DECIMAL] = 0x53, > > > + [Q_KEY_CODE_SYSRQ] = 0x54, > > > + > > > + [Q_KEY_CODE_KP_0] = 0x52, > > > + [Q_KEY_CODE_KP_1] = 0x4f, > > > + [Q_KEY_CODE_KP_2] = 0x50, > > > + [Q_KEY_CODE_KP_3] = 0x51, > > > + [Q_KEY_CODE_KP_4] = 0x4b, > > > + [Q_KEY_CODE_KP_5] = 0x4c, > > > + [Q_KEY_CODE_KP_6] = 0x4d, > > > + [Q_KEY_CODE_KP_7] = 0x47, > > > + [Q_KEY_CODE_KP_8] = 0x48, > > > + [Q_KEY_CODE_KP_9] = 0x49, > > > + > > > + [Q_KEY_CODE_LESS] = 0x56, > > > + > > > + [Q_KEY_CODE_F11] = 0x57, > > > + [Q_KEY_CODE_F12] = 0x58, > > > + > > > + [Q_KEY_CODE_PRINT] = 0xb7, > > > + > > > + [Q_KEY_CODE_HOME] = 0xc7, > > > + [Q_KEY_CODE_PGUP] = 0xc9, > > > + [Q_KEY_CODE_PGDN] = 0xd1, > > > + [Q_KEY_CODE_END] = 0xcf, > > > + > > > + [Q_KEY_CODE_LEFT] = 0xcb, > > > + [Q_KEY_CODE_UP] = 0xc8, > > > + [Q_KEY_CODE_DOWN] = 0xd0, > > > + [Q_KEY_CODE_RIGHT] = 0xcd, > > > + > > > + [Q_KEY_CODE_INSERT] = 0xd2, > > > + [Q_KEY_CODE_DELETE] = 0xd3, > > > +#ifdef NEED_CPU_H > > > +#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > > > + [Q_KEY_CODE_STOP] = 0xf0, > > > + [Q_KEY_CODE_AGAIN] = 0xf1, > > > + [Q_KEY_CODE_PROPS] = 0xf2, > > > + [Q_KEY_CODE_UNDO] = 0xf3, > > > + [Q_KEY_CODE_FRONT] = 0xf4, > > > + [Q_KEY_CODE_COPY] = 0xf5, > > > + [Q_KEY_CODE_OPEN] = 0xf6, > > > + [Q_KEY_CODE_PASTE] = 0xf7, > > > + [Q_KEY_CODE_FIND] = 0xf8, > > > + [Q_KEY_CODE_CUT] = 0xf9, > > > + [Q_KEY_CODE_LF] = 0xfa, > > > + [Q_KEY_CODE_HELP] = 0xfb, > > > + [Q_KEY_CODE_META_L] = 0xfc, > > > + [Q_KEY_CODE_META_R] = 0xfd, > > > + [Q_KEY_CODE_COMPOSE] = 0xfe, > > > +#endif > > > +#endif > > > + [Q_KEY_CODE_MAX] = 0, > > > +}; > > > + > > > +int index_from_key(const char *key) > > > > keycode_from_key() is better. > > QAPI passes 'index' to qmp_send_key(), not value (keycode) > So what those two functions return should be the 'index' of key_defs, > not the value (keycode). You're right, although the problem is that we're calling two things a keycode: the hexdecimal value that is defined in key_defs and is passed to the guest and the QKeyCode enum, which actually maps keycodes in string format to an enum. I honestly don't know what to suggest here, the problem is that index_from_key() is too generic for a public function. > > 'Index' will be converted to 'keycode' insider qmp_send_key() > > > > +{ > > > + int i, keycode; > > > + char *endp; > > > + > > > + for (i = 0; QKeyCode_lookup[i] != NULL; i++) { > > > + if (!strcmp(key, QKeyCode_lookup[i])) { > > > + break; > > > + } > > > + } > > > + > > > + if (strstart(key, "0x", NULL)) { > > > + keycode = strtoul(key, &endp, 0); > > > + if (*endp == '\0' && keycode >= 0x01 && keycode <= 0xff) { > > > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > > > + if (keycode == key_defs[i]) { > > > + break; > > > + } > > > + } > > > + } > > > + } > > > + > > > + /* Return Q_KEY_CODE_MAX if the key is invalid */ > > > + return i; > > > +} > > > + > > > +int index_from_keycode(int code) > > > > keycode_from_code() > > > > > +{ > > > + int i; > > > + for (i = 0; i < Q_KEY_CODE_MAX; i++) { > > > + if (key_defs[i] == code) { > > > + break; > > > + } > > > + } > > > + /* Return Q_KEY_CODE_MAX if the code is invalid */ > > > + return i; > > > +} > > > + > > > +static QKeyCodeList *keycodes; > > > +static QEMUTimer *key_timer; > > > + > > > +static void release_keys(void *opaque) > > > +{ > > > + int keycode; > > > + QKeyCodeList *p; > > > + > > > + for (p = keycodes; p != NULL; p = p->next) { > > > + keycode = key_defs[p->value]; > > > + if (keycode & 0x80) { > > > + kbd_put_keycode(0xe0); > > > + } > > > + kbd_put_keycode(keycode | 0x80); > > > + } > > > + qapi_free_QKeyCodeList(keycodes); > > > + keycodes = NULL; > > > +} > > > + > > > +void qmp_send_key(QKeyCodeList *keys, bool has_hold_time, int64_t > > > hold_time, > > > + Error **errp) > > > +{ > > > + int keycode; > > > + QKeyCodeList *p, *keylist, *head = NULL, *tmp = NULL; > > > + > > > + if (!key_timer) { > > > + key_timer = qemu_new_timer_ns(vm_clock, release_keys, > > > NULL); > > > + } > > > + > > > + if (keycodes != NULL) { > > > + qemu_del_timer(key_timer); > > > + release_keys(NULL); > > > + } > > > + if (!has_hold_time) { > > > + hold_time = 100; > > > + } > > > + > > > + for (p = keys; p != NULL; p = p->next) { > > > + keylist = g_malloc0(sizeof(*keylist)); > > > + keylist->value = p->value; > > > + keylist->next = NULL; > > > + > > > + if (!head) { > > > + head = keylist; > > > + } > > > + if (tmp) { > > > + tmp->next = keylist; > > > + } > > > + tmp = keylist; > > > + > > > + /* key down events */ > > > + keycode = key_defs[p->value]; > > > + if (keycode & 0x80) { > > > + kbd_put_keycode(0xe0); > > > + } > > > + kbd_put_keycode(keycode & 0x7f); > > > + } > > > + keycodes = head; > > > + > > > + /* delayed key up events */ > > > + qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > > > + muldiv64(get_ticks_per_sec(), hold_time, > > > 1000)); > > > +} > > > + > > > void qemu_add_kbd_event_handler(QEMUPutKBDEvent *func, void > > > *opaque) > > > { > > > qemu_put_kbd_event_opaque = opaque; > > > diff --git a/monitor.c b/monitor.c > > > index 4db0c1e..e3a2023 100644 > > > --- a/monitor.c > > > +++ b/monitor.c > > > @@ -1293,252 +1293,6 @@ static void do_sum(Monitor *mon, const > > > QDict *qdict) > > > monitor_printf(mon, "%05d\n", sum); > > > } > > > > > > -typedef struct { > > > - int keycode; > > > - const char *name; > > > -} KeyDef; > > > - > > > -static const KeyDef key_defs[] = { > > > - { 0x2a, "shift" }, > > > - { 0x36, "shift_r" }, > > > - > > > - { 0x38, "alt" }, > > > - { 0xb8, "alt_r" }, > > > - { 0x64, "altgr" }, > > > - { 0xe4, "altgr_r" }, > > > - { 0x1d, "ctrl" }, > > > - { 0x9d, "ctrl_r" }, > > > - > > > - { 0xdd, "menu" }, > > > - > > > - { 0x01, "esc" }, > > > - > > > - { 0x02, "1" }, > > > - { 0x03, "2" }, > > > - { 0x04, "3" }, > > > - { 0x05, "4" }, > > > - { 0x06, "5" }, > > > - { 0x07, "6" }, > > > - { 0x08, "7" }, > > > - { 0x09, "8" }, > > > - { 0x0a, "9" }, > > > - { 0x0b, "0" }, > > > - { 0x0c, "minus" }, > > > - { 0x0d, "equal" }, > > > - { 0x0e, "backspace" }, > > > - > > > - { 0x0f, "tab" }, > > > - { 0x10, "q" }, > > > - { 0x11, "w" }, > > > - { 0x12, "e" }, > > > - { 0x13, "r" }, > > > - { 0x14, "t" }, > > > - { 0x15, "y" }, > > > - { 0x16, "u" }, > > > - { 0x17, "i" }, > > > - { 0x18, "o" }, > > > - { 0x19, "p" }, > > > - { 0x1a, "bracket_left" }, > > > - { 0x1b, "bracket_right" }, > > > - { 0x1c, "ret" }, > > > - > > > - { 0x1e, "a" }, > > > - { 0x1f, "s" }, > > > - { 0x20, "d" }, > > > - { 0x21, "f" }, > > > - { 0x22, "g" }, > > > - { 0x23, "h" }, > > > - { 0x24, "j" }, > > > - { 0x25, "k" }, > > > - { 0x26, "l" }, > > > - { 0x27, "semicolon" }, > > > - { 0x28, "apostrophe" }, > > > - { 0x29, "grave_accent" }, > > > - > > > - { 0x2b, "backslash" }, > > > - { 0x2c, "z" }, > > > - { 0x2d, "x" }, > > > - { 0x2e, "c" }, > > > - { 0x2f, "v" }, > > > - { 0x30, "b" }, > > > - { 0x31, "n" }, > > > - { 0x32, "m" }, > > > - { 0x33, "comma" }, > > > - { 0x34, "dot" }, > > > - { 0x35, "slash" }, > > > - > > > - { 0x37, "asterisk" }, > > > - > > > - { 0x39, "spc" }, > > > - { 0x3a, "caps_lock" }, > > > - { 0x3b, "f1" }, > > > - { 0x3c, "f2" }, > > > - { 0x3d, "f3" }, > > > - { 0x3e, "f4" }, > > > - { 0x3f, "f5" }, > > > - { 0x40, "f6" }, > > > - { 0x41, "f7" }, > > > - { 0x42, "f8" }, > > > - { 0x43, "f9" }, > > > - { 0x44, "f10" }, > > > - { 0x45, "num_lock" }, > > > - { 0x46, "scroll_lock" }, > > > - > > > - { 0xb5, "kp_divide" }, > > > - { 0x37, "kp_multiply" }, > > > - { 0x4a, "kp_subtract" }, > > > - { 0x4e, "kp_add" }, > > > - { 0x9c, "kp_enter" }, > > > - { 0x53, "kp_decimal" }, > > > - { 0x54, "sysrq" }, > > > - > > > - { 0x52, "kp_0" }, > > > - { 0x4f, "kp_1" }, > > > - { 0x50, "kp_2" }, > > > - { 0x51, "kp_3" }, > > > - { 0x4b, "kp_4" }, > > > - { 0x4c, "kp_5" }, > > > - { 0x4d, "kp_6" }, > > > - { 0x47, "kp_7" }, > > > - { 0x48, "kp_8" }, > > > - { 0x49, "kp_9" }, > > > - > > > - { 0x56, "less" }, > > > - > > > - { 0x57, "f11" }, > > > - { 0x58, "f12" }, > > > - > > > - { 0xb7, "print" }, > > > - > > > - { 0xc7, "home" }, > > > - { 0xc9, "pgup" }, > > > - { 0xd1, "pgdn" }, > > > - { 0xcf, "end" }, > > > - > > > - { 0xcb, "left" }, > > > - { 0xc8, "up" }, > > > - { 0xd0, "down" }, > > > - { 0xcd, "right" }, > > > - > > > - { 0xd2, "insert" }, > > > - { 0xd3, "delete" }, > > > -#if defined(TARGET_SPARC) && !defined(TARGET_SPARC64) > > > - { 0xf0, "stop" }, > > > - { 0xf1, "again" }, > > > - { 0xf2, "props" }, > > > - { 0xf3, "undo" }, > > > - { 0xf4, "front" }, > > > - { 0xf5, "copy" }, > > > - { 0xf6, "open" }, > > > - { 0xf7, "paste" }, > > > - { 0xf8, "find" }, > > > - { 0xf9, "cut" }, > > > - { 0xfa, "lf" }, > > > - { 0xfb, "help" }, > > > - { 0xfc, "meta_l" }, > > > - { 0xfd, "meta_r" }, > > > - { 0xfe, "compose" }, > > > -#endif > > > - { 0, NULL }, > > > -}; > > > - > > > -static int get_keycode(const char *key) > > > -{ > > > - const KeyDef *p; > > > - char *endp; > > > - int ret; > > > - > > > - for(p = key_defs; p->name != NULL; p++) { > > > - if (!strcmp(key, p->name)) > > > - return p->keycode; > > > - } > > > - if (strstart(key, "0x", NULL)) { > > > - ret = strtoul(key, &endp, 0); > > > - if (*endp == '\0' && ret >= 0x01 && ret <= 0xff) > > > - return ret; > > > - } > > > - return -1; > > > -} > > > - > > > -#define MAX_KEYCODES 16 > > > -static uint8_t keycodes[MAX_KEYCODES]; > > > -static int nb_pending_keycodes; > > > -static QEMUTimer *key_timer; > > > - > > > -static void release_keys(void *opaque) > > > -{ > > > - int keycode; > > > - > > > - 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); > > > - } > > > -} > > > - > > > -static void do_sendkey(Monitor *mon, const QDict *qdict) > > > -{ > > > - char keyname_buf[16]; > > > - char *separator; > > > - int keyname_len, keycode, i; > > > - const char *keys = qdict_get_str(qdict, "keys"); > > > - int has_hold_time = qdict_haskey(qdict, "hold-time"); > > > - int hold_time = qdict_get_try_int(qdict, "hold-time", -1); > > > - > > > - if (nb_pending_keycodes > 0) { > > > - qemu_del_timer(key_timer); > > > - release_keys(NULL); > > > - } > > > - if (!has_hold_time) > > > - hold_time = 100; > > > - i = 0; > > > - while (1) { > > > - separator = strchr(keys, '-'); > > > - keyname_len = separator ? separator - keys : strlen(keys); > > > - if (keyname_len > 0) { > > > - pstrcpy(keyname_buf, sizeof(keyname_buf), keys); > > > - if (keyname_len > sizeof(keyname_buf) - 1) { > > > - monitor_printf(mon, "invalid key: '%s...'\n", > > > keyname_buf); > > > - return; > > > - } > > > - if (i == MAX_KEYCODES) { > > > - monitor_printf(mon, "too many keys\n"); > > > - return; > > > - } > > > - > > > - /* Be compatible with old interface, convert user > > > inputted "<" */ > > > - if (!strncmp(keyname_buf, "<", 1) && keyname_len == 1) > > > { > > > - pstrcpy(keyname_buf, sizeof(keyname_buf), "less"); > > > - keyname_len = 4; > > > - } > > > - > > > - keyname_buf[keyname_len] = 0; > > > - keycode = get_keycode(keyname_buf); > > > - if (keycode < 0) { > > > - monitor_printf(mon, "unknown key: '%s'\n", > > > keyname_buf); > > > - return; > > > - } > > > - keycodes[i++] = keycode; > > > - } > > > - if (!separator) > > > - break; > > > - keys = separator + 1; > > > - } > > > - 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); > > > - } > > > - /* delayed key up events */ > > > - qemu_mod_timer(key_timer, qemu_get_clock_ns(vm_clock) + > > > - muldiv64(get_ticks_per_sec(), hold_time, > > > 1000)); > > > -} > > > - > > > static int mouse_button_state; > > > > > > static void do_mouse_move(Monitor *mon, const QDict *qdict) > > > @@ -4077,7 +3831,7 @@ static void monitor_find_completion(const > > > char *cmdline) > > > int nb_args, i, len; > > > const char *ptype, *str; > > > const mon_cmd_t *cmd; > > > - const KeyDef *key; > > > + const int *code; > > > > > > parse_cmdline(cmdline, &nb_args, args); > > > #ifdef DEBUG_COMPLETION > > > @@ -4151,9 +3905,14 @@ static void monitor_find_completion(const > > > char *cmdline) > > > if (sep) > > > str = sep + 1; > > > readline_set_completion_index(cur_mon->rs, > > > strlen(str)); > > > - for(key = key_defs; key->name != NULL; key++) { > > > - cmd_completion(str, key->name); > > > > You can do: > > > > cmd_completion(str, KeyCodes_lookup[i]); > > > > The loop below is not needed. > > This is enough, then we can make key_defs static. > > for (i = 0; i < Q_KEY_CODE_MAX; i++) { > cmd_completion(str, QKeyCode_lookup[i]); > } > > > > > + for (code = key_defs; code != NULL; code++) { > > > + int idx; > > > + idx = index_from_keycode(*code); > > > + if (idx != Q_KEY_CODE_MAX) { > > > + cmd_completion(str, QKeyCode_lookup[idx]); > > > + } > > > } > > > + > > > } else if (!strcmp(cmd->name, "help|?")) { > > > readline_set_completion_index(cur_mon->rs, > > > strlen(str)); > > > for (cmd = mon_cmds; cmd->name != NULL; cmd++) { > > > @@ -4681,7 +4440,6 @@ void monitor_init(CharDriverState *chr, int > > > flags) > > > Monitor *mon; > > > > > > if (is_first_init) { > > > - key_timer = qemu_new_timer_ns(vm_clock, release_keys, > > > NULL); > > > monitor_protocol_event_init(); > > > is_first_init = 0; > > > } > > > diff --git a/qapi-schema.json b/qapi-schema.json > > > index bc55ed2..3a562d8 100644 > > > --- a/qapi-schema.json > > > +++ b/qapi-schema.json > > > @@ -2183,3 +2183,49 @@ > > > # Since: 0.14.0 > > > ## > > > { 'command': 'closefd', 'data': {'fdname': 'str'} } > > > + > > > +## > > > +# @QKeyCode: > > > +# > > > +# An enumeration of key name. > > > +# > > > +# This is used by the send-key command. > > > +# > > > +# Since: 1.2 > > > +## > > > +{ 'enum': 'QKeyCode', > > > + 'data': [ 'shift', 'shift_r', 'alt', 'alt_r', 'altgr', > > > 'altgr_r', 'ctrl', > > > + 'ctrl_r', 'menu', 'esc', '1', '2', '3', '4', '5', '6', > > > '7', '8', > > > + '9', '0', 'minus', 'equal', 'backspace', 'tab', 'q', > > > 'w', 'e', > > > + 'r', 't', 'y', 'u', 'i', 'o', 'p', 'bracket_left', > > > 'bracket_right', > > > + 'ret', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', > > > 'semicolon', > > > + 'apostrophe', 'grave_accent', 'backslash', 'z', 'x', > > > 'c', 'v', 'b', > > > + 'n', 'm', 'comma', 'dot', 'slash', 'asterisk', 'spc', > > > 'caps_lock', > > > + 'f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', > > > 'f10', > > > + 'num_lock', 'scroll_lock', 'kp_divide', 'kp_multiply', > > > + 'kp_subtract', 'kp_add', 'kp_enter', 'kp_decimal', > > > 'sysrq', 'kp_0', > > > + 'kp_1', 'kp_2', 'kp_3', 'kp_4', 'kp_5', 'kp_6', > > > 'kp_7', 'kp_8', > > > + 'kp_9', 'less', 'f11', 'f12', 'print', 'home', 'pgup', > > > 'pgdn', 'end', > > > + 'left', 'up', 'down', 'right', 'insert', 'delete', > > > 'stop', 'again', > > > + 'props', 'undo', 'front', 'copy', 'open', 'paste', > > > 'find', 'cut', > > > + 'lf', 'help', 'meta_l', 'meta_r', 'compose' ] } > > > + > > > +## > > > +# @send-key: > > > +# > > > +# Send keys to guest. > > > +# > > > +# @keys: key sequence. 'keys' is the name of the key. Use a JSON > > > array to > > > +# press several keys simultaneously. > > > +# > > > +# @hold-time: #optional time to delay key up events, milliseconds. > > > Defaults > > > +# to 100 > > > +# > > > +# Returns: Nothing on success > > > +# If key is unknown or redundant, InvalidParameter > > > +# > > > +# Since: 1.2 > > > +# > > > +## > > > +{ 'command': 'send-key', > > > + 'data': { 'keys': ['QKeyCode'], '*hold-time': 'int' } } > > > diff --git a/qmp-commands.hx b/qmp-commands.hx > > > index e3cf3c5..3c1e646 100644 > > > --- a/qmp-commands.hx > > > +++ b/qmp-commands.hx > > > @@ -335,6 +335,34 @@ Example: > > > EQMP > > > > > > { > > > + .name = "send-key", > > > + .args_type = "keys:O,hold-time:i?", > > > + .mhandler.cmd_new = qmp_marshal_input_send_key, > > > + }, > > > + > > > +SQMP > > > +send-key > > > +---------- > > > + > > > +Send keys to VM. > > > + > > > +Arguments: > > > + > > > +keys array: > > > + - "key": key sequence (a json-array of key enum values) > > > + > > > +- hold-time: time to delay key up events, milliseconds. Defaults > > > to 100 > > > + (json-int, optional) > > > + > > > +Example: > > > + > > > +-> { "execute": "send-key", > > > + "arguments": { 'keys': [ 'ctrl', 'alt', 'delete' ] } } > > > +<- { "return": {} } > > > + > > > +EQMP > > > + > > > + { > > > .name = "cpu", > > > .args_type = "index:i", > > > .mhandler.cmd_new = qmp_marshal_input_cpu, > > > > > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2012-08-03 13:23 UTC | newest] Thread overview: 12+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-07-26 4:48 [Qemu-devel] [PATCH v5 0/6] convert sendkey to qapi Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 1/6] fix doc of using raw values with sendkey Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 2/6] monitor: rename keyname '<' to 'less' Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 3/6] hmp: rename arguments Amos Kong 2012-07-26 4:48 ` [Qemu-devel] [PATCH v5 4/6] qapi: generate list struct and visit_list for enum Amos Kong 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 5/6] ps2: output warning when event queue full Amos Kong 2012-07-27 19:24 ` Blue Swirl 2012-07-26 4:49 ` [Qemu-devel] [PATCH v5 6/6] qapi: convert sendkey Amos Kong 2012-07-26 21:22 ` Eric Blake 2012-08-02 19:57 ` Luiz Capitulino 2012-08-03 1:38 ` Amos Kong 2012-08-03 13:23 ` Luiz Capitulino
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).