qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH] input-linux: customizable grab toggle keys v3


From: Ryan El Kochta
Subject: [Qemu-devel] [PATCH] input-linux: customizable grab toggle keys v3
Date: Mon, 03 Sep 2018 16:32:10 +0000

This patch adds a new option to the input-linux object:

grab_toggle=key-key-key

These keys can be one of the following:

* lctrl
* rctrl
* lalt
* ralt
* lshift
* rshift
* backtick
* scrolllock

The user can pick any combination of these keys. The VM's grab
of the evdev device will be toggled when all of the selected
keys are pressed at the same time. If grab_toggle is not specified
or malformed, the current default of lctrl+rctrl will be used.

If scrolllock is selected as one of the grab_toggle keys, it
will be entirely disabled and not passed to the guest at all.
This is to prevent enabling it while attempting to leave or enter
the VM. On the host, scrolllock can be disabled using xmodmap.

First, find the modifier that Scroll_Lock is bound to:

$ xmodmap -pm

Then, remove Scroll_Lock from it, replacing modX with the modifier:

$ xmodmap -e 'remove modX = Scroll_Lock'

If Scroll_Lock is not bound to any modifier, it is already disabled.

To save the changes, add them to your xinitrc.

I have also attached the patch contained in the body of this email
since my mail client does not seem to behave well with patches.
If this is a problem, please let me know.

Signed-off-by: Ryan El Kochta <address@hidden>
---
ui/input-linux.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 153 insertions(+), 3 deletions(-)

diff --git a/ui/input-linux.c b/ui/input-linux.c
index 9720333b2c..2cbc877667 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -12,6 +12,7 @@
#include "sysemu/sysemu.h"
#include "ui/input.h"
#include "qom/object_interfaces.h"
+#include "include/qemu/cutils.h"

#include <sys/ioctl.h>
#include "standard-headers/linux/input.h"
@@ -63,6 +64,11 @@ struct InputLinux {
     struct input_event event;
     int         read_offset;

+    char        *grab_toggle;
+    int         grab_toggle_len;
+    int         *grab_toggle_list;
+    bool        skip_scrolllock;
+
     QTAILQ_ENTRY(InputLinux) next;
};

@@ -98,6 +104,25 @@ static void input_linux_toggle_grab(InputLinux *il)
     }
}

+static bool input_linux_check_grab_toggle(InputLinux *il)
+{
+    for (unsigned i = 0; i < il->grab_toggle_len; i++) {
+        if (!il->keydown[il->grab_toggle_list[i]]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+static bool input_linux_check_skip_scrolllock(InputLinux *il,
+                                       struct input_event *event)
+{
+    if (il->skip_scrolllock && event->code == KEY_SCROLLLOCK) {
+        return true;
+    }
+    return false;
+}
+
static void input_linux_handle_keyboard(InputLinux *il,
                                         struct input_event *event)
{
@@ -128,14 +153,13 @@ static void input_linux_handle_keyboard(InputLinux *il,
         }

         /* send event to guest when grab is active */
-        if (il->grab_active) {
+        if (il->grab_active && !input_linux_check_skip_scrolllock(il, event)) {
             int qcode = qemu_input_linux_to_qcode(event->code);
             qemu_input_event_send_key_qcode(NULL, qcode, event->value);
         }

         /* hotkey -> record switch request ... */
-        if (il->keydown[KEY_LEFTCTRL] &&
-            il->keydown[KEY_RIGHTCTRL]) {
+        if (input_linux_check_grab_toggle(il)) {
             il->grab_request = true;
         }

@@ -274,6 +298,15 @@ static void input_linux_complete(UserCreatable *uc, Error 
**errp)
         return;
     }

+    if(!il->grab_toggle || !il->grab_toggle_len || !il->grab_toggle_list) {
+        il->skip_scrolllock = false;
+        il->grab_toggle = NULL;
+        il->grab_toggle_len = 2;
+        il->grab_toggle_list = g_new(int, 2);
+        il->grab_toggle_list[0] = KEY_LEFTCTRL;
+        il->grab_toggle_list[1] = KEY_RIGHTCTRL;
+    }
+
     il->fd = open(il->evdev, O_RDWR);
     if (il->fd < 0)  {
         error_setg_file_open(errp, errno, il->evdev);
@@ -410,11 +443,128 @@ static void input_linux_set_repeat(Object *obj, bool 
value,
     il->repeat = value;
}

+static void input_linux_populate_grab_toggle(InputLinux *il)
+{
+    char *orig, *saveptr, *token;
+    unsigned cntr = 0;
+
+    /*
+     * If no grab_toggle string was provided, return.
+     * This will be cleaned up in the input_linux_complete()
+     * function and reset to both Ctrl keys.
+     */
+    if (!il->grab_toggle) {
+        return;
+    }
+
+    il->skip_scrolllock = false;
+
+    /* Create a new string for strtok_r */
+    orig = g_strdup(il->grab_toggle);
+
+    /*
+     * Iterate through each token in the string,
+     * separated by dashes, and add it to the il->grab_toggle_list
+     * array.
+     *
+     * Unfortunately this must be done twice in order to
+     * determine how much memory will be allocated later on.
+     */
+
+    /* First iteration */
+    il->grab_toggle_len = 0;
+    saveptr = orig;
+    while (strtok_r(saveptr, "-", &saveptr)) {
+        il->grab_toggle_len++;
+        /* If this overflows, use the default */
+        if (il->grab_toggle_len < 0) {
+            il->grab_toggle_len = 0;
+            break;
+        }
+    }
+
+    /*
+     * If the count found zero tokens, return an empty list.
+     * Again, this will be cleaned up in input_linux_complete().
+     */
+    if (!il->grab_toggle_len) {
+        g_free(orig);
+        return;
+    }
+
+    /* Second scan */
+    il->grab_toggle_list = g_new(int, il->grab_toggle_len);
+    strcpy(orig, il->grab_toggle);
+    saveptr = orig;
+
+    /* Add each token's key to the list */
+    while ((token = strtok_r(saveptr, "-", &saveptr))) {
+        if (!strcmp(token, "lctrl")) {
+            il->grab_toggle_list[cntr] = KEY_LEFTCTRL;
+        } else if (!strcmp(token, "rctrl")) {
+            il->grab_toggle_list[cntr] = KEY_RIGHTCTRL;
+        } else if (!strcmp(token, "lalt")) {
+            il->grab_toggle_list[cntr] = KEY_LEFTALT;
+        } else if (!strcmp(token, "ralt")) {
+            il->grab_toggle_list[cntr] = KEY_RIGHTALT;
+        } else if (!strcmp(token, "lshift")) {
+            il->grab_toggle_list[cntr] = KEY_LEFTSHIFT;
+        } else if (!strcmp(token, "rshift")) {
+            il->grab_toggle_list[cntr] = KEY_RIGHTSHIFT;
+        } else if (!strcmp(token, "backtick")) {
+            il->grab_toggle_list[cntr] = KEY_GRAVE;
+        } else if (!strcmp(token, "scrolllock")) {
+            il->grab_toggle_list[cntr] = KEY_SCROLLLOCK;
+            il->skip_scrolllock = true;
+        } else {
+            /*
+            * If any of the parameters are invalid,
+            * stick to the default of LCtrl+RCtrl.
+            *
+            * We could just skip that parameter, but
+            * that means if you input only invalid parameters,
+            * there would be no way to escape the VM.
+            */
+            il->grab_toggle_len = 0;
+            g_free(orig);
+            g_free(il->grab_toggle_list);
+            return;
+        }
+
+        cntr++;
+    }
+    g_free(orig);
+}
+
+static char *input_linux_get_grab_toggle(Object *obj, Error **errp)
+{
+    InputLinux *il = INPUT_LINUX(obj);
+
+    return g_strdup(il->grab_toggle);
+}
+
+static void input_linux_set_grab_toggle(Object *obj, const char *value,
+                                        Error **errp)
+{
+    InputLinux *il = INPUT_LINUX(obj);
+
+    if (il->grab_toggle) {
+        error_setg(errp, "grab_toggle property already set");
+        return;
+    }
+    il->grab_toggle = g_strdup(value);
+
+    input_linux_populate_grab_toggle(il);
+}
+
static void input_linux_instance_init(Object *obj)
{
     object_property_add_str(obj, "evdev",
                             input_linux_get_evdev,
                             input_linux_set_evdev, NULL);
+    object_property_add_str(obj, "grab_toggle",
+                            input_linux_get_grab_toggle,
+                            input_linux_set_grab_toggle, NULL);
     object_property_add_bool(obj, "grab_all",
                              input_linux_get_grab_all,
                              input_linux_set_grab_all, NULL);
--
2.18.0

Attachment: 0001-input-linux-customizable-grab-toggle-keys-v3.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]