diff --git a/README.md b/README.md
index c6bb932..451701e 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@


-[KDE & apps](#configs) · [Packages](#package-sections) · [Setup](docs/setup.md)
+[KDE & apps](#configs) · [Shortcuts](docs/shortcuts.md) · [Packages](#package-sections) · [Setup](docs/setup.md)
diff --git a/docs/shortcuts.md b/docs/shortcuts.md
new file mode 100644
index 0000000..4515bfe
--- /dev/null
+++ b/docs/shortcuts.md
@@ -0,0 +1,473 @@
+# KDE shortcuts
+
+Generated from the repo’s captured `kglobalshortcutsrc`. This describes
+Fiw’s bindings as configured; applying them is a separate installer action.
+It covers KDE global shortcuts, not every shortcut inside individual applications.
+
+**67 assigned actions · 193 unassigned actions · 260 total**
+
+`Meta` is the Super/Windows key. In the full tables, multiple keys for
+one action are alternatives. Grouped summary keys match the named actions
+in order. “Unassigned” means explicitly disabled in this capture;
+a key in the KDE default column is not an active binding. The default
+column is copied from KDE’s stored values, not inferred from a release.
+
+## Everyday bindings
+
+| Keys | Action |
+|---|---|
+| Meta | Open application launcher |
+| Meta+Space | Open KRunner |
+| Meta+Q | Open Kitty |
+| Alt+S
Meta+Shift+S | Select a screenshot region |
+| Print
Alt+D | Screenshot monitor under pointer |
+| Meta+V | Show clipboard history at pointer |
+| Meta+1
Meta+2
Meta+3 | Switch to desktop 1 / 2 / 3 |
+| Meta+!
Meta+@
Meta+# | Move window to desktop 1 / 2 / 3 |
+| Meta+Ctrl+Left
Meta+Ctrl+Right
Meta+Ctrl+Up
Meta+Ctrl+Down | Switch desktop left / right / up / down |
+| Meta+Left
Meta+Right
Meta+Up
Meta+Down | Tile window left / right / up / down |
+| Meta+Shift+Left
Meta+Shift+Right | Move window to previous / next screen |
+| Meta+F | Maximize window |
+| Meta+W | Toggle Overview |
+| Meta+G | Toggle desktop grid |
+| Meta+A
Meta+Shift+A | Next / previous activity |
+| Screensaver
Meta+L | Lock session |
+| Ctrl+Alt+Del | Show logout screen |
+
+Screenshot bindings use `fiw-shot`: copy to clipboard, then offer Save
+or Edit in the notification. They need Spectacle, `wl-copy` and
+`notify-send`; Kitty and KRunner bindings need their respective apps.
+The native Spectacle bindings are unassigned to avoid competing actions.
+
+The desktop-move bindings are stored as literal symbols (`!`, `@`, `#`).
+On a US layout these usually mean Shift+1/2/3; other layouts can differ.
+The keyboard-layout preset contains US English, Russian and Spanish;
+`Meta+Alt+Space` cycles through them. Shortcut restoration does not
+create three virtual desktops or activities on a new installation.
+
+## Captured choices
+
+Forward window switching is currently unassigned; reverse switching
+uses `Alt+Shift+Tab` and `Meta+Shift+Tab`.
+
+Other currently unassigned shortcuts include Peek at Desktop (`Meta+D`
+in the default column), Minimize (`Meta+PgDown`), Restore
+(`Meta+Backspace`) and the window menu (`Alt+F3`). FiwNode’s four
+recorded global actions are unassigned. `Meta+1/2/3` are used for
+desktops, with the corresponding task-manager shortcuts disabled.
+
+## All assigned actions
+
+### Keyboard Layout Switcher
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Switch to Next Keyboard Layout | Meta+Alt+Space | Meta+Alt+K |
+
+### Accessibility
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Toggle Screen Reader On and Off | Meta+Alt+S | Meta+Alt+S |
+
+### Audio Volume
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Decrease Microphone Volume | Microphone Volume Down | Microphone Volume Down |
+| Decrease Volume | Volume Down | Volume Down |
+| Decrease Volume by 1% | Shift+Volume Down | Shift+Volume Down |
+| Increase Microphone Volume | Microphone Volume Up | Microphone Volume Up |
+| Increase Volume | Volume Up | Volume Up |
+| Increase Volume by 1% | Shift+Volume Up | Shift+Volume Up |
+| Mute Microphone | Microphone Mute
Meta+Volume Mute | Microphone Mute
Meta+Volume Mute |
+| Mute | Volume Mute | Volume Mute |
+
+### Session Management
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Lock Session | Screensaver
Meta+L | Screensaver
Meta+L |
+| Show Logout Screen | Ctrl+Alt+Del | Ctrl+Alt+Del |
+
+### KWin
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Activate Window Demanding Attention | Meta+Ctrl+A | Meta+Ctrl+A |
+| Toggle Present Windows (Current desktop) | Ctrl+F9
Meta+F9 | Ctrl+F9
Meta+F9 |
+| Toggle Present Windows (All desktops) | Launch (C)
Ctrl+F10
Meta+F10 | Launch (C)
Ctrl+F10
Meta+F10 |
+| Toggle Present Windows (Window class) | Ctrl+F7
Meta+F7 | Ctrl+F7
Meta+F7 |
+| Toggle Grid View | Meta+G | Meta+G |
+| Kill Window | Meta+Ctrl+Esc | Meta+Ctrl+Esc |
+| Toggle Overview | Meta+W | Meta+W |
+| Switch One Desktop Down | Meta+Ctrl+Down | Meta+Ctrl+Down |
+| Switch One Desktop Up | Meta+Ctrl+Up | Meta+Ctrl+Up |
+| Switch One Desktop to the Left | Meta+Ctrl+Left | Meta+Ctrl+Left |
+| Switch One Desktop to the Right | Meta+Ctrl+Right | Meta+Ctrl+Right |
+| Switch to Desktop 1 | Meta+1 | Ctrl+F1
Meta+F1 |
+| Switch to Desktop 2 | Meta+2 | Ctrl+F2
Meta+F2 |
+| Switch to Desktop 3 | Meta+3 | Ctrl+F3
Meta+F3 |
+| Walk Through Windows (Reverse) | Alt+Shift+Tab
Meta+Shift+Tab | Alt+Shift+Tab
Meta+Shift+Tab |
+| Close Window | Alt+F4 | Alt+F4 |
+| Maximize Window | Meta+F | Meta+PgUp |
+| Quick Tile Window to the Bottom | Meta+Down | Meta+Down |
+| Quick Tile Window to the Left | Meta+Left | Meta+Left |
+| Quick Tile Window to the Right | Meta+Right | Meta+Right |
+| Quick Tile Window to the Top | Meta+Up | Meta+Up |
+| Window to Desktop 1 | Meta+! | Unassigned |
+| Window to Desktop 2 | Meta+@ | Unassigned |
+| Window to Desktop 3 | Meta+# | Unassigned |
+| Move Window to Next Screen | Meta+Shift+Right | Meta+Shift+Right |
+| Move Window to Previous Screen | Meta+Shift+Left | Meta+Shift+Left |
+| Zoom to Actual Size | Meta+0 | Meta+0 |
+| Zoom In | Meta++
Meta+= | Meta++
Meta+= |
+| Zoom Out | Meta+- | Meta+- |
+
+### Media Controller
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Media playback next | Media Next | Media Next |
+| Pause media playback | Media Pause | Media Pause |
+| Play/Pause media playback | Media Play | Media Play |
+| Media playback previous | Media Previous | Media Previous |
+| Media playback seek backward 5s | Media Rewind | Media Rewind |
+| Media playback seek forward 5s | Media Fast Forward | Media Fast Forward |
+| Stop media playback | Media Stop | Media Stop |
+
+### Power Management
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Decrease Keyboard Brightness | Keyboard Brightness Down | Keyboard Brightness Down |
+| Decrease Screen Brightness | Monitor Brightness Down | Monitor Brightness Down |
+| Decrease Screen Brightness by 1% | Shift+Monitor Brightness Down | Shift+Monitor Brightness Down |
+| Hibernate | Hibernate | Hibernate |
+| Increase Keyboard Brightness | Keyboard Brightness Up | Keyboard Brightness Up |
+| Increase Screen Brightness | Monitor Brightness Up | Monitor Brightness Up |
+| Increase Screen Brightness by 1% | Shift+Monitor Brightness Up | Shift+Monitor Brightness Up |
+| Power Down | Power Down | Power Down |
+| Power Off | Power Off | Power Off |
+| Suspend | Sleep | Sleep |
+| Toggle Keyboard Backlight | Keyboard Light On/Off | Keyboard Light On/Off |
+
+### plasmashell
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Activate Application Launcher | Meta | Meta
Alt+F1 |
+| Walk through activities | Meta+A | Unassigned |
+| Walk through activities (Reverse) | Meta+Shift+A | Unassigned |
+| Show Clipboard Items at Mouse Position | Meta+V | Meta+V |
+
+### Screenshot region helper
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Screenshot region helper | Alt+S
Meta+Shift+S | — |
+
+### Screenshot monitor helper
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Screenshot monitor helper | Print
Alt+D | — |
+
+### Kitty launcher
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| Kitty launcher | Meta+Q | — |
+
+### KRunner launcher
+
+| Action | Current keys | Stored KDE default |
+|---|---|---|
+| KRunner launcher | Meta+Space | — |
+
+## All unassigned actions
+
+These entries are restored as unassigned, including actions with a
+stored KDE default. Expand each section to review the full capture.
+
+
+Keyboard Layout Switcher (4)
+
+| Action | Stored KDE default |
+|---|---|
+| Switch keyboard layout to English (US) | Unassigned |
+| Switch keyboard layout to Russian | Unassigned |
+| Switch keyboard layout to Spanish | Unassigned |
+| Switch to Last-Used Keyboard Layout | Meta+Alt+L |
+
+
+
+
+FiwNode (4)
+
+| Action | Stored KDE default |
+|---|---|
+| FiwNode: next | Meta+Alt+N |
+| FiwNode: show and search | Meta+Alt+F |
+| FiwNode: stop | Meta+Alt+S |
+| FiwNode: play / pause | Meta+Alt+P |
+
+
+
+
+Audio Volume (1)
+
+| Action | Stored KDE default |
+|---|---|
+| Push to talk | Unassigned |
+
+
+
+
+Session Management (6)
+
+| Action | Stored KDE default |
+|---|---|
+| Shut Down Without Confirmation | Unassigned |
+| Log Out Without Confirmation | Unassigned |
+| Log Out | Unassigned |
+| Reboot | Unassigned |
+| Reboot Without Confirmation | Unassigned |
+| Shut Down | Unassigned |
+
+
+
+
+KWin (138)
+
+| Action | Stored KDE default |
+|---|---|
+| Cycle through Overview and Grid View | Unassigned |
+| Cycle through Grid View and Overview | Unassigned |
+| Decrease Opacity of Active Window by 5% | Unassigned |
+| Toggle Tiles Editor | Meta+T |
+| Toggle Present Windows (Window class on current desktop) | Unassigned |
+| Increase Opacity of Active Window by 5% | Unassigned |
+| Move the tablet to the next output | Unassigned |
+| Move Mouse to Center | Meta+F6 |
+| Move Mouse to Focus | Meta+F5 |
+| Move Zoomed Area Downwards | Unassigned |
+| Move Zoomed Area to Left | Unassigned |
+| Move Zoomed Area to Right | Unassigned |
+| Move Zoomed Area Upwards | Unassigned |
+| Setup Window Shortcut | Unassigned |
+| Peek at Desktop | Meta+D |
+| Switch to Window Below | Meta+Alt+Down |
+| Switch to Window to the Left | Meta+Alt+Left |
+| Switch to Window to the Right | Meta+Alt+Right |
+| Switch to Window Above | Meta+Alt+Up |
+| Switch to Desktop 10 | Unassigned |
+| Switch to Desktop 11 | Unassigned |
+| Switch to Desktop 12 | Unassigned |
+| Switch to Desktop 13 | Unassigned |
+| Switch to Desktop 14 | Unassigned |
+| Switch to Desktop 15 | Unassigned |
+| Switch to Desktop 16 | Unassigned |
+| Switch to Desktop 17 | Unassigned |
+| Switch to Desktop 18 | Unassigned |
+| Switch to Desktop 19 | Unassigned |
+| Switch to Desktop 20 | Unassigned |
+| Switch to Desktop 21 | Unassigned |
+| Switch to Desktop 22 | Unassigned |
+| Switch to Desktop 23 | Unassigned |
+| Switch to Desktop 24 | Unassigned |
+| Switch to Desktop 25 | Unassigned |
+| Switch to Desktop 4 | Ctrl+F4
Meta+F4 |
+| Switch to Desktop 5 | Unassigned |
+| Switch to Desktop 6 | Unassigned |
+| Switch to Desktop 7 | Unassigned |
+| Switch to Desktop 8 | Unassigned |
+| Switch to Desktop 9 | Unassigned |
+| Switch to Next Desktop | Unassigned |
+| Switch to Next Screen | Unassigned |
+| Switch to Previous Desktop | Unassigned |
+| Switch to Previous Screen | Unassigned |
+| Switch to Screen 0 | Unassigned |
+| Switch to Screen 1 | Unassigned |
+| Switch to Screen 2 | Unassigned |
+| Switch to Screen 3 | Unassigned |
+| Switch to Screen 4 | Unassigned |
+| Switch to Screen 5 | Unassigned |
+| Switch to Screen 6 | Unassigned |
+| Switch to Screen 7 | Unassigned |
+| Switch to Screen Above | Unassigned |
+| Switch to Screen Below | Unassigned |
+| Switch to Screen to the Left | Unassigned |
+| Switch to Screen to the Right | Unassigned |
+| Suspend/Resume Night Light | Unassigned |
+| Toggle Window Raise/Lower | Unassigned |
+| Walk Through Windows | Alt+Tab
Meta+Tab |
+| Walk Through Windows Alternative | Unassigned |
+| Walk Through Windows Alternative (Reverse) | Unassigned |
+| Walk Through Windows of Current Application | Alt+`
Meta+` |
+| Walk Through Windows of Current Application (Reverse) | Alt+~
Meta+~ |
+| Walk Through Windows of Current Application Alternative | Unassigned |
+| Walk Through Windows of Current Application Alternative (Reverse) | Unassigned |
+| Keep Window Above Others | Unassigned |
+| Keep Window Below Others | Unassigned |
+| Custom Quick Tile Window to the Bottom | Unassigned |
+| Custom Quick Tile Window to the Left | Unassigned |
+| Custom Quick Tile Window to the Right | Unassigned |
+| Custom Quick Tile Window to the Top | Unassigned |
+| Make Window Fullscreen | Unassigned |
+| Expand Window Horizontally | Unassigned |
+| Expand Window Vertically | Unassigned |
+| Lower Window | Unassigned |
+| Maximize Window Horizontally | Unassigned |
+| Maximize Window Vertically | Unassigned |
+| Minimize Window | Meta+PgDown |
+| Move Window | Unassigned |
+| Move Window to the Center | Unassigned |
+| Toggle Window Titlebar and Frame | Unassigned |
+| Keep Window on All Desktops | Unassigned |
+| Window One Desktop Down | Meta+Ctrl+Shift+Down |
+| Window One Desktop Up | Meta+Ctrl+Shift+Up |
+| Window One Desktop to the Left | Meta+Ctrl+Shift+Left |
+| Window One Desktop to the Right | Meta+Ctrl+Shift+Right |
+| Move Window One Screen Down | Unassigned |
+| Move Window One Screen Up | Unassigned |
+| Move Window One Screen to the Left | Unassigned |
+| Move Window One Screen to the Right | Unassigned |
+| Window Menu | Alt+F3 |
+| Move Window Down | Unassigned |
+| Move Window Left | Unassigned |
+| Move Window Right | Unassigned |
+| Move Window Up | Unassigned |
+| Quick Tile Window to the Bottom Left | Unassigned |
+| Quick Tile Window to the Bottom Right | Unassigned |
+| Quick Tile Window to the Top Left | Unassigned |
+| Quick Tile Window to the Top Right | Unassigned |
+| Raise Window | Unassigned |
+| Resize Window | Unassigned |
+| Restore Window | Meta+Backspace |
+| Shrink Window Horizontally | Unassigned |
+| Shrink Window Vertically | Unassigned |
+| Window to Desktop 10 | Unassigned |
+| Window to Desktop 11 | Unassigned |
+| Window to Desktop 12 | Unassigned |
+| Window to Desktop 13 | Unassigned |
+| Window to Desktop 14 | Unassigned |
+| Window to Desktop 15 | Unassigned |
+| Window to Desktop 16 | Unassigned |
+| Window to Desktop 17 | Unassigned |
+| Window to Desktop 18 | Unassigned |
+| Window to Desktop 19 | Unassigned |
+| Window to Desktop 20 | Unassigned |
+| Window to Desktop 21 | Unassigned |
+| Window to Desktop 22 | Unassigned |
+| Window to Desktop 23 | Unassigned |
+| Window to Desktop 24 | Unassigned |
+| Window to Desktop 25 | Unassigned |
+| Window to Desktop 4 | Unassigned |
+| Window to Desktop 5 | Unassigned |
+| Window to Desktop 6 | Unassigned |
+| Window to Desktop 7 | Unassigned |
+| Window to Desktop 8 | Unassigned |
+| Window to Desktop 9 | Unassigned |
+| Window to Next Desktop | Unassigned |
+| Window to Previous Desktop | Unassigned |
+| Move Window to Screen 0 | Unassigned |
+| Move Window to Screen 1 | Unassigned |
+| Move Window to Screen 2 | Unassigned |
+| Move Window to Screen 3 | Unassigned |
+| Move Window to Screen 4 | Unassigned |
+| Move Window to Screen 5 | Unassigned |
+| Move Window to Screen 6 | Unassigned |
+| Move Window to Screen 7 | Unassigned |
+| Disable Active Input Capture | Meta+Shift+Esc |
+
+
+
+
+Media Controller (5)
+
+| Action | Stored KDE default |
+|---|---|
+| Media volume down | Unassigned |
+| Media volume up | Unassigned |
+| Play media playback | Unassigned |
+| Media playback seek backward 30s | Unassigned |
+| Media playback seek forward 30s | Unassigned |
+
+
+
+
+Power Management (2)
+
+| Action | Stored KDE default |
+|---|---|
+| Turn Off Screen | Unassigned |
+| Switch Power Profile | Battery
Meta+B |
+
+
+
+
+plasmashell (25)
+
+| Action | Stored KDE default |
+|---|---|
+| Next Wallpaper Image | Unassigned |
+| Activate Task Manager Entry 1 | Meta+1 |
+| Activate Task Manager Entry 10 | Unassigned |
+| Activate Task Manager Entry 2 | Meta+2 |
+| Activate Task Manager Entry 3 | Meta+3 |
+| Activate Task Manager Entry 4 | Meta+4 |
+| Activate Task Manager Entry 5 | Meta+5 |
+| Activate Task Manager Entry 6 | Meta+6 |
+| Activate Task Manager Entry 7 | Meta+7 |
+| Activate Task Manager Entry 8 | Meta+8 |
+| Activate Task Manager Entry 9 | Meta+9 |
+| Clear Notification History | Unassigned |
+| Clear Clipboard History | Unassigned |
+| Automatic Action Popup Menu | Meta+Ctrl+X |
+| Move keyboard focus between panels | Meta+Alt+P |
+| Next History Item | Unassigned |
+| Previous History Item | Unassigned |
+| Edit Contents… | Unassigned |
+| Show Activity Switcher | Meta+Q |
+| Manually Invoke Action on Current Clipboard | Unassigned |
+| Show Desktop | Ctrl+F12 |
+| Show Barcode… | Unassigned |
+| Switch to Next Activity | Unassigned |
+| Switch to Previous Activity | Unassigned |
+| Toggle do not disturb | Unassigned |
+
+
+
+
+services][org.kde.kscreen.desktop (1)
+
+| Action | Stored KDE default |
+|---|---|
+| ShowOSD | — |
+
+
+
+
+services][org.kde.spectacle.desktop (7)
+
+| Action | Stored KDE default |
+|---|---|
+| ActiveWindowScreenShot | — |
+| CurrentMonitorScreenShot | — |
+| FullScreenScreenShot | — |
+| OpenWithoutScreenshot | — |
+| RectangularRegionScreenShot | — |
+| WindowUnderCursorScreenShot | — |
+| _launch | — |
+
+
+
+## Refresh the reference
+
+```sh
+python3 tools/shortcuts.py
+```
+
+Run this after reviewing a shortcut capture or changing the preset.
+The generator reads repo files only and does not change live KDE settings.
diff --git a/tools/shortcuts.py b/tools/shortcuts.py
new file mode 100644
index 0000000..ee481e9
--- /dev/null
+++ b/tools/shortcuts.py
@@ -0,0 +1,151 @@
+#!/usr/bin/env python3
+"""Generate a readable reference from the captured KDE global shortcuts."""
+from collections import defaultdict
+from pathlib import Path
+
+from capture import sections
+
+REPO = Path(__file__).resolve().parents[1]
+SOURCE = REPO / 'configs/kde-shortcuts/kconfig/.config/kglobalshortcutsrc'
+
+
+def bindings(value):
+ return [key.strip() for key in value.replace(r'\t', '\t').split('\t')
+ if key.strip() and key.strip().lower() != 'none']
+
+
+def records(path=SOURCE):
+ for group, values in sections(path.read_text()).items():
+ for action, value in values.items():
+ if action.startswith('_') and action != '_launch':
+ continue
+ fields = value.split(',', 2)
+ current = bindings(fields[0])
+ default = bindings(fields[1]) if len(fields) > 1 else None
+ label = fields[2] if len(fields) > 2 else action
+ yield group, action, label, current, default
+
+
+def cell(value):
+ return value.replace('&', '&').replace('<', '<').replace('>', '>').replace('|', '|').replace('`', '`')
+
+
+def keys(values):
+ if values is None:
+ return '—'
+ return '
'.join('' + cell(value) + '' for value in values) or 'Unassigned'
+
+
+def generate():
+ entries = list(records())
+ active = [r for r in entries if r[3]]
+ inactive = [r for r in entries if not r[3]]
+ by_key = defaultdict(list)
+ for group, action, label, current, default in active:
+ for key in current:
+ by_key[key].append(group + ' / ' + action)
+ duplicates = {key: owners for key, owners in by_key.items() if len(owners) > 1}
+ lines = ['# KDE shortcuts', '',
+ 'Generated from the repo’s captured `kglobalshortcutsrc`. This describes',
+ 'Fiw’s bindings as configured; applying them is a separate installer action.',
+ 'It covers KDE global shortcuts, not every shortcut inside individual applications.', '',
+ f'**{len(active)} assigned actions · {len(inactive)} unassigned actions · {len(entries)} total**', '',
+ '`Meta` is the Super/Windows key. In the full tables, multiple keys for',
+ 'one action are alternatives. Grouped summary keys match the named actions',
+ 'in order. “Unassigned” means explicitly disabled in this capture;',
+ 'a key in the KDE default column is not an active binding. The default',
+ 'column is copied from KDE’s stored values, not inferred from a release.', '',
+ '## Everyday bindings', '',
+ '| Keys | Action |', '|---|---|',
+ 'Screenshot bindings use `fiw-shot`: copy to clipboard, then offer Save',
+ 'or Edit in the notification. They need Spectacle, `wl-copy` and',
+ '`notify-send`; Kitty and KRunner bindings need their respective apps.',
+ 'The native Spectacle bindings are unassigned to avoid competing actions.', '',
+ 'The desktop-move bindings are stored as literal symbols (`!`, `@`, `#`).',
+ 'On a US layout these usually mean Shift+1/2/3; other layouts can differ.',
+ 'The keyboard-layout preset contains US English, Russian and Spanish;',
+ '`Meta+Alt+Space` cycles through them. Shortcut restoration does not',
+ 'create three virtual desktops or activities on a new installation.', '',
+ '## Captured choices', '']
+ lookup = {(r[0], r[1]): r for r in entries}
+ highlights = [
+ ('Open application launcher', '[plasmashell]', ['activate application launcher']),
+ ('Open KRunner', '[services][org.kde.krunner.desktop]', ['_launch']),
+ ('Open Kitty', '[services][net.local.kitty.desktop]', ['_launch']),
+ ('Select a screenshot region', '[services][net.local.fiw-shot-region.desktop]', ['_launch']),
+ ('Screenshot monitor under pointer', '[services][net.local.fiw-shot-screen.desktop]', ['_launch']),
+ ('Show clipboard history at pointer', '[plasmashell]', ['show-on-mouse-pos']),
+ ('Switch to desktop 1 / 2 / 3', '[kwin]', ['Switch to Desktop 1', 'Switch to Desktop 2', 'Switch to Desktop 3']),
+ ('Move window to desktop 1 / 2 / 3', '[kwin]', ['Window to Desktop 1', 'Window to Desktop 2', 'Window to Desktop 3']),
+ ('Switch desktop left / right / up / down', '[kwin]', ['Switch One Desktop to the Left', 'Switch One Desktop to the Right', 'Switch One Desktop Up', 'Switch One Desktop Down']),
+ ('Tile window left / right / up / down', '[kwin]', ['Window Quick Tile Left', 'Window Quick Tile Right', 'Window Quick Tile Top', 'Window Quick Tile Bottom']),
+ ('Move window to previous / next screen', '[kwin]', ['Window to Previous Screen', 'Window to Next Screen']),
+ ('Maximize window', '[kwin]', ['Window Maximize']),
+ ('Toggle Overview', '[kwin]', ['Overview']),
+ ('Toggle desktop grid', '[kwin]', ['Grid View']),
+ ('Next / previous activity', '[plasmashell]', ['next activity', 'previous activity']),
+ ('Lock session', '[ksmserver]', ['Lock Session']),
+ ('Show logout screen', '[ksmserver]', ['Log Out']),
+ ]
+ at = lines.index('Screenshot bindings use `fiw-shot`: copy to clipboard, then offer Save')
+ summary = []
+ for label, group, actions in highlights:
+ current = [key for action in actions for key in lookup.get((group, action), (None, None, None, [], None))[3]]
+ summary.append('| ' + keys(current) + ' | ' + cell(label) + ' |')
+ lines[at:at] = summary + ['']
+ forward = lookup[('[kwin]', 'Walk Through Windows')][3]
+ lines += [('Forward window switching is currently unassigned; reverse switching' if not forward else
+ 'Forward window switching uses ' + keys(forward) + '; reverse switching'),
+ 'uses `Alt+Shift+Tab` and `Meta+Shift+Tab`.', '',
+ 'Other currently unassigned shortcuts include Peek at Desktop (`Meta+D`',
+ 'in the default column), Minimize (`Meta+PgDown`), Restore',
+ '(`Meta+Backspace`) and the window menu (`Alt+F3`). FiwNode’s four',
+ 'recorded global actions are unassigned. `Meta+1/2/3` are used for',
+ 'desktops, with the corresponding task-manager shortcuts disabled.', '']
+ if duplicates:
+ lines += ['Keys assigned to multiple captured actions:', '']
+ for key, owners in duplicates.items():
+ lines.append('- ' + keys([key]) + ': ' + cell('; '.join(owners)))
+ lines.append('')
+ lines += ['## All assigned actions', '']
+ grouped = defaultdict(list)
+ for record in entries:
+ grouped[record[0]].append(record)
+ friendly = sections(SOURCE.read_text())
+ launch_names = {'[services][net.local.fiw-shot-region.desktop]': 'Screenshot region helper',
+ '[services][net.local.fiw-shot-screen.desktop]': 'Screenshot monitor helper',
+ '[services][net.local.kitty.desktop]': 'Kitty launcher',
+ '[services][org.kde.krunner.desktop]': 'KRunner launcher'}
+ for group, rows in grouped.items():
+ assigned = [r for r in rows if r[3]]
+ if not assigned:
+ continue
+ title = launch_names.get(group, friendly[group].get('_k_friendly_name', group.strip('[]')))
+ lines += ['### ' + cell(title), '', '| Action | Current keys | Stored KDE default |', '|---|---|---|']
+ for _, action, label, current, default in assigned:
+ label = launch_names.get(group, label) if action == '_launch' else label
+ lines.append('| ' + cell(label) + ' | ' + keys(current) + ' | ' + keys(default) + ' |')
+ lines.append('')
+ lines += ['## All unassigned actions', '',
+ 'These entries are restored as unassigned, including actions with a',
+ 'stored KDE default. Expand each section to review the full capture.', '']
+ for group, rows in grouped.items():
+ disabled = [r for r in rows if not r[3]]
+ if not disabled:
+ continue
+ title = friendly[group].get('_k_friendly_name', group.strip('[]'))
+ lines += ['', '' + cell(title) + f' ({len(disabled)})
', '',
+ '| Action | Stored KDE default |', '|---|---|']
+ for _, action, label, current, default in disabled:
+ lines.append('| ' + cell(label) + ' | ' + keys(default) + ' |')
+ lines += ['', ' ', '']
+ lines += ['## Refresh the reference', '', '```sh', 'python3 tools/shortcuts.py', '```', '',
+ 'Run this after reviewing a shortcut capture or changing the preset.',
+ 'The generator reads repo files only and does not change live KDE settings.', '']
+ dest = REPO / 'docs/shortcuts.md'
+ dest.write_text('\n'.join(lines))
+ print(f'Wrote docs/shortcuts.md: {len(active)} assigned, {len(inactive)} unassigned, {len(duplicates)} duplicate keys.')
+
+
+if __name__ == '__main__':
+ generate()