|
| 1 | +# Keybindings |
| 2 | + |
| 3 | +YASB supports global keyboard shortcuts (hotkeys) to trigger widget actions. Keybindings are configured per-widget in the widget's `options` section. This feature uses native Windows low-level keyboard hooks and requires no third-party dependencies. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +- **Per-widget instance**: Keybindings are tied to the specific widget name in your config (e.g., `clock` vs `clock_2`) |
| 8 | +- **Multiple keybindings**: A single widget can have multiple keybindings for different actions |
| 9 | +- **Screen-aware**: Hotkeys trigger the widget on the currently focused screen |
| 10 | +- **Zero overhead**: If no keybindings are defined, no hotkey listener is started |
| 11 | + |
| 12 | +## Configuration |
| 13 | + |
| 14 | +Add a `keybindings` list to any widget's options. Each keybinding requires: |
| 15 | +- `keys`: The key combination (e.g., `"win+c"`, `"ctrl+shift+f1"`) |
| 16 | +- `action`: The callback action to trigger (e.g., `"toggle_calendar"`, `"toggle_label"`) |
| 17 | + |
| 18 | +### Basic Example |
| 19 | + |
| 20 | +```yaml |
| 21 | +clock: |
| 22 | + type: "yasb.clock.ClockWidget" |
| 23 | + options: |
| 24 | + label: "{%H:%M}" |
| 25 | + keybindings: |
| 26 | + - keys: "win+c" |
| 27 | + action: "toggle_calendar" |
| 28 | + - keys: "ctrl+shift+t" |
| 29 | + action: "toggle_label" |
| 30 | +``` |
| 31 | +
|
| 32 | +### Multiple Widgets Example |
| 33 | +
|
| 34 | +```yaml |
| 35 | +clock: |
| 36 | + type: "yasb.clock.ClockWidget" |
| 37 | + options: |
| 38 | + keybindings: |
| 39 | + - keys: "win+c" |
| 40 | + action: "toggle_calendar" |
| 41 | + |
| 42 | +volume: |
| 43 | + type: "yasb.volume.VolumeWidget" |
| 44 | + options: |
| 45 | + keybindings: |
| 46 | + - keys: "win+v" |
| 47 | + action: "toggle_menu" |
| 48 | +``` |
| 49 | +
|
| 50 | +## Supported Keys |
| 51 | +
|
| 52 | +### Modifier Keys |
| 53 | +
|
| 54 | +| Key Name | Description | |
| 55 | +|----------|-------------| |
| 56 | +| `win`, `windows`, `super`, `meta` | Either Windows key (left or right) | |
| 57 | +| `lwin`, `leftwin`, `left_win` | Left Windows key only | |
| 58 | +| `rwin`, `rightwin`, `right_win` | Right Windows key only | |
| 59 | +| `alt` | Either Alt key (left or right) | |
| 60 | +| `lalt`, `leftalt`, `left_alt` | Left Alt key only | |
| 61 | +| `ralt`, `rightalt`, `right_alt` | Right Alt key only | |
| 62 | +| `ctrl`, `control` | Either Control key (left or right) | |
| 63 | +| `lctrl`, `leftctrl`, `left_ctrl` | Left Control key only | |
| 64 | +| `rctrl`, `rightctrl`, `right_ctrl` | Right Control key only | |
| 65 | +| `shift` | Shift key | |
| 66 | + |
| 67 | +### Function Keys |
| 68 | + |
| 69 | +| Key Name | Description | |
| 70 | +|----------|-------------| |
| 71 | +| `f1` - `f24` | Function keys F1 through F24 | |
| 72 | + |
| 73 | +### Letter and Number Keys |
| 74 | + |
| 75 | +| Key Name | Description | |
| 76 | +|----------|-------------| |
| 77 | +| `a` - `z` | Letter keys (case-insensitive) | |
| 78 | +| `0` - `9` | Number keys | |
| 79 | + |
| 80 | +### Special Keys |
| 81 | + |
| 82 | +| Key Name | Aliases | Description | |
| 83 | +|----------|---------|-------------| |
| 84 | +| `space` | | Spacebar | |
| 85 | +| `tab` | | Tab key | |
| 86 | +| `enter`, `return` | | Enter/Return key | |
| 87 | +| `esc`, `escape` | | Escape key | |
| 88 | +| `backspace` | | Backspace key | |
| 89 | +| `delete`, `del` | | Delete key | |
| 90 | +| `insert`, `ins` | | Insert key | |
| 91 | +| `home` | | Home key | |
| 92 | +| `end` | | End key | |
| 93 | +| `pageup`, `pgup` | | Page Up key | |
| 94 | +| `pagedown`, `pgdn` | | Page Down key | |
| 95 | +| `pause` | | Pause key | |
| 96 | +| `capslock`, `caps` | | Caps Lock key | |
| 97 | +| `numlock` | | Num Lock key | |
| 98 | +| `scrolllock` | | Scroll Lock key | |
| 99 | +| `printscreen`, `prtsc` | | Print Screen key | |
| 100 | + |
| 101 | +### Arrow Keys |
| 102 | + |
| 103 | +| Key Name | Description | |
| 104 | +|----------|-------------| |
| 105 | +| `left` | Left arrow | |
| 106 | +| `up` | Up arrow | |
| 107 | +| `right` | Right arrow | |
| 108 | +| `down` | Down arrow | |
| 109 | + |
| 110 | +### Numpad Keys |
| 111 | + |
| 112 | +| Key Name | Description | |
| 113 | +|----------|-------------| |
| 114 | +| `numpad0` - `numpad9` | Numpad number keys | |
| 115 | +| `multiply` | Numpad * | |
| 116 | +| `add` | Numpad + | |
| 117 | +| `subtract` | Numpad - | |
| 118 | +| `decimal` | Numpad . | |
| 119 | +| `divide` | Numpad / | |
| 120 | + |
| 121 | +### Punctuation and Symbol Keys |
| 122 | + |
| 123 | +| Key Name | Description | |
| 124 | +|----------|-------------| |
| 125 | +| `semicolon` | ; key | |
| 126 | +| `equal`, `equals` | = key | |
| 127 | +| `comma` | , key | |
| 128 | +| `minus` | - key | |
| 129 | +| `period` | . key | |
| 130 | +| `slash` | / key | |
| 131 | +| `backquote`, `grave` | \` key | |
| 132 | +| `bracketleft` | [ key | |
| 133 | +| `bracketright` | ] key | |
| 134 | +| `backslash` | \\ key | |
| 135 | +| `quote` | ' key | |
| 136 | + |
| 137 | +## Win Key Specificity |
| 138 | + |
| 139 | +YASB supports distinguishing between the left and right Windows keys: |
| 140 | + |
| 141 | +| Configuration | Behavior | |
| 142 | +|--------------|----------| |
| 143 | +| `"win+c"` | Triggered by **either** left or right Win key + C | |
| 144 | +| `"lwin+c"` | Triggered **only** by left Win key + C | |
| 145 | +| `"rwin+c"` | Triggered **only** by right Win key + C | |
| 146 | + |
| 147 | +### Example: Different Actions for Left/Right Win |
| 148 | + |
| 149 | +```yaml |
| 150 | +clock: |
| 151 | + type: "yasb.clock.ClockWidget" |
| 152 | + options: |
| 153 | + keybindings: |
| 154 | + - keys: "lwin+c" |
| 155 | + action: "toggle_calendar" |
| 156 | + - keys: "rwin+c" |
| 157 | + action: "toggle_label" |
| 158 | +``` |
| 159 | + |
| 160 | +## Alt/Ctrl Key Specificity |
| 161 | + |
| 162 | +Similarly, you can distinguish between left and right Alt or Ctrl keys: |
| 163 | + |
| 164 | +| Configuration | Behavior | |
| 165 | +|--------------|----------| |
| 166 | +| `"alt+x"` | Triggered by **either** left or right Alt key + X | |
| 167 | +| `"lalt+x"` | Triggered **only** by left Alt key + X | |
| 168 | +| `"ralt+x"` | Triggered **only** by right Alt key + X | |
| 169 | +| `"ctrl+x"` | Triggered by **either** left or right Ctrl key + X | |
| 170 | +| `"lctrl+x"` | Triggered **only** by left Ctrl key + X | |
| 171 | +| `"rctrl+x"` | Triggered **only** by right Ctrl key + X | |
| 172 | + |
| 173 | +### Example: Left Alt vs Right Alt |
| 174 | + |
| 175 | +```yaml |
| 176 | +volume: |
| 177 | + type: "yasb.volume.VolumeWidget" |
| 178 | + options: |
| 179 | + keybindings: |
| 180 | + - keys: "lalt+v" |
| 181 | + action: "toggle_menu" |
| 182 | + - keys: "ralt+v" |
| 183 | + action: "toggle_mute" |
| 184 | +``` |
| 185 | + |
| 186 | +## Extra Modifier Rejection |
| 187 | + |
| 188 | +YASB uses **exact modifier matching**. If you register `alt+x`, pressing `ctrl+alt+x` will **not** trigger it because Ctrl is an extra modifier that wasn't specified. |
| 189 | + |
| 190 | +| Registered | User Presses | Result | |
| 191 | +|------------|--------------|--------| |
| 192 | +| `alt+x` | Alt + X | Triggers | |
| 193 | +| `alt+x` | Ctrl + Alt + X | Blocked (extra Ctrl) | |
| 194 | +| `ctrl+alt+x` | Ctrl + Alt + X | Triggers | |
| 195 | +| `ctrl+alt+x` | Ctrl + Alt + Shift + X | Blocked (extra Shift) | |
| 196 | + |
| 197 | +This prevents accidental triggers when using similar hotkeys in other applications. |
| 198 | + |
| 199 | +## Limitations |
| 200 | + |
| 201 | +### No Multi-Key Combos |
| 202 | + |
| 203 | +YASB only supports **modifier + single key** combinations. You cannot bind multiple non-modifier keys together: |
| 204 | + |
| 205 | +| Configuration | Valid | |
| 206 | +|--------------|-------| |
| 207 | +| `"alt+a"` | Yes | |
| 208 | +| `"ctrl+shift+f1"` | Yes | |
| 209 | +| `"a+b"` | No - two non-modifier keys | |
| 210 | +| `"ctrl+a+b"` | No - two non-modifier keys | |
| 211 | + |
| 212 | +### Modifier-Only Hotkeys Not Supported |
| 213 | + |
| 214 | +You cannot use a modifier key alone as a hotkey: |
| 215 | + |
| 216 | +| Configuration | Valid | |
| 217 | +|--------------|-------| |
| 218 | +| `"ctrl"` | No - no main key | |
| 219 | +| `"alt+shift"` | No - no main key | |
| 220 | +| `"win+a"` | Yes | |
| 221 | + |
| 222 | +### Press Order Matters |
| 223 | + |
| 224 | +Hotkeys are triggered when the **main key** is pressed while modifiers are held. This means: |
| 225 | + |
| 226 | +- Hold Alt, then press X → Triggers `alt+x` |
| 227 | +- Hold X, then press Alt → Does NOT trigger `alt+x` |
| 228 | + |
| 229 | +This is standard behavior for all hotkey systems (Windows `RegisterHotKey`, AutoHotkey, etc.). |
| 230 | + |
| 231 | +## Available Actions |
| 232 | + |
| 233 | +Each widget has its own set of available callback actions. Common actions include: |
| 234 | + |
| 235 | +| Action | Description | |
| 236 | +|--------|-------------| |
| 237 | +| `toggle_label` | Toggle between primary and alternate label | |
| 238 | +| `toggle_menu` | Show/hide the widget's menu | |
| 239 | +| `update_label` | Force refresh the widget label | |
| 240 | +| `do_nothing` | No action (useful for disabling) | |
| 241 | + |
| 242 | +Refer to individual widget documentation for widget-specific actions. For example, the Clock widget supports: |
| 243 | +- `toggle_calendar` - Show/hide calendar popup |
| 244 | +- `toggle_label` - Toggle between label formats |
| 245 | +- `next_timezone` - Cycle to next timezone |
| 246 | +- `context_menu` - Show context menu |
| 247 | + |
| 248 | +## Screen Targeting |
| 249 | + |
| 250 | +When a hotkey is triggered, YASB determines which screen's widget should respond based on: |
| 251 | +1. The currently focused window's screen |
| 252 | +2. If no window is focused, falls back to the primary screen |
| 253 | + |
| 254 | +This means pressing `win+c` will toggle the calendar on the monitor where you're currently working. |
| 255 | + |
| 256 | +## Conflict Handling |
| 257 | + |
| 258 | +If the same key combination is assigned to multiple widgets, YASB will: |
| 259 | +1. Log a warning message indicating the conflict |
| 260 | +2. Use the **last** defined keybinding (later widgets override earlier ones) |
| 261 | + |
| 262 | +``` |
| 263 | +WARNING: Hotkey conflict: 'win+c' is already assigned to 'yasb.clock.ClockWidget', |
| 264 | +overriding with 'yasb.volume.VolumeWidget' |
| 265 | +``` |
| 266 | +
|
| 267 | +To avoid conflicts, use unique key combinations for each widget action. |
| 268 | +
|
| 269 | +## Troubleshooting |
| 270 | +
|
| 271 | +### Hotkey Not Working |
| 272 | +
|
| 273 | +1. **Check the logs**: Enable debug logging to see if the hotkey is being registered |
| 274 | +2. **Verify key names**: Ensure you're using supported key names from the tables above |
| 275 | +3. **Check for conflicts**: Another application might be using the same hotkey |
| 276 | +4. **Elevated apps**: If an elevated (admin) application has focus, hotkeys may not be captured due to Windows UIPI security. This is normal - hotkeys will work again once a non-elevated window has focus |
| 277 | +
|
| 278 | +### Hotkey Conflicts with Windows |
| 279 | +
|
| 280 | +Some key combinations are reserved by Windows and may not work: |
| 281 | +- `win+l` (Lock screen) |
| 282 | +- `ctrl+alt+del` (Security options) |
| 283 | +
|
| 284 | +Consider using alternative combinations or disabling the Windows shortcuts via Group Policy if needed. |
| 285 | +
|
| 286 | +### Keybinding Not in Config |
| 287 | +
|
| 288 | +If you don't define any `keybindings` in your widget options, the hotkey listener won't start at all. When keybindings are configured, the listener uses a low-level keyboard hook which has negligible overhead. |
0 commit comments