# [TECH] [2022. VII] DIY Macro-keyboard Using a short Python script, an extra keyboard can easily be configured to serve as custom macro-keyboard. The script relies on the `evdev`package that provides and interface for passing events generated in the kernel directly to userspace. Simulating key presses (and controlling the mouse) can be done with `xdotool`(which allows access to all keys - binded or not), or with Python's `pyautogui`package. ## Setting up and running the macro-keyboard script (1) Detect the input event associated to the keyboard that will be used as a macro-keyboard by examining `/proc/bus/input/devices`. The keyboard will topically be listed multiple times but only one entry will have have contain `Handlers=sysrq kbd leds eventXY` - event of that entry is the keyboard input event. (2) Modify the following script to contain the correct input event and desired macros. ```python #!/usr/bin/env python import os import pyautogui from evdev import InputDevice, categorize, ecodes dev = InputDevice('/dev/input/eventXY') dev.grab() for event in dev.read_loop(): if event.type == ecodes.EV_KEY: key = categorize(event) if key.keystate == key.key_down: if key.keycode == 'KEY_A': ... if key.keycode == 'KEY_B': ... ``` (3) Run the script as root. ### Example macro-keyboard script ```python #!/usr/bin/env python import os import pyautogui from evdev import InputDevice, categorize, ecodes dev = InputDevice('/dev/input/event21') dev.grab() for event in dev.read_loop(): if event.type == ecodes.EV_KEY: key = categorize(event) if key.keystate == key.key_down: if key.keycode == 'KEY_Q': os.system('echo "Macro-Keyboard has been used!"') # call a command if key.keycode == 'KEY_W': os.system('xdotool key dead_greek+Y') # use xdotool to simulate key presses if key.keycode == 'KEY_E': pyautogui.hotkey('win', 'a') # use pyautogui to simulate key presses if key.keycode == 'KEY_R': # use pyautogui to control the mouse pyautogui.move(100, 0) ``` ## Appendix: `xdotool` commands ``` | Command | Description | Example | | -------------------- | -------------------------------------------------------- | -------------------------------------- | | `key` | Simulate a key stroke. | `xdotool key a` | | | Simulate a key stroke with a modifier. | `xdotool key crtl+a` | | | Simulate repeated key strokes. | `xdotool key --repeat 10 --delay 50 a` | | | Simulate a key stroke sequence. | `xdotool key a s d` | | `keydown` | Simulate a key press. | `xdotool keydown a` | | `keyup` | Simulate a key relese. | `xdotool keyup a` | | `click` | Simulate mouse click [1 - left, 2 - middle, 3] | `xdotool click 3` | | `mousemove` | Move the cursor to given point. | `xdotool mousemove 100 100` | | `mousemove_relative` | Move cursor to a point relative to the current position. | `xdotool mousemove_relative 100 100` | ``` ## Appendix: `pyautogui` commands ``` | Command | Description | Example | | ----------- | -------------------------------------------------------------------- | ------------------------------------------------ | | `press` | Simulate a key stroke. | `pyautogui.press('a')` | | `hotkey` | Simulate pressing multiple keys and releasing them in reverse order. | `pyautogui.hotkey('a', 's', 'd')` | | `keyDown` | Simulate a key press. | `pyautogui.keyDown('a')` | | `keyUp` | Simulate a key release. | `pyautogui.keyUp('a')` | | `write` | Type the characters in the string. | `pyautogui.write('Greetins!')` | | `typewrite` | Type the characters in the string wherever at the cursor location. | `pyautogui.typewrite('Greetins!')` | | `click` | Move the cursor and preform clicks. | `pyautogui.click()` | | | | `pyautogui.click(button='right')` | | | | ``pyautogui.click(x=100, y=100, button='right')` | | `moveTo` | Move the cursor. | `pyautogui.moveTo(100,100)` | | `move` | Move the cursor to a point relative to the current position. | `pyautogui.move(100,0)` | ```