An independent GNOME Shell extension for the Keychron K5 Pro. It adds a panel menu for battery status, standard desktop actions, software display dimming and wired VIA RGB Matrix controls.
This project is unofficial and is not affiliated with or endorsed by Keychron. No Keychron logos, artwork or firmware are included. The product name is used only to identify compatible hardware.
- GNOME Shell 50
- Keychron K5 Pro USB vendor/product ID
3434:0250 - Primary tested variant: K5 Pro ANSI RGB
- A standard GNOME user session on Linux
GNOME Shell 50.3 on Fedora/Bazzite is the tested release. Older GNOME releases are not claimed because they have not been tested against this version.
- Shows Bluetooth connection and battery percentage when BlueZ exposes the
keyboard's
Battery1interface. - Provides a left-to-right software screen-brightness slider, compact
previous/next track buttons below Play / Pause, and a
0–100%volume slider backed by GNOME's mixer API. A native mute switch changes the default sink and verifies the requested state. A persistent Win Key Gaming Lock prevents Super alone from opening GNOME Overview while preserving and restoring the user's previous Mutter overlay-key setting. Compact GNOME-style keycap badges retain the corresponding Keychronfnshortcuts alongside these controls. - Controls VIA RGB Matrix brightness, effect, speed, hue and saturation over
the keyboard's raw-HID interface while connected by USB. A compact effect
row shows the current effect with boundary-aware previous/next buttons.
Brightness uses a live
0–254slider; speed, hue and saturation use0–255sliders. Rapid movement is coalesced and every applied value is verified from the device. Keycap badges retain the stock K5 Profncombinations for toggling and adjusting each corresponding lighting control. - Detects per-key RGB colour zones on demand when its Per-key RGB submenu is opened. Selecting a zone provides a visual colour picker, preset swatches and direct hex entry, then verifies and saves the change. It also shows the zone's physical key names and provides one-level undo without background polling. The same section controls and verifies the effect and brightness shared by all per-key zones.
- Reads the two firmware-defined Mix RGB zones on demand. The Mix RGB submenu shows each zone's physical key membership and every active timeline level's effect, colour, duration and speed without background polling. Selecting an active level opens a verified effect, visual colour picker with direct hex entry, duration and speed editor. Selecting a zone heading changes its active timeline from one to five levels; removed slots are cleared and new slots duplicate the last active level.
- Automatically batches and saves lighting changes to the keyboard after 750 ms of inactivity, avoiding a persistent-memory write for every rapid adjustment.
- Stores ten host-side lighting profiles. New profiles preserve the RGB Matrix
state, the Per-key RGB subtype and all 108 HSV values, plus both Mix RGB zone
assignments and all five timeline records per zone regardless of the active
lighting mode. Applying a profile verifies every applicable write, saves it,
and attempts to restore the complete previous state on failure. Profiles can
be saved, loaded, renamed and cleared through four icon buttons directly on
each panel-menu row. Save captures or overwrites that slot; Load is available
only for populated slots. Existing version 1 and 2 profiles remain compatible
and are identified as
Legacyuntil recaptured. The last successfully loaded profile is remembered across logins and remains green while temporary lighting adjustments are made. Captures are flushed to GNOME Settings, read back byte-for-byte, and rolled back if host-side storage or active-profile persistence fails. - Reads a complete configuration snapshot only when the Keyboard Configuration submenu is opened. It identifies the exact ANSI RGB variant, layer count and layout options, then reads the packed keymap and macro buffers for sizes, counts and checksums. Macro contents are never shown and this path performs no keyboard writes.
- Exports a versioned complete JSON backup through the desktop's native Save dialog, allowing the destination folder and filename to be chosen. The export contains the exact device fingerprint, layout options, packed keymap, macro buffer and complete version 3 lighting snapshot. Export performs fresh reads, validates buffer checksums before saving, and creates the file with user-only permissions. Macro data may contain sensitive typed text, so backup files should be handled as private data.
- Restores a JSON backup selected through the desktop's native Open dialog. Before confirmation it checks the format, payload checksums, exact device and firmware identity, keymap and macro storage dimensions, and both custom-lighting structures against fresh keyboard reads. An incompatible backup stops without writing. After confirmation, the extension captures the complete current state, restores every section in batches, reads everything back, and automatically restores the pre-write snapshot if verification fails. Stored keycodes and macro contents are never displayed.
- Before the first restore write, saves an exact private recovery backup under
the user's XDG state directory and records a pending transaction marker. A
verified restore or verified automatic rollback clears the marker. If GNOME
Shell, the computer or USB power is interrupted, the next extension session
exposes
Recover interrupted restore…so the preserved pre-write state can be validated and restored. The keymap is written last during a normal restore to reduce the window in which damaged mappings could affect the reset chord. - Colours only right-hand operational status text: yellow while reading, exporting, validating or restoring; green after successful reads, saves and restores; and red after failures. Static values and action hints retain the normal menu text colour.
- Uses a native GNOME switch for the keyboard backlight, marks the currently selected RGB effect green, and marks the last successfully loaded or captured lighting profile green. A selected profile is yellow while its apply-and-verify operation is in progress, then green only after success. Temporary lighting changes do not replace or clear the loaded-profile marker.
- Shows on-demand model, connection, USB ID, RGB capability, VIA protocol and optional firmware-version information.
- Consolidates snapshot/backup controls, device information and maintenance
actions into the final top-level
Keyboard Configurationmenu. Device fields follow Snapshot, while Reset the Keyboard sits at the bottom; USB-only actions remain guarded when the keyboard is disconnected. - Keeps the panel menu open after activating its controls, including repeated increment adjustments. The menu still closes normally when its panel icon is toggled or the user clicks elsewhere.
- Sends previous, play/pause and next commands to MPRIS media players.
- Controls the default GNOME audio output through GNOME's mixer API.
- Opens the default file manager without assuming a particular application.
- Provides a software dimmer for the primary display and handles the keyboard's standard screen-brightness keys while enabled.
- Lists firmware-only shortcuts, including F-Key Mode, as disabled reference rows.
The keyboard's Bluetooth profile selection, pairing, sleep configuration and
reset combinations are implemented by its firmware. GNOME cannot synthesize
those private fn combinations, so the extension does not pretend to run them.
Keychron documents factory reset as holding fn + J + Z for four seconds. It is
a useful fallback, but not an absolute recovery guarantee: a partially damaged
keymap could prevent the firmware from resolving that chord. The host-side
recovery snapshot is therefore the extension's primary interrupted-restore
safety path.
The extension has no Python, shell-script, playerctl, wpctl, busctl or
gio command dependency. It uses APIs already present in GNOME Shell 50:
- Gio and BlueZ D-Bus for Bluetooth state and battery data
- MPRIS D-Bus for media controls
- GNOME's Gvc mixer API for volume
- Gio application launching for the file manager
- Gio file streams for VIA raw HID
- XDG Desktop Portal FileChooser for backup Open and Save dialogs
BlueZ is optional: without it, Bluetooth battery status is unavailable but the extension remains usable. An MPRIS-compatible player is required only for the three media menu actions.
RGB controls work only in USB mode. Detection verifies USB ID 3434:0250 plus
the VIA usage descriptor while scanning /sys/class/hidraw. Bluetooth detection
uses BlueZ's matching modalias. Neither path uses a Bluetooth address, USB serial
number or machine-specific device path.
The logged-in user must have read/write permission for the matching /dev/hidraw*
device. Distribution policies differ; if RGB controls stay disabled, inspect:
ls -l /dev/input/by-id/*Keychron*K5*Pro*hidraw /dev/hidraw*Do not make every HID device globally writable. Add a narrowly scoped udev rule
for vendor 3434, product 0250 and the VIA interface according to your
distribution's policy.
Once approved and published, install the extension from extensions.gnome.org.
For a local development install from this checkout:
./install.sh
gnome-extensions enable k5-pro-controls@royza.github.ioUse ./install.sh --symlink while developing. GNOME Shell caches extension
modules; after changing JavaScript for an already-loaded UUID on Wayland, log
out and back in before treating a test as conclusive.
To build the same minimal package intended for extensions.gnome.org:
mkdir -p dist
gnome-extensions pack --force --out-dir=dist \
--extra-source=backup.js --extra-source=controller.js \
--extra-source=device-configuration.js \
--extra-source=file-chooser.js --extra-source=hid.js \
--extra-source=mix-rgb.js --extra-source=per-key-rgb.js \
--extra-source=profile.js --extra-source=recovery-store.js .Run the profile tests and JavaScript checks with:
npm ci
npm test
npm run lintThe tested keyboard emits standard XF86MonBrightnessDown and
XF86MonBrightnessUp keys. The extension temporarily clears GNOME Shell's two
built-in brightness bindings, grabs those keys for its software dimmer, and
restores the exact values it found when disabled. The installer does not modify
the bindings.
The dimmer covers only the primary monitor's window layer, leaving Shell UI visible, and its minimum is deliberately capped at a readable level. Returning the slider to 100%, pressing the brightness-up shortcut, or disabling the extension removes the overlay. This changes perceived brightness, not monitor hardware brightness or power use.
- No panel indicator: check
gnome-extensions info k5-pro-controls@royza.github.ioand the GNOME Shell journal. - RGB rows disabled: connect by USB and check raw-HID permissions.
- No battery percentage: verify the keyboard is connected over Bluetooth
and that BlueZ exposes
org.bluez.Battery1. - Media action reports no player: start an MPRIS-compatible media player.
- Updated code does not load: log out and back in to clear GNOME Shell's module cache.
Development observations and hardware diagnostic tools live in docs/
and tools/. They are not part of the EGO upload ZIP.
The known-good host-controls and recovery baseline is preserved by the annotated
Git tag milestone-host-controls-2026-08-28.
Report bugs at https://github.com/Royza/Keychron-K5-Pro-Gnome-Ext/issues. Useful reports include the GNOME Shell version, connection mode, whether the panel menu works, and relevant non-sensitive journal messages.
The extension is licensed under GPL-3.0-or-later. See LICENSE.