Search code examples
linuxkeyboardmousetrackpad

Linux get keyboard mouse trackpad activity


I'm looking for a way to detect keyboard, mouse and trackpad activity on Linux. This will probably be a kernel module. I don't care about the details of the input just the fact that something happened. I don't want it to depend on X. From the kernel headers I've noticed that there's a callback method for keyboard input so that doesn't look like too much of a problem.

I've looked at the kernel headers and libevdev but haven't found anything similar for mouse and trackpad input. With an evdev example program that I tried it required the device name in /dev/input that are mostly named event(n). It didn't work with /dev/input/mice. Also, I'm not sure it's a good idea to open a file and keep it open waiting for events?


Solution

  • In your comment you say that you are simply looking at activity to control a keyboard backlight (please update your question if you have sufficient reputation; my edit queue is full), so I would approach this from user space. I see two options, both based on the system device symlinks setup in /dev/input/. I initially suggested using the links in by-id/ but my laptop keyboard and trackpad only show up in by-path/ so the better approach may be to scan here for kbd and mouse entries, but you'll have to test. According to this answer, cameras will also show up in here: https://unix.stackexchange.com/questions/340430/dev-input-what-exactly-is-this

    I assume that in your application the keyboard lights go on with any activity on these devices, and after some timeout they go off. Option one would be to open all the relevant files and put them in a select() loop. The command man 2 select will show you an example program demonstrating how to use this interface if you are unfamiliar. If you are less decrepit than me, I believe the poll() interface is preferred these days - and it is event driven; it doesn't actually poll. Read man 2 poll for more details and to see an example.

    The nice thing about these two interfaces is that they take a timeout so your program can simply test if the timeout triggered to determine if it's time to turn the backlight off.

    Another option would be to use the inotify() system call. This function will indicate which of the file(s) you are monitoring change. This should be more efficient then opening each of the files because you do not have to read the data from the file itself. More information is available in man 7 inotify.

    You can see how this function works by installing the inotify-tools package (this is the Debian/Ubuntu name, other distro package names may differ). For instance, the command:

    sudo inotifywait -m /dev/input/by-path/usb-*
    

    will watch all of my USB input devices and report when they change. You can use this to test which interfaces you want to monitor before committing anything to code. You could even write your daemon in shell script or python this way, but I'm assuming you're using C to control the backlight already. If not, the commandline program inotifywait comes with its own -t <timeout> parameter which could simplify your logic significantly.

    Another thing to note is that these device files may come and go if devices are unplugged or if they go to sleep. If you use inotify() on the /dev/input directory itself you can be alerted of these changes and rescan the entries to know which files to then monitor.

    There is some documentation on these interfaces in the Documentation/ folder provided with the Linux kernel sources. You can also find a copy of this file online: https://www.kernel.org/doc/Documentation/input/input.txt

    As for controlling the keyboard backlight from user space, this appears to depend on your hardware. Based on the answer here https://unix.stackexchange.com/questions/760993/how-to-best-override-behavior-of-keyboard-backlight-key-with-new-custom-driver I found that my laptop keyboard backlight is controllable from the files in /sys/class/leds/dell::kbd_backlight. You may want to see if your system has something similar.

    If you insist on developing code in the kernel, this post may be of use as well: https://unix.stackexchange.com/questions/747697/mouse-input-from-files-dev-input

    Despite my better judgement, here's an 11-line proof of concept implementation:

    #!/bin/bash
    
    while true; do
            # wait for event to turn on backlight
            inotifywait -qq /dev/input/by-id/usb-* || break
            echo LED ON
    
            # wait for silence to turn off backlight
            inotifywait -qq -m -t 5 /dev/input/by-id/usb-*
            echo LED OFF
    done