Home > Software design >  Multi-pointer handling in Linux via QT application
Multi-pointer handling in Linux via QT application

Time:07-23

Xorg servers starting from version 1.7 supports having multiple mouse cursors in one PC.

I also know that QT provides functionality to handle mouse events and operate on them.

Question:

I want to handle specific mouse events in QT application in dual mouse device configuration.

Imagine I have created 2 mouse pointers and have 2 physical mouse devices connected to the PC. First mouse device is for regular usage, and the second one should be moved infinitely in some QWidget.

Is it possible to identify the corresponding mouse device(in multiple mouse cursors case) in QT application and made it to move only in specified widget and in the same time the second mouse should be able to be used as a regular mouse device ?.

NOTES:

The QT application will run on Linux, so I am not interested on Windows.

I am free to modify the Linux Kernel drivers, etc...

CodePudding user response:

This does not answer OP's question in the sense that this is more generic approach, and not Qt-specific.


If the secondary mouse (or whatever HID device you want to use) is generally not intended to be a pointer at all, you can use the Linux Input Subsystem to "grab" and interface directly to the input device. The downside is then that it isn't a pointer anymore, and you need to handle its movement and generate the events it produces yourself; however, all toolkits including Qt do support that.

HID event input devices are accessible as /dev/input/event*, with the corresponding pseudofile /sys/class/input/event*/device/name giving its human-readable name (say, PS/2 Generic Mouse), /sys/class/input/event*/device/id/vendor and /sys/class/input/event*/device/id/product its USB vendor:product (in hexadecimal). Most Linux distributions generate symlinks in /dev/input/by-id/ and /dev/input/by-path/, but you most likely want to set up an udev rule (in /etc/udev/rules.d/ or /lib/udev/rules.d/, depending on whether you do that as an user or admin, or as part of installing your application) that makes suitable symlink and grants access to the device for the target users.

Essentially, a process with access to the event device, opens it (read-write), and runs ioctl(devfd, EVIOCGRAB, 1) to "grab" the device so that only this process sees the events generated by this device (and they are no longer forwarded to others; in particular, a mouse will no longer affect the main pointer movement). Then, the process just reads struct input_event structures from the device, as described in <linux/input.h>. (More details for example here.) The device only returns full structures, and can return more than one structure per read if the buffer is large enough, so it is very easy interface.

All these (both the device and the pseudofiles) are direct Linux kernel-userspace interfaces, and deemed stable by Linux kernel developers. This means that it is safe to rely on them in an application.

In practice, you'll want to access the device in either a separate thread, or a separate process. The separate process allows you to do privilege separation, in case you want to restrict direct access to the device by other applications (when yours is not running); note that even then, you'll probably want to use a separate thread in your Qt application to receive the events from that process and generate the widget events handled by your main thread.

Personally, I'd use a separate process that is started by the application, connecting the two with an Unix domain stream socket (instead of a plain pipe, since sockets are bidirectional) or perhaps two: one socket provides mouse events in whatever format you find comfortable (in native binary format, since they run on the same machine), and one socket is used for control information, for example describing which devices are available, when devices are added or removed, and for the application to select which device is actually used. (I would replace standard input with the former, and standard output with the latter –– or vice versa –– in the separate process. It really is not complicated at all to achieve.)

A separate process also allows you to separate translation logic, if you one day decide to support non-HID devices, say a custom 3D USB controller with its own userspace "driver" application. Just make sure that whatever format you decide to use between the application and the helper process, covers your needs (as opposed to device capabilities).

Note that none of the above is limited to mice or joysticks, the same applies to keyboards, too. The event structures are the same, only the content differs.

  • Related