diff mbox

[PULL,v2,8/9] input-linux: refine mouse detection

Message ID 1460562303-17079-9-git-send-email-kraxel@redhat.com
State New
Headers show

Commit Message

Gerd Hoffmann April 13, 2016, 3:45 p.m. UTC
Read absolute and relative axis information, only classify
devices as mouse/tablet in case the x axis is present.

Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
 ui/input-linux.c | 30 +++++++++++++++++++++++++-----
 1 file changed, 25 insertions(+), 5 deletions(-)

Comments

Ladi Prosek April 14, 2016, 7:42 a.m. UTC | #1
On Wed, Apr 13, 2016 at 5:45 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Read absolute and relative axis information, only classify
> devices as mouse/tablet in case the x axis is present.

I, too, had to come up with a heuristic to classify input devices in
my guest driver and what I ended up with is different.

For example my Dell keyboard has two endpoints, one with a bunch of
keys and LEDs, so it would be classified as a keyboard. The second one
with special keys (KEY_MUTE, KEY_WWW, KEY_BACK, ..) *and* with a mouse
(REL_X, REL_Y, REL_WHEEL, BTN_LEFT, ...). The reason for this are the
zoom in/out buttons. Pressing them generates Ctrl down on the first
endpoint and mouse wheel up/down on the second one. Releasing them
then translates to Ctrl up. Crazy.

So I wouldn't use exclusive OR when classifying because there are
combo devices out there. Maybe anything with an EV_KEY (minus BTN_*)
would be a keyboard?

Ladi
Gerd Hoffmann April 14, 2016, 8:07 a.m. UTC | #2
On Do, 2016-04-14 at 09:42 +0200, Ladi Prosek wrote:
> On Wed, Apr 13, 2016 at 5:45 PM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> > Read absolute and relative axis information, only classify
> > devices as mouse/tablet in case the x axis is present.
> 
> I, too, had to come up with a heuristic to classify input devices in
> my guest driver and what I ended up with is different.
> 
> For example my Dell keyboard has two endpoints, one with a bunch of
> keys and LEDs, so it would be classified as a keyboard. The second one
> with special keys (KEY_MUTE, KEY_WWW, KEY_BACK, ..) *and* with a mouse
> (REL_X, REL_Y, REL_WHEEL, BTN_LEFT, ...). The reason for this are the
> zoom in/out buttons. Pressing them generates Ctrl down on the first
> endpoint and mouse wheel up/down on the second one. Releasing them
> then translates to Ctrl up. Crazy.

So they are building os-specific hotkeys into the hardware.  Crazy
indeed.

It's not obvious though why the second function has keyboard keys.
Possibly they want the first function look like a pretty standard
keyboard without any extra fluff, to sidestep compatibility issues with
old software not expecting that.

> So I wouldn't use exclusive OR when classifying because there are
> combo devices out there. Maybe anything with an EV_KEY (minus BTN_*)
> would be a keyboard?

Right now each device type has its own callback function, we have to
reorganize that to support a device being classified as both mouse and
keyboard.  Worth considering, but not 2.6 material.

There surely is more room for improvements, not only in input-linux but
in the input system in general and in the virtual input devices, for
example to support all those extra keys on multimedia keyboards.

cheers,
  Gerd
diff mbox

Patch

diff --git a/ui/input-linux.c b/ui/input-linux.c
index 9c921cc..1d33b5c 100644
--- a/ui/input-linux.c
+++ b/ui/input-linux.c
@@ -337,7 +337,7 @@  static void input_linux_event_mouse(void *opaque)
 static void input_linux_complete(UserCreatable *uc, Error **errp)
 {
     InputLinux *il = INPUT_LINUX(uc);
-    uint32_t evtmap;
+    uint32_t evtmap, relmap, absmap;
     int rc, ver;
 
     if (!il->evdev) {
@@ -359,16 +359,36 @@  static void input_linux_complete(UserCreatable *uc, Error **errp)
     }
 
     rc = ioctl(il->fd, EVIOCGBIT(0, sizeof(evtmap)), &evtmap);
+    if (rc < 0) {
+        error_setg(errp, "%s: failed to read event bits", il->evdev);
+        goto err_close;
+    }
 
     if (evtmap & (1 << EV_REL)) {
-        /* has relative axis -> assume mouse */
+        rc = ioctl(il->fd, EVIOCGBIT(EV_REL, sizeof(relmap)), &relmap);
+        if (rc < 0) {
+            relmap = 0;
+        }
+    }
+
+    if (evtmap & (1 << EV_ABS)) {
+        ioctl(il->fd, EVIOCGBIT(EV_ABS, sizeof(absmap)), &absmap);
+        if (rc < 0) {
+            absmap = 0;
+        }
+    }
+
+    if ((evtmap & (1 << EV_REL)) &&
+        (relmap & (1 << REL_X))) {
+        /* has relative x axis -> assume mouse */
         qemu_set_fd_handler(il->fd, input_linux_event_mouse, NULL, il);
-    } else if (evtmap & (1 << EV_ABS)) {
-        /* has absolute axis -> not supported */
+    } else if ((evtmap & (1 << EV_ABS)) &&
+               (absmap & (1 << ABS_X))) {
+        /* has absolute x axis -> not supported */
         error_setg(errp, "tablet/touchscreen not supported");
         goto err_close;
     } else if (evtmap & (1 << EV_KEY)) {
-        /* has keys/buttons (and no axis) -> assume keyboard */
+        /* has keys/buttons (and no x axis) -> assume keyboard */
         qemu_set_fd_handler(il->fd, input_linux_event_keyboard, NULL, il);
     } else {
         /* Huh? What is this? */