Skip to content

Repository files navigation

Keychron K5 Pro Controls

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.

Compatibility

  • 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.

Features

  • Shows Bluetooth connection and battery percentage when BlueZ exposes the keyboard's Battery1 interface.
  • 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 Keychron fn shortcuts 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–254 slider; speed, hue and saturation use 0–255 sliders. Rapid movement is coalesced and every applied value is verified from the device. Keycap badges retain the stock K5 Pro fn combinations 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 Legacy until 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 Configuration menu. 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.

Runtime requirements

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.

Wired RGB and device permissions

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.

Installation

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.io

Use ./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 lint

Brightness behavior

The 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.

Troubleshooting

  • No panel indicator: check gnome-extensions info k5-pro-controls@royza.github.io and 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.

Development and support

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.

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages