[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey
From: |
Amos Kong |
Subject: |
Re: [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey |
Date: |
Wed, 18 Jul 2012 14:25:37 -0400 (EDT) |
----- Original Message -----
> On Wed, 18 Jul 2012 20:56:54 +0800
> Amos Kong <address@hidden> wrote:
>
> > >> +} KeyDef;
> > >> +
> > >> +static const KeyDef key_defs[] = {
> > >
> > > We can't have an array defined in a header file because it will
> > > be defined in
> > > each .c file that includes it.
> > >
> > > Please, define it in input.c (along with qmp_send_key())
> >
> > Ok.
> >
> > > and write the following public functions:
> > >
> > > o KeyCode keycode_from_key(const char *key);
> > > o KeyCode keycode_from_code(int code);
> >
> >
> > void qmp_send_key(KeyCodesList *keys, bool has_hold_time, int64_t
> > hold_time, ...)
> > ^
> > \_ when we use qmp, a key list will be passed,
> > the
> > values are the index
> > in enum KeyCodes. not the real KeyCode.
>
> Right.
>
> >
> > { 'enum': 'KeyCodes',
> > 'data': [ 'shift', 'shift_r', 'al...
> >
> > So we need to get this kind of 'index' in hmp_send_key() and pass
> > to
> > qmp_send_key().
>
> Yes, that's what keycode_from_key() would do, something like this:
>
> KeyCode keycode_from_key(const char *key)
> {
> int i;
>
> for (i = 0; i < KEY_CODES_MAX; i++) {
> if (!strcmp(key, KeyCode_lookup[i])) {
> return i;
> }
> }
>
> return KEY_CODE_MAX;
> }
>
> Note that it returns the KeyCode index, and should be defined in
> input.c.
Sure :)
> > then convert this 'index' to keycode in qmp_send_key()
>
> Exactly, qmp_send_key() can access key_defs[] to get the keycode from
> the
> index.
>
> >
> > I didn't find a way to define a non-serial enum.
>
> I'm not sure I follow you here, I think that what I suggested above
> will work.
So I would continually pass 'index' to qmp_send_key().
I already implemented those in localhost, they all works.
Will fix other issues and post v5 later, thanks.
> > eg: (then int qmp_marshal_input_send_key() would pass real keycode
> > to
> > qmp_send_key())
> > { 'enum': 'KeyCodes',
> > 'data': [ 'shift' = 0x2a, 'shift_r' = 0x36, 'alt' = 0x38, ...
> >
> >
> > If we still pass 'index' to qmp_send_key as patch V4.
> >
> > extern int index_from_key(const char *key); -> it's used in
> > hmp_send_key()
> > extern int index_from_keycode(int code); -> it's used in
> > hmp_send_key()
> > extern char *key_from_keycode(int idx); -> it's used in
> > monitor_find_completion()
> > extern int keycode_from_key(const char *key); -> it's used in
> > qmp_send_key()
> >
> >
> > > and then use these functions where using key_defs would be
> > > necessary. Also,
> > > note that keycode_from_key() can use KeyCodes_lookup[] instead of
> > > key_defs (this
> > > way we can drop 'name' from KeyDef).
> >
> > ....
> >
> > >> +#endif
> > >> +#endif
> > >> + [KEY_CODES_MAX] = { 0, NULL },
> > >> +};
> > >> +
> > >> #endif
> > >> diff --git a/hmp-commands.hx b/hmp-commands.hx
> > >> index e336251..865eea9 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 b9cec1d..cfdc106 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)
> > >> {
> > >> @@ -1000,3 +1001,66 @@ void hmp_netdev_del(Monitor *mon, const
> > >> QDict *qdict)
> > >> qmp_netdev_del(id,&err);
> > >> hmp_handle_error(mon,&err);
> > >> }
> > >> +
> > >> +static int get_key_index(const char *key)
> > >> +{
> > >> + int i, keycode;
> > >> + char *endp;
> > >> +
> > >> + for (i = 0; i< KEY_CODES_MAX; i++)
> > >> + if (key_defs[i].keycode&& !strcmp(key,
> > >> key_defs[i].name))
> > >> + return i;
> > >
> > > Here you can call do:
> > >
> > > keycode = keycode_from_key(key);
> > > if (keycode != KEY_CODES_MAX) {
> > > return keycode;
> > > }
> > >
> > >> +
> > >> + if (strstart(key, "0x", NULL)) {
> > >> + keycode = strtoul(key,&endp, 0);
> > >> + if (*endp == '\0'&& keycode>= 0x01&& keycode<= 0xff)
> > >> + for (i = 0; i< KEY_CODES_MAX; i++)
> > >> + if (keycode == key_defs[i].keycode)
> > >> + return i;
> > >
> > > You can drop that for loop and do instead:
> > >
> > > keycode = keycode_from_code(keycode);
> > >
> > >
> > >> + }
> > >> +
> > >> + return -1;
> > >> +}
> > >> +
> > >> +void hmp_send_key(Monitor *mon, const QDict *qdict)
> > >> +{
> > >> + const char *keys = qdict_get_str(qdict, "keys");
> > >> + KeyCodesList *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;
> > >> +
> > >> + 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;
> > >> +
> > >> + keylist = g_malloc0(sizeof(*keylist));
> > >> + keylist->value = get_key_index(keyname_buf);
> > >
> > > get_key_index() can fail.
> >
> > Ok, I would check it.
> >
> > >> + keylist->next = NULL;
> > >> +
> > >> + if (tmp)
> > >> + tmp->next = keylist;
> > >> + tmp = keylist;
> > >> + if (!head)
> > >> + head = keylist;
> > >> +
> > >> + if (!separator)
> > >> + break;
> > >> + keys = separator + 1;
> > >> + }
> >
> > ...
> >
> > >> - { 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 KeyCodesList *keycodes;
> > >> static QEMUTimer *key_timer;
> > >>
> > >> static void release_keys(void *opaque)
> > >> {
> > >> int keycode;
> > >> + KeyCodesList *p;
> > >> +
> > >> + for (p = keycodes; p != NULL; p = p->next) {
> > >> + if (p->value> KEY_CODES_MAX) {
> > >
> > > This check is not needed, as far as I can understand only
> > > qmp_send_key() can put
> > > keys in the keycodes list and qmp_send_key() does this check
> > > already.
> >
> > If we find one invalid 'value', other keys in the list will be
> > ignored.
> > so we don't need to release them here.
>
> That should be done in qmp_send_key(), only valid keys should be
> passed to
> release_keys().
Ok. will use two loops.
> >
> >
> > >> + keycodes = NULL;
> > >> + break;
> > >> + }
> > >>
> > >> - while (nb_pending_keycodes> 0) {
> > >> - nb_pending_keycodes--;
> > >> - keycode = keycodes[nb_pending_keycodes];
> > >> + keycode = key_defs[p->value].keycode;
> > >> if (keycode& 0x80)
> > >> kbd_put_keycode(0xe0);
> > >> kbd_put_keycode(keycode | 0x80);
> > >> }
> > >
> > > Please set keycodes to NULL here. Actually, you'll have to free
> > > it first,
> > > because keycodes has to be duplicated (see below).
> > >
> > >> }
> > >>
> > >> -static void do_sendkey(Monitor *mon, const QDict *qdict)
> > >> +void qmp_send_key(KeyCodesList *keys, bool has_hold_time,
> > >> int64_t hold_time,
> > >> + Error **errp)
> > >> {
> > >> - 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);
> > >> + int keycode;
> > >> + char value[5];
> > >> + KeyCodesList *p;
> > >
> > > Let's initialize key_timer here, like this:
> > >
> > > if (!key_timer) {
> > > key_timer = qemu_new_timer_ns(vm_clock, release_keys, NULL);
> > > }
> > >
> > > Then drop the initialization done in monitor_init(). This way we
> > > untangle
> > > qmp_send_key() from the monitor.
> > >
> > > Also, please, move qmp_send_key(), release_keys, etc to input.c
> > > as I said
> > > above.
> >
> > Ok.
> >
> > >> - if (nb_pending_keycodes> 0) {
> > >> + if (keycodes != NULL) {
> > >> qemu_del_timer(key_timer);
> > >> release_keys(NULL);
> > >> }
> > >> if (!has_hold_time)
> > >> hold_time = 100;
> > >
> > > Please, add { } around the if body above.
> > >
> > >> - 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;
> > >> - }
> > >> + keycodes = keys;
> > >
> > > It's better to this assignment after the for loop below.
> > > Actually, you have to
> > > duplicate the key list because the qapi code will free it as soon
> > > as
> > > qmp_send_key() returns, but it will be used later in the timer
> > > handler.
> > >
> > >>
> > >> - 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;
> > >> + for (p = keycodes; p != NULL; p = p->next) {
> > >> + if (p->value> KEY_CODES_MAX) {
> > >
> > > You should test against>=.
> > >
> > >> + sprintf(value, "%d", p->value);
> > >> + error_set(errp, QERR_INVALID_PARAMETER, value);
> >
> > ^^ If an invalid key is found, the other keys will be ignored.
>
> Well, that's the behavior I'd expect. Maybe we should loop twice.
> First
> we check everything is ok and then we trigger the key down events.
>
> Now, the current code doesn't do this and I'm not sure if we would
> break compatibility... I'll let you choose what you think is best.
>
> >
> >
> > Will fix other issues you mentioned, thanks for your review.
> >
>
>
>
- [Qemu-devel] [PATCH v4 1/6] fix doc of using raw values with sendkey, (continued)
- [Qemu-devel] [PATCH v4 1/6] fix doc of using raw values with sendkey, Amos Kong, 2012/07/05
- [Qemu-devel] [PATCH v4 3/6] hmp: rename arguments, Amos Kong, 2012/07/05
- [Qemu-devel] [PATCH v4 2/6] monitor: rename keyname '<' to 'less', Amos Kong, 2012/07/05
- [Qemu-devel] [PATCH v4 4/6] qapi: generate list struct and visit_list for enum, Amos Kong, 2012/07/05
- [Qemu-devel] [PATCH v4 6/6] ps2: output warning when event queue full, Amos Kong, 2012/07/05
- [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey, Amos Kong, 2012/07/05
- Re: [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey, Amos Kong, 2012/07/25
- Re: [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey, Luiz Capitulino, 2012/07/25
- Re: [Qemu-devel] [PATCH v4 5/6] qapi: convert sendkey, Amos Kong, 2012/07/25