Some stuff with keyboard and mouse events

· 2min · Dmitry Scherbakov

Blocking keyboard/mouse inputs

  1. Setup DISPLAY environment variable. Usually, it is set to just :0. If default way does not work, you can try to find the process, which is already running wth GDI and see its environment variables. To check process environment variables, use:

    grep DISPLAY <(xargs -n 1 -0 </proc/<pid>/environ)
    
  2. Make sure xinput is installed, otherwise:

    # Debian, Ubuntu, ...
    apt-get install -y xinput
    
    # Arch, Artix, ...
    pacman -S xorg-xinput
    
  3. Use xinput list to view all devices. Possible output for this command:

    ⎡ Virtual core pointer                    	    id=2	[master pointer  (3)]
    ⎜   ↳ Virtual core XTEST pointer              	id=4	[slave  pointer  (2)]
    ⎜   ↳ VMware VMware Virtual USB Mouse         	id=6	[slave  pointer  (2)]
    ⎜   ↳ VMware VMware Virtual USB Mouse         	id=7	[slave  pointer  (2)]
    ⎣ Virtual core keyboard                   	    id=3	[master keyboard (2)]
        ↳ Virtual core XTEST keyboard             	id=5	[slave  keyboard (3)]
        ↳ VMware VMware Virtual USB Keyboard      	id=8	[slave  keyboard (3)]
    

    Notice that actual keyboard (marked as 'slave') has the id of 8. Virtual keyboard (marked as 'master') has the id of 3.

  4. Disable the device:

    xinput float <device-id>
    
  5. Enable the device back:

    xinput reattaach <device-id> <master-id>
    

Capturing keyboard/mouse events on Linux

Capturing keyboard and mouse on linux is quite complicated job, since it uses pretty old and really unusable X11 API. Wayland seems to only quite get off the ground, so this guide does not cover Wayland. The best solution so far is to use linux /dev filesystem to monitor mouse and keyboard devices. Doing this in C is quite complicated as well so here is a python code, which will do the work for you:

import pynput
import signal

from typing import Union


def on_click(x: Union[int, float],
             y: Union[int, float],
             button: pynput.mouse.Button,
             pressed: bool) -> None:
    """Mouse button event handler."""
    print(button)


def on_press(key: pynput.keyboard.Key) -> None:
    """Key press/character event handler."""


def on_release(key: pynput.keyboard.Key) -> None:
    """Key release event handler."""


def on_exit(*_) -> None:
    """Signal handler."""
    sys.exit(0)


def main() -> int:
    signal.signal(signal.SIGINT, on_exit)
    signal.signal(signal.SIGTERM, on_exit)

    mouse_listener = pynput.mouse.Listener(on_click=on_click)
    mouse_listener.start()

    keyboard_listener = pynput.keyboard.Listener(on_press=on_press,
                                                 on_release=on_release)
    keyboard_listener.start()


if __name__ == "__main__":
    main()

This code uses pynput library, which works for linux and windows (does not work on MacOS Sonoma, last tested 18 Apr 2024). You can install this library with python3 -m pip install pynput command.

Capturing keyboard/mouse events on Windows

This can be done either with hook procedures (specifically take a look at keyboard proc and mouse proc) or with the same pynput library, which does the job for linux systems.