Turn a cheap macro pad into an app-aware command deck. Detects the focused app, switches key/knob layers per app, and shows a toggleable on-screen HUD of the current layer's shortcuts.
- Stack: Python 3.11 + PySide6 (Qt). No compiler; just run it.
- Config:
settings.json(global) +profiles.json(per-app layers) — add apps and shortcuts via the files or the GUI editor, never a rebuild. - Platform: Windows first, Linux later (only the key listener + active-window detector are OS-specific).
pip install -r requirements.txt
pythonw src/main.py # seeds settings.json + profiles.json from the examples
Then use the tray icon: Toggle HUD, Open Editor, Back up profiles.
Run at login: python scripts/install_autostart.py.
| File | Holds |
|---|---|
settings.json |
HUD options, auto-switch mode, and the controls map (signal → control id) |
profiles.json |
just the profiles, so it can be backed up or shared on its own |
backups/ |
timestamped copies of profiles.json, written on every save (last 20 kept) |
Action types: shortcut (keys to the focused app), open (URL, obsidian://, file, app, or
a command line with arguments — one type, resolved by the target), text, and cmdpad for
commandpad's own actions: hud.toggle, profile.next, profile.prev, profile.default.
cmdpad actions drive the app, never the OS — they send no keystrokes, so they can't
collide with an application shortcut. The HUD toggle is one of them (bind it to any control,
or use the tray); there is no reserved control and no global hotkey.
In the editor the preset picker follows the Type: Shortcut lists the common commands, cmd Pad lists only the internal ones, Open and Text have none and it's disabled.
Play / Pause / Next track / Previous track are OS media keys: they reach whichever tab is
playing even when Chrome isn't focused. Windows has no media key for seeking, so
scrubbing has to use the player's own keys, which means the page must be focused (click the
video once): ←/→ seek ±5s on most HTML5 players (±10s on Netflix), and J/L/K
(±10s, play/pause) plus ,/. (frame step) are YouTube's. Because those are plain letters,
keep them in a title-matched profile ("match": {"title": "YouTube"}) rather than a
process-wide Chrome one — a title match wins over a process match, so typing stays safe in
other tabs.
Auto profile switching (settings.auto_switch):
on— follow the focused app; a manual switch lasts until you change appstoggle— follow apps, but a manual switch sticks until you switch backoff— manual only
Bind profile actions in every profile you want to switch away from — a profile with no
switch key can only be left by changing apps or using the editor.
python scripts/show_signals.py prints the signal each key/knob emits for the controls map.