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)` |
```