This project uses a Raspberry Pi Pico micro controller and an Pimoroni RGB Keypad to provide dynamic app-specific shortcut keys. This will streamline your workflow and increase productivity.
- Assign actions and colors to the keypad keys
- Actions can be...
- keyboard shortcuts
- open a folder (= a new page of key definitions)
- There is a Mac script called
watchdog.py
to enable more actions...- Determine the active application, to load and show app-specific shortcuts
- Launch a Mac application
- Launch a plugin command
- Plugins are included for...
- Audio playback (to act as a sound board)
- Spotify playback
- Philips Hue control
- All key definitions are defined in a JSON file, stored on the Pi Pico
- Define global shortcuts in a
_default
section for both, folders and apps - Use the
_otherwise
section to assign shortcuts for non-defined apps (withwatchdog.py
running on a Mac) - Rotate the keyboard layout clockwise or counter-clockwise (for 3d printed cases) 🆕
- Create your own plugin with the simple plugins system
If you find this project helpful please consider giving it a ⭐️ at GitHub and/or buy me a ☕️. Thanks!
This is an ongoing project. To see the latest changes please take a look at the Changelog.
It is (still)) a very successful experiment in programming with ChatGPT-4 and Copilot. 🤖 I built this without any knowledge of Python or CircuitPython. The goal was to not program it myself but tell ChatGPT-4 what I wanted. This is the result so far. GPT wrote the code and this README as well. This paragraph here is the only piece I am writing myself (and about twenty lines in the CircuitPython code).
Update: I recently started to refactor some code myself now but still use GPT for new features
- Raspberry Pi Pico
- Pimoroni RGB Keypad for Raspberry Pi Pico
- Micro-USB cable to connect the Pi Pico to your computer
- Optional (but strongly suggested): a Mac running the Watchdog script
The code.py
script reads key definitions from a JSON file and maps them to specific key sequences and LED colors. It listens for the currently active application on the host computer and updates the keypad based on the key mappings for the active application.
The watchdog.py
script monitors the currently active application on the host computer and sends its name to the microcontroller connected to the RGB keypad. It also receives action
commands for plugin events. You can use the pad it without, but then you lose the application-specific launch feature. It is currently only available for a Mac.
-
Download this repository.
-
On the Pi Pico
- Install CircuitPython on your Raspberry Pi Pico following the instructions here.
- Install the required CircuitPython libraries by following the instructions here (download). You definatetly need
adafruit_dotstar.mpy
, andadafruit_hid
files/folders in yourlib\
folder. - Add the library rgbkeypad-circuitpython to your
lib
folder. - Copy the contents of the
src/pico
folder to your Raspberry Pi Pico.
-
On the Mac (for running
watchdog.py
)-
Install Python3 on your Mac, e.g. via
brew
. -
Copy the contents of
src/mac
and its sub-folders to your Mac (best in a separate folder). -
Install the needed libraries to the folder. (Use
pip
and therequirements/mac/requirements_mac.txt
file, see here. -
If you want to use the plugins, edit the config files in the
config
directory. -
Run
watchdog.py
, e.g.:python3 watchdog.py --port /dev/cu.usbmodem2101 --verbose
-
-
Defining keyboard layout
- Edit the
key_def.json
file to configure the shortcut keys and colors for your desired apps. - Note: The first key (top left) has the number
0
and the last one (bottom right) has the number15
. - Install Thonny on your Mac– this IDE makes starting and stopping the Pi Pico easier, as well as editing the
key_def.json
file.
- Edit the
In the key_def.json
configuration file, each app is defined as a JSON object with key-value pairs, with four possible entries: settings
, applications
, folders
, and urls
.
- For details on the
settings
section look here. - In the
applications
section the different keys for various apps are defined with the key numbers (0
-15
). - The
folders
section defines key sets that can be assigned to a single key. - The
urls
section contains keyboard definitions for Safari and Chrome URls.
Applications and URLs are similar in their content. They usually contain shortcut keys for an app or a web site.
Note: The watchdog.py
script cannot detect tab changes in a browser. The current browser tab URL is only detected when Chrome/Firefox becomes active.
You can define four types of keys: shortcut
, application launch
, folder
, and action
, keys.
- Shortcut keys have a
key_sequence
field which specifies the key combination to be executed when the key is pressed. - Application keys have an
application
field which opens or brings the specified application to front when the key is pressed. - Folder keys have an
folder
key. When the key is pressed it will "open" the folder and display its key definitions. - Action keys have an
action
key. They are used to trigger event of plugins or are needed to provide aclose_folder
action for folders
key_sequence
: This field specifies the key combination to be executed when the key is pressed. You can use either a string or an array to specify the key sequence. If a string is provided, it should contain the keycodes separated by '+' (e.g.,CTRL+ALT+T
). If an array is provided, it should contain the keycodes as separate elements (e.g.,["CTRL", "ALT", "T"]
). You can also add delays between key presses within a shortcut by including a floating-point number in the list of keys for a specific shortcut in thekey_def.json
file. This number represents the delay in seconds between key presses. You can find a list of possible keycodes here.pressedUntilReleased
: Tells the keypad to keep the button pressed until manually released. 🆕
application
: This field is used to specify the application to be launched when an application key is pressed.alias_of
: Only for application entries. This field will tell the keypad to use another applications key definition. All other keys will be ignored. 🆕
-
folder
: This field allows you assign a folder (a set of key definitions) to be opened. A folder will auto-close per default, ohter actions has been triggered inside. Folders can also be nested. -
"autoclose": "false"
will keep a folder active after a key has been pressed. 🆕 -
action
: It is mandatory inside a folder definition without theautoclose
setting. -
ignore_default": "true"
will don't ignore the global definitions and don't add them to a folder or an application.
action
: This field can have the valuesclose_folder
or an plugin command, e.g.spotify.next
.ignore_default": "true"
will don't ignore the global definitions and don't add them to a folder or an application.
color
: This field specifies the color of the key, in RGB format. You can specify the color of the key using an RGB string (e.g.,#FF0000
for red,#00FF00
for green,#0000FF
for blue).pressedColor
allows you to define a color for while the button is pressed 🆕toggleColor
allows you to define a color to show an active state 🆕description
: This optional field provides a description of the function of the key, which is useful for understanding the purpose of each key when printed in the console.
Here is an example configuration file:
{
"settings": {
"rotate": "CCW"
},
"applications": {
"_default": {
"15": {
"key_sequence": "GUI+Q",
"color": "#FF0000",
"description": "Close App"
}
},
"zoom.us": {
"0": {
"key_sequence": [
"GUI+SHIFT+A"
],
"color": "#FFFF00",
"description": "Mute/Unmute Audio"
},
"1": {
"key_sequence": [
"GUI+SHIFT+V"
],
"color": "#FFFF00",
"description": "Start/Stop Video"
},
"15": {
"key_sequence": [
"GUI+W",
0.1,
"RETURN"
],
"color": "#FF0000",
"description": "End Meeting"
}
},
"_otherwise": {
"0": {
"key_sequence": [
"GUI+SPACE"
],
"color": "#FFFFFF",
"description": "Open Spotlight Search"
},
"4": {
"action": "spotify.prev",
"color": "#00FF00",
"description": "Spotify - Previous Song"
},
"5": {
"action": "spotify.playpause",
"color": "#00FF00",
"description": "Spotify - Play or Pause"
},
"6": {
"action": "spotify.next",
"color": "#00FF00",
"description": "Spotify - Next Song"
},
"13": {
"folder": "apps",
"color": "#FFFFFF",
"description": "Apps Folder"
}
}
},
"folders": {
"apps": {
"0": {
"action": "close_folder",
"color": "#FFFFFF",
"description": "Close"
},
"12": {
"application": "zoom.us",
"color": "#0000FF",
"description": "Launch Zoom"
},
"13": {
"application": "Slack",
"color": "#FF0000",
"description": "Launch Slack"
}
}
}
}
In the key_def.json
file, you will find a special app key called _otherwise
. This key is used to define shortcut keys that are not specific to any particular app. When the Python script is running, it constantly monitors the active application on your computer, and if the active application matches any of the keys in the JSON file, it will load the relevant shortcut keys onto the keypad. If the active application does not match any of the defined keys, the _otherwise
key is used as a fallback, and the shortcut keys defined under this key are loaded onto the keypad. This means that you can define a set of general-purpose shortcut keys that are always available, regardless of which application is currently active.
In addition you can define a _default
application. These key definitions will be added to all apps and folders. They can be "overwritten" via specific folder or app definition. You can set "ignore_default": "true"
for folders and apps where they should not be used.
The key_def.json
File can also contain a settings
section. There you can define the rotate
parameter (CW
or CCW
– clockwise or counter-clockwise). This will rotate the keyboard layout. This is useful when using the keypad in some 3D printed cases. 🆕
You can build your own plugins for the keypad. They are stored in the plugins/
folder. A plugin defines set of commands that can be used in the action
key in the JSON config. In the JSON above you can see three commands being called in the _otherwise
section. If needed, the plugin can have a config file to load settings.
As an example I included a Spotify plugin called spotify.py. The Spotify plugin has the following commands:
spotify.play
spotify.pause
spotify.playpause
spotify.next
spotify.prev
spotify.volume_up
spotify.volume_down
To use it you need to have a Spotify premium account and need to add you API credentials to the spotify.json config file.
hue.turn_off [Lamp ID | 'Lamp Name']
hue.turn_on [Lamp ID | 'Lamp Name']
hue.turn_toggle [Lamp ID | 'Lamp Name']
You need to define the IP address of your hue bridge in the config JSON and press its connect button on first run. Provide the ID of your lamp or its name enclosed in single quotes.
sounds.play ['File Name']
sounds.stop
The plugin can playback .wav
and .mp3
files.
To enable the dynamic detection of the active app, you need to run the watchdog script on your computer that sends the active app's name to the Pi Pico via USB serial. This project includes a Python watchdog script for Mac OS.
To run the watchdog script, navigate to the directory containing the watchdog.py
file and execute the following command, e.g.:
python3 watchdog.py --port /dev/cu.usbmodem2101 --speed 9600 --verbose
- The
--port
parameter needs to be set to the USB serial port corresponding to your Raspberry Pi Pico (e.g.,/dev/cu.usbmodem2101
). - The optional
--speed
parameter should be set to the desired baud rate for the serial communication (default:9600
). - If the optional
--verbose
parameter is set, the current app will be printed to the console. - With the optional
--rotate
parameter you can rotate the keypad layout clockwise (CW
) or counter-clockwise (CCW
). 🆕
When the watchdog script detects a change in the active app, it sends the app's name as a single line over the USB serial connection. The Pi Pico then reads this information, loads the corresponding shortcuts from the key_def.json
file, and updates the keypad accordingly.
- As you can see in the picture above I use a 3d printed case. You can get it here.
- Since the case rotates the keypad, I added a
settings
section and arotate
option for the keyboard layout.