diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..745b3bd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,43 @@ +name: Bug Report +description: Something is wrong or outdated +labels: [bug] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report an issue. Fill in as much detail as you can. + + - type: textarea + id: description + attributes: + label: What happened? + description: A clear description of the issue. + validations: + required: true + + - type: dropdown + id: keyboard + attributes: + label: Keyboard model + options: + - K2 + - K6 + - Other + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected behavior + description: What should the documentation say instead? + validations: + required: true + + - type: textarea + id: context + attributes: + label: Additional context + description: OS, distro, firmware version, or anything else relevant. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml new file mode 100644 index 0000000..c10f5bf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature.yml @@ -0,0 +1,40 @@ +name: Feature Request +description: Suggest an improvement or new section +labels: [enhancement] +body: + - type: markdown + attributes: + value: | + Got an idea? Describe it below. + + - type: textarea + id: description + attributes: + label: What do you want? + description: A clear description of the content you are requesting. + validations: + required: true + + - type: textarea + id: use_case + attributes: + label: Use case + description: What problem does this solve? Who benefits? + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: How might this work? Rough ideas welcome. + validations: + required: false + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Any workarounds you have tried or other approaches you thought about. + validations: + required: false diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000..9ad13e0 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,13 @@ +k2: + - changed-files: + - any-glob-to-any-file: "k2.md" + +k6: + - changed-files: + - any-glob-to-any-file: "k6.md" + +docs: + - changed-files: + - any-glob-to-any-file: + - "*.md" + - "docs/**" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..1a27278 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,22 @@ +## Summary + + + +- +- + +## Keyboard model + + + +- [ ] K2 +- [ ] K6 +- [ ] General + +## Verification + + + +- [ ] Tested on actual hardware +- [ ] Confirmed against official documentation +- [ ] Other (describe below) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..2ed06a7 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,16 @@ +name: Labeler +on: + pull_request_target: + types: [opened, synchronize] + +permissions: + contents: read + pull-requests: write + +jobs: + label: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v5 + with: + configuration-path: .github/labeler.yml diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000..d53d8b4 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,25 @@ +name: Stale +on: + schedule: + - cron: "0 0 * * *" + +permissions: + issues: write + pull-requests: write + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v9 + with: + stale-issue-message: "This issue has been inactive for 60 days. It will be closed in 14 days unless there is new activity." + stale-pr-message: "This PR has been inactive for 30 days. It will be closed in 14 days unless there is new activity." + days-before-issue-stale: 60 + days-before-pr-stale: 30 + days-before-issue-close: 14 + days-before-pr-close: 14 + stale-issue-label: stale + stale-pr-label: stale + exempt-issue-labels: pinned,keep + exempt-pr-labels: pinned,keep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7107666 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# =========================== +# Local +# =========================== +AGENTS.md +CLAUDE.md +PLAN.md +.claude/ +.worktrees/ diff --git a/README.md b/README.md index f5f69e6..a41d8cd 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,47 @@ -# keychron -Settings for Keychron keyboards +# Keychron on Linux -## K2 -[Keychron K2](https://github.com/IulianDita/keychron/blob/master/k2.md) page +Community-maintained guides for using Keychron keyboards on Linux. -## K6 -[Keychron K6](https://github.com/IulianDita/keychron/blob/master/k6.md) page +## Keyboards + +- **[Keychron K2](k2.md)** -- 75% layout, compact with function row +- **[Keychron K6](k6.md)** -- 65% layout, no function row + +## Quick Start + +Most issues boil down to three things: + +1. **Set the physical switch to Windows/Android mode** (back of keyboard) +2. **Function keys should work out of the box on kernel 5.19+** thanks to `fnmode=3` auto-detection +3. **Bluetooth reconnection problems?** See the Bluetooth section in your keyboard's page + +## Original vs Pro (QMK) Models + +Keychron ships two variants of many keyboards. They have very different Linux experiences: + +| | Original | Pro (QMK) | +|---|---|---| +| Kernel driver | `hid-apple` | `hid-generic` | +| Function keys | `fnmode` parameter | Configured via VIA/Launcher | +| Firmware updates | Windows only | Linux via Keychron Launcher | +| Key remapping | `keyd`, `xremap`, XKB | VIA, Keychron Launcher | +| RGB control | Hardware shortcuts only | VIA/Launcher (wired) | + +If you have a Pro model, the `hid_apple` kernel module parameters (`fnmode`, `swap_opt_cmd`, etc.) **do not apply** to you. Use [Keychron Launcher](https://launcher.keychron.com/) or [VIA](https://usevia.app/) instead (Chromium required, wired connection only). + +## Contributing + +Pull requests welcome. If you have a tip, fix, or workaround, open a PR or file an issue. + +## Resources + +- [andrebrait's Keychron Linux guide](https://gist.github.com/andrebrait/961cefe730f4a2c41f57911e6195e444) -- the most comprehensive community resource +- [Arch Wiki: Apple Keyboard](https://wiki.archlinux.org/title/Apple_Keyboard) -- covers `hid_apple` parameters +- [Arch Wiki: Bluetooth keyboard](https://wiki.archlinux.org/title/Bluetooth_keyboard) -- generic BT pairing/troubleshooting +- [keyd](https://github.com/rvaiya/keyd) -- system-wide key remapping daemon (X11, Wayland, TTY) +- [Keychron Launcher](https://launcher.keychron.com/) -- web-based configuration for QMK boards +- [r/Keychron](https://www.reddit.com/r/Keychron/) -- community subreddit + +## License + +[MIT](LICENSE) -- originally by [kurgol](https://github.com/kurgol/keychron). diff --git a/k2.md b/k2.md index 48b183c..d360893 100644 --- a/k2.md +++ b/k2.md @@ -1,129 +1,433 @@ -# Keychron K2 +# Keychron K2 on Linux + +> This guide covers the **original K2** (non-QMK). If you have a **K2 Pro**, most `hid_apple` tips here don't apply -- use [Keychron Launcher](https://launcher.keychron.com/) or [VIA](https://usevia.app/) instead. ## Table of Contents -1. [udev](#udev) -2. [Numlock](#numlock) -3. [Insert](#insert) +1. [First Steps](#first-steps) +2. [Function Keys](#function-keys) +3. [Bluetooth](#bluetooth) 4. [Battery](#battery) 5. [Sleep](#sleep) -6. [Caps Lock and Num Lock](#caps-lock-and-num-lock) -7. [F Keys on Ubuntu](#f-keys-on-ubuntu) -8. [Keymap](#keymap) -9. [Firmware](#firmware) -10. [Fast reconnect bluetooth](#fast-reconnect-bluetooth) -11. [GitLab](#gitlab) +6. [Key Remapping](#key-remapping) +7. [Numlock](#numlock) +8. [Insert Key](#insert-key) +9. [Caps Lock Indicator](#caps-lock-indicator) +10. [Backlight / RGB](#backlight--rgb) +11. [Firmware](#firmware) +12. [Keychron Launcher / VIA (QMK boards)](#keychron-launcher--via-qmk-boards) +13. [Factory Reset](#factory-reset) +14. [Troubleshooting](#troubleshooting) +15. [en-GB Keymap Quirks](#en-gb-keymap-quirks) +16. [Resources](#resources) -## udev -This udev rule is credited to [Emilio Coppa](https://www.facebook.com/ercoppa) from the [Facebook: Keychron User Group](https://www.facebook.com/profile.php?id=534114427066453&ref=br_rs) and was provided as [GitHub Gist: ercoppa/80-keychron.rules](https://gist.github.com/ercoppa/87a42a5d1fd65539844d7badc276d8e7). +--- -1. Create udev rule `sudo touch /etc/udev/rules.d/80-keychron.rules` -2. Add the udev rule `SUBSYSTEMS=="input", ATTRS{name}=="Keychron K2", RUN+="echo 0 | tee /sys/module/hid_apple/parameters/fnmode"` to `/etc/udev/rules.d/80-keychron.rules` -3. `sudo udevadm control --reload-rules && sudo udevadm trigger` +## First Steps -An alternative solution was offered by [Thạch Nguyễn](https://www.facebook.com/Cobblestone8x). +Before anything else: -1. Set fkeyfirst by: - - create the conf file `sudo touch /etc/modprobe.d/hid_apple.conf`. - - add this line to the file: `options hid_apple fnmode=2` and save - - `sudo update-initramfs -u` - - `reboot` -2. Use the keyboard in Windows/Android mode +1. **Set the physical switch on the back of the keyboard to Windows/Android mode.** Mac/iOS mode maps modifier keys incorrectly on Linux. +2. **If you're on kernel 5.19 or newer**, function keys should work out of the box. The `hid_apple` driver auto-detects Keychron keyboards and uses `fnmode=3` (auto), which behaves like `fnmode=2` for Keychron and `fnmode=1` for real Apple keyboards. Check your kernel version with `uname -r`. +--- -## Numlock -If you get stuck in Numlock mode, double tap F6 to disable it. -Alternative way is to open `onboard` and disable "NmLk" in there. +## Function Keys -## Insert -By default there is no `Insert` key natively on the Keychron K2. But [since firmware v1.6](https://www.keychron.com/pages/firmware-v2-3-for-k2-keyboards), `fn`+ DEL will be interpreted as `Insert`. Also it is possible to switch to permanent `Insert` by pressing `fn` + `I` + `D` (for 6 seconds). +The `hid_apple` kernel module controls how function keys behave. Since kernel 5.19, the default `fnmode=3` handles Keychron keyboards correctly. If your function keys aren't working as expected, you can override the behavior. -## Battery -The battery can report it's state via upower. If your distribution supports this you will be able to get a battery indicator on your desktop. +### Check current mode -To check the keyboard is recognized type: +```sh +cat /sys/module/hid_apple/parameters/fnmode ``` -$ upower --dump | grep keyboard -A 7 + +### fnmode values + +| Value | Behavior | +|-------|----------| +| 0 | Fn key disabled entirely | +| 1 | F-keys are secondary (press Fn to get F1-F12) | +| 2 | F-keys are primary (press Fn to get media keys) | +| 3 | Auto -- acts like 2 for Keychron, 1 for Apple (default since kernel 5.19) | + +### Temporary change (lost on reboot) + +```sh +echo 2 | sudo tee /sys/module/hid_apple/parameters/fnmode ``` -You can get some GUI front-end to reflect the battery status, and different distributions often have them enabled by default. Examples include `gnome-power-statistics`, `mate-power-statistics`, Arch with Gnome has battery reporting working out of the box and in Ubuntu `Settings ⇾ Power` it's also working. +### Persistent change -## Sleep -The keyboard goes to Auto Sleep Mode in 10 mins of sitting idle to save battery. +Create or edit `/etc/modprobe.d/hid_apple.conf`: + +``` +options hid_apple fnmode=2 +``` -Press `fn` + `S` + `O` (for 3 seconds) to disable the Auto Sleep Mode. If you want to go back to the Auto Sleep Mode, press `fn` + `S` + `O` (for 3 seconds) again. (Wait for the visual light confirmation.) +Then rebuild your initramfs: -## Caps Lock and Num Lock -The Caps Lock key does not have an dedicated hardware indicator, but [since firmware v1.37](https://www.keychron.com/pages/firmware-v2-3-for-k2-keyboards) you can press `fn` + `Caps Lock`+ `P` for 6 seconds and the Caps Lock key will no longer follow the backlight mode. Instead it will be used to indicate the status of capital/ small letters (with red LED). +```sh +# Debian / Ubuntu +sudo update-initramfs -u -There is also a [Gnome Extension: Lock Keys](https://extensions.gnome.org/extension/36/lock-keys/) that will show a Caps Lock and Num Lock indicator on the panel. +# Arch +sudo mkinitcpio -P -## F Keys on Ubuntu +# Fedora +sudo dracut --force +``` -There is a [discussion on Stackexchange](https://unix.stackexchange.com/questions/121395/on-an-apple-keyboard-under-linux-how-do-i-make-the-function-keys-work-without-t?fbclid=IwAR0cJUOhd6rRn3MG5lGK_3CGE73iy0nCFXqWrjjmtMVCeYjXLQdl7CzOn-E) regarding making the F Keys work. +Reboot for the change to take effect. -[Claus Zotter](https://www.facebook.com/claus.zotter) noticed the `F1` ⇾ `F12` keys always act as though `function` key is pressed. +### Alternative: udev rule -Edit (create if it doesn't exist, it doesn't on 16.04) `/etc/modprobe.d/hid_apple.conf` and add the line `options hid_apple fnmode=2` followed by: +If you prefer a udev rule instead of modprobe.d: +```sh +sudo tee /etc/udev/rules.d/80-keychron.rules <<'EOF' +SUBSYSTEMS=="input", ATTRS{name}=="Keychron K2", RUN+="/bin/sh -c 'echo 2 > /sys/module/hid_apple/parameters/fnmode'" +EOF +sudo udevadm control --reload-rules && sudo udevadm trigger ``` -$ sudo update-initramfs -u && reboot + +> **Note:** The `RUN+=` command needs `/bin/sh -c '...'` wrapping. A bare `echo | tee` won't work in udev because the pipe is a shell construct. + +### All hid_apple parameters + +```sh +ls /sys/module/hid_apple/parameters/ ``` -> fnmode = 0 disable `fn` key -> fnmode = 1 function keys are used as last key -> fnmode = 2 function keys are used as first key +| Parameter | Default | Description | +|-----------|---------|-------------| +| `fnmode` | 3 | Function key behavior (see above) | +| `swap_opt_cmd` | 0 | Swap Alt/Option and Super/Command. 0=default, 1=full swap, 2=left-side only | +| `swap_fn_leftctrl` | 0 | Swap Fn and left Ctrl | +| `swap_ctrl_cmd` | 0 | Swap Ctrl and Cmd (kernel 6.1+) | +| `iso_layout` | -1 | -1=auto, 0=ANSI, 1=ISO | + +Multiple options can be combined in `/etc/modprobe.d/hid_apple.conf`: -Reference: -* [Claus Zotter Gist](https://gist.github.com/mid9commander/669273) -* [Andrii Shkodyn Gist](https://gist.github.com/j2ko/00254950a24498df5902ddc9fceb5ee0) who also noticed he does not get a bind action on Ubuntu 16.04 but that it was working as expected on 18.04. (Seems of no issue with 1.6 in 16.04) +``` +options hid_apple fnmode=2 swap_opt_cmd=1 +``` -## Keymap -If your Keymap appears to be incorrect make sure that `/sys/module/hid_apple/parameters/fnmode` is set to `0` and not `1`. +### NixOS -Method of binding `shift` + `delete` to `insert` suggested by [Konstantinos Liopetas](https://www.facebook.com/konliopetas). +```nix +boot.extraModprobeConfig = '' + options hid_apple fnmode=2 +''; ``` -$ xmodmap -pke | grep Delete -My Output was: -keycode 91 = KP_Delete KP_Decimal KP_Delete KP_Separator -keycode 119 = Delete NoSymbol Delete NoSymbol Delete + +--- + +## Bluetooth + +### Pairing + +```sh +bluetoothctl +power on +agent on +default-agent +scan on +# Put keyboard in pairing mode: Fn + 1/2/3 (hold 4 seconds, light blinks) +pair +trust +connect ``` -So what I did was to add the following line on my `~/.bashrc` (to persist change on reboot) +### Recommended bluetooth config + +Edit `/etc/bluetooth/main.conf` under `[General]`: + +```ini +[General] +FastConnectable = true +ReconnectAttempts = 7 +ReconnectIntervals = 1, 2, 4 +JustWorksRepairing = always +Experimental = true ``` -xmodmap -e "keycode 119 = Delete Insert Delete NoSymbol Delete" + +> **Note:** `JustWorksRepairing` must be under `[General]`, not `[Policy]` -- placing it under `[Policy]` causes a BlueZ error. `Experimental = true` is needed for battery reporting on some setups. + +Restart bluetooth after changes: + +```sh +sudo systemctl restart bluetooth +``` + +### Reconnection after suspend/resume + +This is the most common Bluetooth issue. Two fixes, apply both: + +**1. Disable btusb autosuspend** + +```sh +echo "options btusb enable_autosuspend=n" | sudo tee /etc/modprobe.d/btusb_disable_autosuspend.conf +``` + +Rebuild initramfs (see [Function Keys](#persistent-change) for your distro's command) and reboot. + +**2. Systemd sleep hook** + +Create `/lib/systemd/system-sleep/bt-reconnect`: + +```sh +#!/bin/sh +case $1 in + post) + modprobe -r btusb + sleep 1 + service bluetooth restart + sleep 1 + modprobe btusb + ;; +esac +``` + +```sh +sudo chmod +x /lib/systemd/system-sleep/bt-reconnect +``` + +### CVE-2023-45866: BlueZ security patch breaking keyboards + +A BlueZ security update in 2024 set `ClassicBondedOnly=true` by default, which breaks reconnection for keyboards using "Just Works" pairing (including Keychron). + +**Symptom:** keyboard connects but no input is received. + +**Fix:** edit `/etc/bluetooth/input.conf`: + +```ini +ClassicBondedOnly=false ``` -Reference: [Ask Ubuntu](https://askubuntu.com/questions/158333/how-to-create-a-shortcut-for-forward-delete/158524#158524) -If you use Linux and Wayland (opposed to X11), you can't use X11 utilities such as `xmodmap`. Here's [a guide on how to customize](https://git.sr.ht/~jman/dotfiles/tree/refs/heads/master/xkb/README.md) a Keychron K2 when using the Sway window manager (with links to the original X11 documentation to customize keymappings). +> **Warning:** This reduces Bluetooth security. The proper mitigation is to ensure the keyboard is fully bonded during initial pairing. -### Keymap: en-GB (United Kingdom) -When the keymap is changed to en-GB many characters useful for Linux administration and programming are hard to find. +--- -The following is a list of the characters I have been able to locate on the changed keymap. -The `\ ~` describes the key above enter on the Keychron K2. -The \` ~ describes the key above tab on the Keychron K2. +## Battery +### upower + +```sh +upower --dump | grep keyboard -A 7 ``` -# = "` |" -| = AltGr + "` ~" -\ = AltGr + "\ |" (or alternatively AltGR + "- _") + +Desktop environments with battery indicator support: GNOME (built-in via Settings > Power), KDE Plasma (bluetooth widget), MATE (`mate-power-statistics`). + +### bluetoothctl + +```sh +bluetoothctl info | grep Battery +``` + +### On-keyboard check + +Press `Fn + B`: +- Green = >70% +- Blue = >30% +- Red = <30% + +> **Note:** Battery reporting requires `Experimental = true` in `/etc/bluetooth/main.conf` (see [Bluetooth](#recommended-bluetooth-config)). Some setups also need the `org.bluez.Battery1` D-Bus interface, which is only exposed with experimental features enabled. + +--- + +## Sleep + +The keyboard enters auto-sleep after 10 minutes of inactivity. + +**Toggle auto-sleep:** press `Fn + S + O` (hold 3 seconds). Wait for the backlight to flash as confirmation. + +> The K2 Pro has a different default (2 hours) and allows configuring the timeout via Keychron Launcher. + +--- + +## Key Remapping + +### keyd (recommended -- works on X11, Wayland, and TTY) + +[keyd](https://github.com/rvaiya/keyd) is a system-wide key remapping daemon that works everywhere. Available in Arch (`pacman -S keyd`), Debian 13+, Ubuntu 25.04+, Fedora. + +```sh +sudo systemctl enable --now keyd +``` + +Example `/etc/keyd/default.conf`: + +```ini +[ids] +* + +[main] +capslock = overload(control, esc) ``` +Reload after editing: + +```sh +sudo keyd reload +``` + +### xmodmap (X11 only -- does not work on Wayland) + +For X11 users, `xmodmap` still works. Example: bind `Shift + Delete` to `Insert`: + +```sh +xmodmap -pke | grep Delete +# Find the keycode for Delete (usually 119) +xmodmap -e "keycode 119 = Delete Insert Delete NoSymbol Delete" +``` + +Add to `~/.bashrc` or `~/.xinitrc` to persist across reboots. + +### XKB custom symbols (Wayland-native) + +For GNOME Wayland, put custom symbol files in `~/.config/xkb/symbols/` -- no root access or initramfs rebuild needed. + +--- + +## Numlock + +If stuck in Numlock mode, double-tap `F6` to disable it. Alternatively, open `onboard` (on-screen keyboard) and toggle "NmLk". + +--- + +## Insert Key + +By default there is no dedicated `Insert` key on the K2. + +- **Fn + Delete** sends `Insert` (since firmware v1.6) +- **Fn + I + D** (hold 6 seconds) swaps the default: short press becomes `Insert`, Fn combo becomes `Delete`. Hold again to revert. + +--- + +## Caps Lock Indicator + +The Caps Lock key has no dedicated hardware indicator, but since firmware v1.37: + +**Fn + Caps Lock + P** (hold 6 seconds) -- the Caps Lock LED stops following the backlight mode and instead indicates Caps Lock state with a red LED. + +For a desktop indicator, there's a [GNOME extension: Lock Keys](https://extensions.gnome.org/extension/36/lock-keys/) that shows Caps Lock and Num Lock status in the panel. + +--- + +## Backlight / RGB + +The original K2 has **no software RGB control from Linux**. All lighting is controlled via hardware shortcuts: + +| Shortcut | Action | +|----------|--------| +| Fn + lightbulb key | Cycle lighting effects | +| Fn + left/right arrow | Change color scheme | +| Fn + +/- | Adjust effect speed | +| Fn + L + lightbulb (hold 6s) | Lock current effect | + +[OpenRGB](https://gitlab.com/CalcProgrammer1/OpenRGB) has experimental Keychron support via a [community merge request](https://gitlab.com/CalcProgrammer1/OpenRGB/-/merge_requests/1090), but it's not production-ready for the K2. + +The K2 Pro with QMK can control per-key RGB via VIA or Keychron Launcher (wired mode only). + +--- + ## Firmware -Keychron are investigating [Linux Vendor Firmware Service](https://fwupd.org/) as a possible solution to delivering firmware on Linux, at present it is only possible to update the firmware via Windows. -### Firmware 1.6 -Firmware 1.6 arrived with some new features, they are listed below but taken from the [firmware update page](https://www.keychron.com/pages/firmware-v2-3-for-k2-keyboards). +### Original K2 (non-QMK) + +Firmware updates still require Windows. Keychron has not engaged with [fwupd/LVFS](https://fwupd.org/) despite community requests -- there are zero Keychron devices in the LVFS catalog. + +The [firmware page](https://www.keychron.com/pages/firmware-v2-3-for-k2-keyboards) has the latest version and a changelog. + +### K2 Pro (QMK) + +The K2 Pro can be flashed from Linux using [Keychron Launcher](https://launcher.keychron.com/) or [QMK Toolbox](https://github.com/qmk/qmk_toolbox). See [Keychron Launcher / VIA](#keychron-launcher--via-qmk-boards) below. -1. fn + Caps Lock + P -- Hold these three keys together for 6 seconds, the Caps Lock key will no longer follow the backlight mode, it will be used to indicate the status of capital/ small letters. This feature was included in the last firmware, but with bugs, this time we have fixed the bug for this feature. -2. fn + L + light effect key (the light bulb key) -- Hold these three keys together for 6 seconds, it will lock the light effect you are using now. To unlock the light effect, press these three keys together for 6 seconds again. Please make sure to hold the fn and L key first then hold the light effect key. -3. Under the no backlight circumstances, if you press the light effect key, the backlight will be turned on. (We add this because there are too many users send questions to us saying "my backlight is not working." "my keyboard's backlight has dead '', but the reason for it is they accidentally turned off the backlight and forgot to turn it back. -4. fn + I + D -- By default, short press del to get del, press fn + del to get insert; Hold these three keys together for 6 seconds, the function of the del key will be reversed to insert. Then the short press the key to get insert, press fn key combination will get the del function. Hold these three keys together for 6 seconds again to change back to the default. +--- + +## Keychron Launcher / VIA (QMK boards) + +For QMK-based Keychron keyboards (K2 Pro, Q series, V series), you can remap keys and update firmware from Linux. + +### Setup + +1. Find your device IDs: + +```sh +lsusb | grep -i keychron +``` + +2. Create udev rules at `/etc/udev/rules.d/99-keychron.rules`: + +``` +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3434", MODE="0660", GROUP="users", TAG+="uaccess", TAG+="udev-acl" +``` + +For firmware flashing, also add the bootloader rule: + +``` +SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666", GROUP="users", TAG+="uaccess", TAG+="udev-acl" +``` + +3. Reload udev: + +```sh +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +4. Open [launcher.keychron.com](https://launcher.keychron.com/) or [usevia.app](https://usevia.app/) in **Chromium/Chrome** (Firefox does not support WebHID). + +> **Warning:** The keyboard must be connected via **USB cable**. Flashing firmware over Bluetooth will brick the keyboard. + +--- + +## Factory Reset + +If Bluetooth is completely broken or the keyboard is behaving erratically: + +**Fn + J + Z** (hold 4 seconds) -- backlight flashes to confirm reset. + +After reset, re-enter pairing mode: hold `Fn + 1` (or `2`/`3`) for 4 seconds. + +--- + +## Troubleshooting + +| Problem | Fix | +|---------|-----| +| F-keys act as media keys | Check `fnmode` value (see [Function Keys](#function-keys)). On kernel 5.19+ this should be automatic. | +| Keyboard not responding after suspend | Apply both btusb autosuspend fix and systemd sleep hook (see [Bluetooth](#reconnection-after-suspendresume)) | +| Connects but no input | CVE-2023-45866 fix: set `ClassicBondedOnly=false` in `/etc/bluetooth/input.conf` | +| Wrong modifier keys | Set physical switch to Windows/Android mode | +| `hid-apple` module not loading | Check `lsmod | grep hid_apple`. On QMK boards this is expected -- they use `hid-generic` | +| Keyboard detected as `hid-generic` instead of `hid-apple` | Reported on some kernel 6.7.9+ setups. Ensure Windows/Android mode is set. | +| Battery percentage not showing | Set `Experimental = true` in `/etc/bluetooth/main.conf` and restart bluetooth | + +--- + +## en-GB Keymap Quirks + +When using the en-GB keymap, some characters useful for programming are hard to find. + +The `\ ~` refers to the key above Enter on the K2. The `` ` ~ `` refers to the key above Tab. + +``` +# = "` |" +| = AltGr + "` ~" +\ = AltGr + "\ |" (or AltGr + "- _") +``` -## Fast reconnect bluetooth -For faster reconnect need to set "FastConnectable" to true in /etc/bluetooth/main.conf +--- -## GitLab +## Resources -[Мухаммад Алифф Муаззам](https://www.facebook.com/Tester2009) also maintains a [GitLab repository](https://gitlab.com/keychron/k2) that is dedicated to tracking issues with the K2. +- [andrebrait's Keychron Linux guide](https://gist.github.com/andrebrait/961cefe730f4a2c41f57911e6195e444) -- the definitive community resource +- [svmorris: Silverblue/immutable distro variant](https://gist.github.com/svmorris/b3380b0d0b787d56c42ef8eb1d9d7995) +- [Arch Wiki: Apple Keyboard](https://wiki.archlinux.org/title/Apple_Keyboard) -- covers all hid_apple parameters +- [Arch Wiki: Bluetooth keyboard](https://wiki.archlinux.org/title/Bluetooth_keyboard) +- [keyd: key remapping daemon](https://github.com/rvaiya/keyd) +- [Diolinux/keychron-k2-k4-function-keys-linux](https://github.com/Diolinux/keychron-k2-k4-function-keys-linux) -- boot script for function keys +- [K2 firmware page](https://www.keychron.com/pages/firmware-v2-3-for-k2-keyboards) +- [Keychron Launcher](https://launcher.keychron.com/) +- [K2 GitLab issue tracker](https://gitlab.com/keychron/k2) -- community-maintained diff --git a/k6.md b/k6.md index 0ecb8af..105a70c 100644 --- a/k6.md +++ b/k6.md @@ -1,111 +1,436 @@ -# Keychron K6 +# Keychron K6 on Linux + +> This guide covers the **original K6** (non-QMK). If you have a **K6 Pro**, most `hid_apple` tips here don't apply -- use [Keychron Launcher](https://launcher.keychron.com/) or [VIA](https://usevia.app/) instead. ## Table of Contents - -1. [udev](#udev) -2. [Numlock](#numlock) -3. [Battery](#battery) -4. [Sleep](#sleep) -5. [F Keys on Ubuntu](#f-keys-on-ubuntu) -6. [Swapping Cmd and Alt/AltGr](#swapping-cmd-and-altaltgr) -7. [Keymap](#keymap) -8. [Firmware](#firmware) -9. [Fast reconnect bluetooth](#fast-reconnect-bluetooth) - -## udev -This udev rule is credited to [Emilio Coppa](https://www.facebook.com/ercoppa) from the [Facebook: Keychron User Group](https://www.facebook.com/profile.php?id=534114427066453&ref=br_rs) and was provided as [GitHub Gist: ercoppa/80-keychron.rules](https://gist.github.com/ercoppa/87a42a5d1fd65539844d7badc276d8e7). - -1. Create udev rule `sudo touch /etc/udev/rules.d/80-keychron.rules` -2. Add the udev rule `SUBSYSTEMS=="input", ATTRS{name}=="Keychron K6", RUN+="echo 0 | tee /sys/module/hid_apple/parameters/fnmode"` to `/etc/udev/rules.d/80-keychron.rules` -3. `sudo udevadm control --reload-rules && sudo udevadm trigger` - -An alternative solution was offered by [Thạch Nguyễn](https://www.facebook.com/Cobblestone8x). - -1. Set fkeyfirst by: - - create the conf file `sudo touch /etc/modprobe.d/hid_apple.conf`. - - add this line to the file: `options hid_apple fnmode=1` and save - - `sudo update-initramfs -u` - - `reboot` -2. Use the keyboard in Windows/Android mode +1. [First Steps](#first-steps) +2. [Function Keys](#function-keys) +3. [Bluetooth](#bluetooth) +4. [Battery](#battery) +5. [Sleep](#sleep) +6. [Key Remapping](#key-remapping) +7. [Numlock](#numlock) +8. [Swapping Cmd and Alt](#swapping-cmd-and-alt) +9. [Backlight / RGB](#backlight--rgb) +10. [Firmware](#firmware) +11. [Keychron Launcher / VIA (QMK boards)](#keychron-launcher--via-qmk-boards) +12. [Factory Reset](#factory-reset) +13. [Troubleshooting](#troubleshooting) +14. [en-GB Keymap Quirks](#en-gb-keymap-quirks) +15. [Resources](#resources) -## Numlock -If you get stuck in Numlock mode, double tap fn2 + F6 to disable it. -Alternative way is to open `onboard` and disable "NmLk" in there. +--- + +## First Steps + +Before anything else: + +1. **Set the physical switch on the back of the keyboard to Windows/Android mode.** Mac/iOS mode maps modifier keys incorrectly on Linux. +2. **If you're on kernel 5.19 or newer**, function keys should work out of the box. The `hid_apple` driver auto-detects Keychron keyboards and uses `fnmode=3` (auto), which behaves like `fnmode=2` for Keychron and `fnmode=1` for real Apple keyboards. Check your kernel version with `uname -r`. + +--- + +## Function Keys + +The `hid_apple` kernel module controls how function keys behave. Since kernel 5.19, the default `fnmode=3` handles Keychron keyboards correctly. If your function keys aren't working as expected, you can override the behavior. + +### Check current mode + +```sh +cat /sys/module/hid_apple/parameters/fnmode +``` + +### fnmode values + +| Value | Behavior | +|-------|----------| +| 0 | Fn key disabled entirely | +| 1 | F-keys are secondary (press Fn to get F1-F12) | +| 2 | F-keys are primary (press Fn to get media keys) | +| 3 | Auto -- acts like 2 for Keychron, 1 for Apple (default since kernel 5.19) | + +### Temporary change (lost on reboot) + +```sh +echo 2 | sudo tee /sys/module/hid_apple/parameters/fnmode +``` + +### Persistent change + +Create or edit `/etc/modprobe.d/hid_apple.conf`: + +``` +options hid_apple fnmode=2 +``` + +Then rebuild your initramfs: + +```sh +# Debian / Ubuntu +sudo update-initramfs -u + +# Arch +sudo mkinitcpio -P + +# Fedora +sudo dracut --force +``` + +Reboot for the change to take effect. + +### Alternative: udev rule + +If you prefer a udev rule instead of modprobe.d: + +```sh +sudo tee /etc/udev/rules.d/80-keychron.rules <<'EOF' +SUBSYSTEMS=="input", ATTRS{name}=="Keychron K6", RUN+="/bin/sh -c 'echo 2 > /sys/module/hid_apple/parameters/fnmode'" +EOF +sudo udevadm control --reload-rules && sudo udevadm trigger +``` + +> **Note:** The `RUN+=` command needs `/bin/sh -c '...'` wrapping. A bare `echo | tee` won't work in udev because the pipe is a shell construct. + +### Testing without reboot + +```sh +sudo rmmod hid_apple && sudo modprobe hid_apple +``` + +> **Warning:** If the K6 is your only input device, this will briefly disconnect it. If the second command fails, you'll need a hard reboot. + +### All hid_apple parameters + +```sh +ls /sys/module/hid_apple/parameters/ +``` + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `fnmode` | 3 | Function key behavior (see above) | +| `swap_opt_cmd` | 0 | Swap Alt/Option and Super/Command. 0=default, 1=full swap, 2=left-side only | +| `swap_fn_leftctrl` | 0 | Swap Fn and left Ctrl | +| `swap_ctrl_cmd` | 0 | Swap Ctrl and Cmd (kernel 6.1+) | +| `iso_layout` | -1 | -1=auto, 0=ANSI, 1=ISO | + +Multiple options can be combined in `/etc/modprobe.d/hid_apple.conf`: + +``` +options hid_apple fnmode=2 swap_opt_cmd=1 +``` + +### NixOS + +```nix +boot.extraModprobeConfig = '' + options hid_apple fnmode=2 +''; +``` + +--- + +## Bluetooth + +### Pairing + +```sh +bluetoothctl +power on +agent on +default-agent +scan on +# Put keyboard in pairing mode: Fn + 1/2/3 (hold 4 seconds, light blinks) +pair +trust +connect +``` + +### Recommended bluetooth config + +Edit `/etc/bluetooth/main.conf` under `[General]`: + +```ini +[General] +FastConnectable = true +ReconnectAttempts = 7 +ReconnectIntervals = 1, 2, 4 +JustWorksRepairing = always +Experimental = true +``` + +> **Note:** `JustWorksRepairing` must be under `[General]`, not `[Policy]` -- placing it under `[Policy]` causes a BlueZ error. `Experimental = true` is needed for battery reporting on some setups. + +Restart bluetooth after changes: + +```sh +sudo systemctl restart bluetooth +``` + +### Reconnection after suspend/resume + +This is the most common Bluetooth issue. Two fixes, apply both: + +**1. Disable btusb autosuspend** + +```sh +echo "options btusb enable_autosuspend=n" | sudo tee /etc/modprobe.d/btusb_disable_autosuspend.conf +``` + +Rebuild initramfs (see [Function Keys](#persistent-change) for your distro's command) and reboot. + +**2. Systemd sleep hook** + +Create `/lib/systemd/system-sleep/bt-reconnect`: + +```sh +#!/bin/sh +case $1 in + post) + modprobe -r btusb + sleep 1 + service bluetooth restart + sleep 1 + modprobe btusb + ;; +esac +``` + +```sh +sudo chmod +x /lib/systemd/system-sleep/bt-reconnect +``` + +### CVE-2023-45866: BlueZ security patch breaking keyboards + +A BlueZ security update in 2024 set `ClassicBondedOnly=true` by default, which breaks reconnection for keyboards using "Just Works" pairing (including Keychron). + +**Symptom:** keyboard connects but no input is received. + +**Fix:** edit `/etc/bluetooth/input.conf`: + +```ini +ClassicBondedOnly=false +``` + +> **Warning:** This reduces Bluetooth security. The proper mitigation is to ensure the keyboard is fully bonded during initial pairing. + +--- ## Battery -The battery can report it's state via upower. If your distribution supports this you will be able to get a battery indicator on your desktop. -To check the keyboard is recognized type: +### upower + +```sh +upower --dump | grep keyboard -A 7 ``` -$ upower --dump | grep keyboard -A 7 + +Desktop environments with battery indicator support: GNOME (built-in via Settings > Power), KDE Plasma (bluetooth widget), MATE (`mate-power-statistics`). + +### bluetoothctl + +```sh +bluetoothctl info | grep Battery ``` -You can get some GUI front-end to reflect the battery status, and different distributions often have them enabled by default. Examples include `gnome-power-statistics`, `mate-power-statistics`, Arch with Gnome has battery reporting working out of the box and in Ubuntu `Settings ⇾ Power` it's also working. +### On-keyboard check + +Press `Fn + B`: +- Green = >70% +- Blue = >30% +- Red = <30% + +> **Note:** Battery reporting requires `Experimental = true` in `/etc/bluetooth/main.conf` (see [Bluetooth](#recommended-bluetooth-config)). Some setups also need the `org.bluez.Battery1` D-Bus interface, which is only exposed with experimental features enabled. + +--- ## Sleep -The keyboard goes to Auto Sleep Mode in 10 mins of sitting idle to save battery. -Press `fn1` + `S` + `O` (for 3 seconds) to disable the Auto Sleep Mode. If you want to go back to the Auto Sleep Mode, press `fn` + `S` + `O` (for 3 seconds) again. (Wait for the visual light confirmation.) +The keyboard enters auto-sleep after 10 minutes of inactivity. -## F Keys on Ubuntu +**Toggle auto-sleep:** press `Fn + S + O` (hold 3 seconds). Wait for the backlight to flash as confirmation. -There is a [discussion on Stackexchange](https://unix.stackexchange.com/questions/121395/on-an-apple-keyboard-under-linux-how-do-i-make-the-function-keys-work-without-t?fbclid=IwAR0cJUOhd6rRn3MG5lGK_3CGE73iy0nCFXqWrjjmtMVCeYjXLQdl7CzOn-E) regarding making the F Keys work. +> The K6 Pro has a different default (2 hours), configurable sleep timeout via Keychron Launcher, and a separate 10-minute backlight timeout. -[Claus Zotter](https://www.facebook.com/claus.zotter) noticed the `F1` ⇾ `F12` keys always act as though `function` key is pressed. +--- -Edit (create if it doesn't exist, it doesn't on 16.04) `/etc/modprobe.d/hid_apple.conf` and add the line `options hid_apple fnmode=1` followed by: +## Key Remapping +### keyd (recommended -- works on X11, Wayland, and TTY) + +[keyd](https://github.com/rvaiya/keyd) is a system-wide key remapping daemon that works everywhere. Available in Arch (`pacman -S keyd`), Debian 13+, Ubuntu 25.04+, Fedora. + +```sh +sudo systemctl enable --now keyd +``` + +Example `/etc/keyd/default.conf`: + +```ini +[ids] +* + +[main] +capslock = overload(control, esc) ``` -$ sudo update-initramfs -u && reboot + +Reload after editing: + +```sh +sudo keyd reload ``` -If you want to test without rebooting, run `rmmod hid_apple && modprobe hid_apple`. Warning: If the Keychron K6 keyboard is the only input device, beware that doing so might leave your computer in an inoperable state unless hard reboot when the second command failes. +### xmodmap (X11 only -- does not work on Wayland) -> fnmode = 0 disable `fn` key -> fnmode = 1 function keys are used as last key -> fnmode = 2 function keys are used as first key +For X11 users, `xmodmap` still works. Example: bind `Shift + Delete` to `Insert`: -Reference: -* [Claus Zotter Gist](https://gist.github.com/mid9commander/669273) -* [Andrii Shkodyn Gist](https://gist.github.com/j2ko/00254950a24498df5902ddc9fceb5ee0) who also noticed he does not get a bind action on Ubuntu 16.04 but that it was working as expected on 18.04. (Seems of no issue with 1.6 in 16.04) +```sh +xmodmap -pke | grep Delete +# Find the keycode for Delete (usually 119) +xmodmap -e "keycode 119 = Delete Insert Delete NoSymbol Delete" +``` -## Swapping Cmd and Alt/AltGr +Add to `~/.bashrc` or `~/.xinitrc` to persist across reboots. -To swap the left `Alt` and `Cmd` keys and use the keyboard in PC mode, edit and `/etc/modprobe.d/hid_apple.conf` and add the line `options hid_apple swap_opt_cmd=1`. -This also fixes the right AltGr on non US layouts (ISO layouts) not working. +### XKB custom symbols (Wayland-native) -## Keymap -If your Keymap appears to be incorrect make sure that `/sys/module/hid_apple/parameters/fnmode` is set to `0` and not `1`. +For GNOME Wayland, put custom symbol files in `~/.config/xkb/symbols/` -- no root access or initramfs rebuild needed. + +--- + +## Numlock + +If stuck in Numlock mode, double-tap `Fn2 + F6` to disable it. Alternatively, open `onboard` (on-screen keyboard) and toggle "NmLk". + +--- + +## Swapping Cmd and Alt + +To swap the left `Alt` and `Cmd` keys and use the keyboard in PC mode, add to `/etc/modprobe.d/hid_apple.conf`: -Method of binding `shift` + `delete` to `insert` suggested by [Konstantinos Liopetas](https://www.facebook.com/konliopetas). ``` -$ xmodmap -pke | grep Delete -My Output was: -keycode 91 = KP_Delete KP_Decimal KP_Delete KP_Separator -keycode 119 = Delete NoSymbol Delete NoSymbol Delete +options hid_apple swap_opt_cmd=1 ``` -So what I did was to add the following line on my `~/.bashrc` (to persist change on reboot) +This also fixes the right AltGr not working on non-US ISO layouts. + +Use `swap_opt_cmd=2` to swap only the left-side keys (leaving the right side unchanged). + +Rebuild initramfs and reboot (see [Function Keys](#persistent-change) for your distro's command). + +--- + +## Backlight / RGB + +The original K6 has **no software RGB control from Linux**. All lighting is controlled via hardware shortcuts on the keyboard. + +[OpenRGB](https://gitlab.com/CalcProgrammer1/OpenRGB) has experimental Keychron support via a [community merge request](https://gitlab.com/CalcProgrammer1/OpenRGB/-/merge_requests/1090), but it's not production-ready for the K6. + +The K6 Pro with QMK can control per-key RGB via VIA or Keychron Launcher (wired mode only). + +### SonixQMK (community -- advanced) + +[QMK-on-K6](https://github.com/CanUnesi/QMK-on-K6) is a community project that flashes QMK onto the original K6 RGB (SN32F24x MCU only). This enables software RGB control via VIA. + +> **Warning:** Risk of bricking. **Permanently disables Bluetooth.** The white-backlit K6 is not supported. + +--- + +## Firmware + +### Original K6 (non-QMK) + +Firmware updates still require Windows. Keychron has not engaged with [fwupd/LVFS](https://fwupd.org/) despite community requests -- there are zero Keychron devices in the LVFS catalog. + +The [firmware page](https://www.keychron.com/pages/firmware-for-keychron-k6) has the latest version and a changelog. + +### K6 Pro (QMK) + +The K6 Pro can be flashed from Linux using [Keychron Launcher](https://launcher.keychron.com/) or [QMK Toolbox](https://github.com/qmk/qmk_toolbox). See [Keychron Launcher / VIA](#keychron-launcher--via-qmk-boards) below. + +--- + +## Keychron Launcher / VIA (QMK boards) + +For QMK-based Keychron keyboards (K6 Pro, Q series, V series), you can remap keys and update firmware from Linux. + +### Setup + +1. Find your device IDs: + +```sh +lsusb | grep -i keychron ``` -xmodmap -e "keycode 119 = Delete Insert Delete NoSymbol Delete" + +2. Create udev rules at `/etc/udev/rules.d/99-keychron.rules`: + +``` +KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3434", MODE="0660", GROUP="users", TAG+="uaccess", TAG+="udev-acl" +``` + +For firmware flashing, also add the bootloader rule: + +``` +SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0666", GROUP="users", TAG+="uaccess", TAG+="udev-acl" ``` -Reference: [Ask Ubuntu](https://askubuntu.com/questions/158333/how-to-create-a-shortcut-for-forward-delete/158524#158524) -### Keymap: en-GB (United Kingdom) -When the keymap is changed to en-GB many characters useful for Linux administration and programming are hard to find. +3. Reload udev: -The following is a list of the characters I have been able to locate on the changed keymap. The `\ |` describes the key above enter on the Keychron K6. +```sh +sudo udevadm control --reload-rules && sudo udevadm trigger ``` -# = "\ |" -\ = AltGr + "\ |" + +4. Open [launcher.keychron.com](https://launcher.keychron.com/) or [usevia.app](https://usevia.app/) in **Chromium/Chrome** (Firefox does not support WebHID). + +> **Warning:** The keyboard must be connected via **USB cable**. Flashing firmware over Bluetooth will brick the keyboard. + +--- + +## Factory Reset + +If Bluetooth is completely broken or the keyboard is behaving erratically: + +**Fn + J + Z** (hold 4 seconds) -- backlight flashes to confirm reset. + +After reset, re-enter pairing mode: hold `Fn + 1` (or `2`/`3`) for 4 seconds. + +--- + +## Troubleshooting + +| Problem | Fix | +|---------|-----| +| F-keys act as media keys | Check `fnmode` value (see [Function Keys](#function-keys)). On kernel 5.19+ this should be automatic. | +| Keyboard not responding after suspend | Apply both btusb autosuspend fix and systemd sleep hook (see [Bluetooth](#reconnection-after-suspendresume)) | +| Connects but no input | CVE-2023-45866 fix: set `ClassicBondedOnly=false` in `/etc/bluetooth/input.conf` | +| Wrong modifier keys | Set physical switch to Windows/Android mode, and/or use `swap_opt_cmd` | +| `hid-apple` module not loading | Check `lsmod | grep hid_apple`. On QMK boards this is expected -- they use `hid-generic` | +| Battery percentage not showing | Set `Experimental = true` in `/etc/bluetooth/main.conf` and restart bluetooth | + +--- + +## en-GB Keymap Quirks + +When using the en-GB keymap, some characters useful for programming are hard to find. + +The `\ |` refers to the key above Enter on the K6. + +``` +# = "\ |" +\ = AltGr + "\ |" ~ = Shift + "\ |" ``` -I have not located `|` -## Firmware -Keychron are investigating [Linux Vendor Firmware Service](https://fwupd.org/) as a possible solution to delivering firmware on Linux, at present it is only possible to update the firmware via Windows. +The `|` character has not been reliably located on this layout. + +--- -## Fast reconnect bluetooth -For faster reconnect need to set "FastConnectable" to true in /etc/bluetooth/main.conf +## Resources +- [andrebrait's Keychron Linux guide](https://gist.github.com/andrebrait/961cefe730f4a2c41f57911e6195e444) -- the definitive community resource +- [svmorris: Silverblue/immutable distro variant](https://gist.github.com/svmorris/b3380b0d0b787d56c42ef8eb1d9d7995) +- [Arch Wiki: Apple Keyboard](https://wiki.archlinux.org/title/Apple_Keyboard) -- covers all hid_apple parameters +- [Arch Wiki: Bluetooth keyboard](https://wiki.archlinux.org/title/Bluetooth_keyboard) +- [keyd: key remapping daemon](https://github.com/rvaiya/keyd) +- [QMK-on-K6 (SonixQMK)](https://github.com/CanUnesi/QMK-on-K6) -- community QMK port for original K6 +- [K6 firmware page](https://www.keychron.com/pages/firmware-for-keychron-k6) +- [Keychron Launcher](https://launcher.keychron.com/)