Open hatl opened 2 years ago
I am going to need a lot more detail about how this would work. A proof-of-concept would be ideal. If it is possible I don't mind adding it to 1.3 which is currently in progress and overhauls a lot of the Linux code.
Thanks for the quick reply! Maybe the evsieve code can serve as a basis. It seems to work really well.
Apologies, I thought I responded to this weeks ago but just noticed I never submitted my response.
I've read though the readme and it looks like it is interacting with /dev/input which would require additional permissions and why this library doesn't currently use /dev/input. I'll leave this open for a while and revisit the idea of /dev/input in the future.
This might also be needed for support of Wayland. Unless Wayland on Linux is not a goal of this project?
I'm also interested in Wayland and dev/input
support.
Could this potentially be a configurable option? 👀
Thanks! 💯
After a lot of thought, evdev
will be the way forward for both Linux and BSD support. It is going to be a monumental undertaking to implement so if anyone wants to help make this happen, please reach out. I will start look at this again after I finish refactoring a lot of the existing code but I don't think this will make it into 1.3.
Consider this as a bit of a self-plug. I've personally used libevdev
to perform input simulation and capturing on Linux as part of my software KVM switch uni project. The repo for that is here (a lot of refactoring can be done with it). Imo, it seemed quite okay to work with, so hopefully it doesn't cause many issues if you decide to implement evdev
in the future. 💯
I was just looking at libevdev which looks like its going to deal with most of the heavy lifting. The biggest problem I am aware of is that the mouse coordinates are all relative which is both good and bad. I would need to figure out a way to get those relative coordinates mapped on to the desktop environment.
Could that not be performed with a display-server-specific function call for X11 and Wayland? Correct me if I'm wrong 💯
Do any of you know how to consume events with libevdev? I am working on setting up epoll and event hooking but I have no idea how to prevent event propagation.
The way that I have done it was by calling ::libevdev_grab(input, LIBEVDEV_GRAB)
where input
is a libevdev*
. To get a libevdev*
, I used ::libevdev_new_from_fd
for each symlink present in /dev/input/by-path
that ends with -event-mouse
or -event-kbd
. If you go down this route, IIRC the device file needs to be kept open until the hook is finished. In a relevant destructor you can then call libevdev_free
and close
the file descriptor, in that order.
I've not used epoll
before and instead used ::libevdev_next_event
with the LIBEVDEV_READ_FLAG_BLOCKING
as I had this running on a separate thread that I wanted to block.
@szymonj99 thanks for the info, the only example I've found is this where it kind of proxies what is read to something created with libevdev_uinput_create_from_device
after grabbing with libevdev_grab
. Is that +/- the correct approach? If so, what happens if the program is run multiple times, do we get a proxy chain that just grows?
When I was working with libevdev, I've never tried running the program multiple times, but I assume it would not be optimal 😆 How the events would get passed along I'm not too sure, but if the libevdev device is grabbed, then I would assume that only the first process that grabs the device would see the events, and they wouldn't be passed further. This would mirror the normal behaviour when a libevdev process grabs the device, and the display server etc. does not see the events.
In my program, I've turned the class responsible for interacting with libevdev
into a singleton to avoid usage that could lead to unexpected behaviour. You could use a named semaphore to further prevent issues that could arise when users try running a program multiple times.
IIRC, you only need to call either ::libevdev_from_fd
or ::libevdev_uinput_create_from_device
, not both. Then you call ::libevdev_grab
and that is it. In my program, I used the former and had no issues with it (apart from needing either sudo permissions or for the user to be in a specific input group). Then call ::libevdev_next_event
in a loop.
Good news and bad news.
I've got it things more or less working with libevdev. The bad news is that libevdev_uinput_write_event
requires access to /dev/uinput
which seems to be owned and grouped to root with 600 permissions. I don't know if this is the standard, or if this is how my distribution does things.
It is pretty easy to override the permissions with a /etc/udev/rules.d/99-libuiohook.rules
file containing something like this:
SUBSYSTEM=="misc", KERNEL=="uinput", GROUP="input", MODE="0660"
After running udevadm control --reload-rules && udevadm trigger
, /dev/uinput
will now be owned by root and grouped to input with mode 0660. This matches the default behavior for /dev/input
on my distribution, but again, I don't know how other distributions do these permissions. You may need to add modules="uinput"
to /etc/conf.d/modules
if it is a module and not loaded by default
If we stick with evdev we would likely need to use one of these udev rules to make permissions more permissive. This isn't the end of the world, but it is definitely inconvenient. I would also need to verify that this solution works on at least a few other distributions. I don't use systemd so there maybe other issues.
Other options. There is libinput which sits a bit further up the stack and does not require any special permissions or udev rules. I believe there are some x11 compatibility here so this makes it an appealing choices when trying to support both environments. Con is that you couldn't use it outside of the window environment like x11 or wayland which was a feature ask at some point.
Thoughts?
On other platforms, it's possible to consume an event by setting reserved to 1. Under Linux, this could be done by "grabbing" the device(s) when using evdev. And then forward events to a new virtual device if reserved is 0. This solution would work for X11 and Wayland.
What do you think?
BTW: this is how evsieve works