Skip to content

Instantly share code, notes, and snippets.

@morkev
Last active July 22, 2026 14:54
Show Gist options
  • Select an option

  • Save morkev/3f08cf45f38610565455bf48190b1b7e to your computer and use it in GitHub Desktop.

Select an option

Save morkev/3f08cf45f38610565455bf48190b1b7e to your computer and use it in GitHub Desktop.
Fix Linux Keychron Error: HID Device Connected [K]
#!/bin/bash
# ==============================================================================
# KEYCHRON LINUX FIX F0R HID DEVICE C0NNECTED [K]
# Author: morkev
#
# Contributors:
# - SIMULATAN: Fixed dongle interference by filtering out "Link" devices.
# - karoltheguy: Added SELinux context reset (restorecon) to prevent silent blocks.
# - wanjas: Verified 'input' group addition is required for distros like Pop_OS.
# - Veliion: Simplifying the script for multiple devices (mice, dongles) at once.
# - pyr0bot: Added an interesting case to support ONEofZERO Keychron boards.
# - sthouement: Added STM32 DFU bootloader udev rule to fix firmware flashing freezes.
#
# INSTRUCTIONS
#
# Step 1: Open your terminal and create the file:
# nano fix-keychron.sh
#
# Step 2: Paste this entire script into the nano editor.
#
# Step 3: Save and Exit nano
# Press Ctrl + O to save.
# Press Enter to confirm.
# Press Ctrl + X to exit.
#
# Step 4: Make executable and run
# chmod +x fix-keychron.sh
# sudo ./fix-keychron.sh
# ==============================================================================
# --- 1. SUDO THIS PUPPY ---
if [ "$EUID" -ne 0 ]; then
echo "Please run this script with sudo: sudo ./fix-keychron.sh"
exit 1
fi
# --- 2. SETUP VARIABLES ---
REAL_USER=${SUDO_USER:-$USER}
USER_GROUP=$(id -gn "$REAL_USER")
RULE_FILE="/etc/udev/rules.d/99-keychron.rules"
# --- 3. FIND KEYCHRON VEND0R ID ---
echo "Looking for Keychron devices..."
# Grab the first Keychron or ONEofZERO device found to extract the Vendor ID.
# Using grep -iE allows us to check for multiple manufacturer names at once.
KEYCHRON_INFO=$(lsusb | grep -iE "Keychron|ONEofZERO" | head -n 1)
if [ -z "$KEYCHRON_INFO" ]; then
echo "No Keychron device detected. Please ensure it is plugged in via USB."
exit 1
fi
echo "Found: $KEYCHRON_INFO"
# Extract the Vendor ID
VENDOR_ID=$(echo "$KEYCHRON_INFO" | awk '{print $6}' | cut -d':' -f1)
echo "Authorizing Vendor ID: $VENDOR_ID"
# --- 4. APPLY UDEV RULES ---
echo "Creating udev rule at $RULE_FILE..."
# Write the rule dynamically based only on Vendor ID.
# This ensures mice, keyboards, and dongles all work with one rule.
cat <<EOF > "$RULE_FILE"
# Keychron Keyboard/Mouse udev rule for VIA / Keychron Launcher
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"
# STM32 DFU bootloader rule (Keychron firmware flashing support)
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"
EOF
# Reset SELinux context (if applicable for your case)
if command -v restorecon &> /dev/null; then
echo "Resetting SELinux context for the udev rule..."
restorecon -v "$RULE_FILE"
fi
echo "Reloading udev rules..."
udevadm control --reload-rules
udevadm trigger
# --- 5. PERMISSIONS ---
echo "Adding $REAL_USER to the 'input' group..."
usermod -aG input "$REAL_USER"
# --- 6. YOU SHOULD BE GOOD ---
echo "Done! All your Keychron devices should now be accessible."
echo "IMPORTANT: Please unplug your device(s) and plug them back in for the changes to take full effect."
@SIMULATAN

SIMULATAN commented Feb 23, 2026

Copy link
Copy Markdown

Thank you! One major problem I encountered is that my system also had some weird Keychron Link device:

~ ❯ lsusb | grep -i Keychron
Bus 003 Device 005: ID 3434:d030 Keychron  Keychron Link 
Bus 007 Device 011: ID 3434:0a11 Keychron Keychron K1 Max

Due to the head -1 call, the udev rule used that link device's product id, which did not fix the Launcher connection error.
To address this bug, I added a grep -vi "Link" into the pipeline before the head -n 1.
After doing that, I successfully got the Launcher to work.

EDIT: the "Keychron Link" device is actually the 2.4 GHz Dongle

@morkev

morkev commented Feb 24, 2026

Copy link
Copy Markdown
Author

Hey, @SIMULATAN! Glad it was a bit helpful, I added your thinking process to the Revision#3 of the script, so it can help future users. Thanks for sharing :)

@karoltheguy

Copy link
Copy Markdown

I can't fully explain why for after trying multiple things and got to your script, it only worked once I did
sudo restorecon -v /etc/udev/rules.d/99-keychron.rules
to reset SELinux so it doesn't silently block it.

@morkev

morkev commented Mar 12, 2026

Copy link
Copy Markdown
Author

Interesting! I will go ahead and add some exception handling for this tomorrow @karoltheguy

@wanjas

wanjas commented Mar 12, 2026

Copy link
Copy Markdown

Thank you! Worked for me on Pop_OS 22.04.

The following part of the script made a difference for me. Just having /etc/udev/rules.d/99-keychron.rules wasn't working in my case.

echo "Adding $REAL_USER to the 'input' group..."
usermod -aG input "$REAL_USER"

@morkev

morkev commented Mar 12, 2026

Copy link
Copy Markdown
Author

Hey @SIMULATAN @karoltheguy @wanjas, thanks so much for the feedback! I've just updated the script based on all your suggestions. I've also added you all to the contributor credits at the top of the script.

@Veliion

Veliion commented Apr 19, 2026

Copy link
Copy Markdown

Thanks for your work. I can confirm that this worked for me on CachyOS.

@Veliion

Veliion commented Apr 19, 2026

Copy link
Copy Markdown

So, I changed

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", ATTRS{idProduct}=="$PRODUCT_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"

to

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"

since I also have a Keychron M6 mouse, which can connect via a dongle (one of the "Ultra-Link" devices). This also allows all my Keychron devices to work with this one udev rule. I am not sure if this is the most secure thing as my knowledge is limited.

Screenshot_20260419_141623

@uxsoft

uxsoft commented May 9, 2026

Copy link
Copy Markdown

Worked!

@releasetheduck

Copy link
Copy Markdown

thank you so much!

@rursache

Copy link
Copy Markdown

thank you, it fixed my K1 version 6 on cachyos

@morkev

morkev commented May 15, 2026

Copy link
Copy Markdown
Author

So, I changed

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", ATTRS{idProduct}=="$PRODUCT_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"

to

KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"

since I also have a Keychron M6 mouse, which can connect via a dongle (one of the "Ultra-Link" devices). This also allows all my Keychron devices to work with this one udev rule. I am not sure if this is the most secure thing as my knowledge is limited.

Screenshot_20260419_141623

@Veliion that is actually a pretty good point, yeah instead of just giving permissions to the keyboard you’re giving permissions to any Keychron device. I will remove that rule for users with more Keychron devices, will make sure to give you credit. Revision #5 reflects this change to the $PRODUCT_ID rule

@morkev

morkev commented May 15, 2026

Copy link
Copy Markdown
Author

Happy to read your comments, guys! Glad the script was useful :) Have a nice Friday everyone

@cellophane11

Copy link
Copy Markdown

Thank you so much for this!

@Minsekt

Minsekt commented Jun 18, 2026

Copy link
Copy Markdown

worke for me on Cachyos using Helium browser. thanks!

@bacaron

bacaron commented Jun 26, 2026

Copy link
Copy Markdown

you are that person! thank you so much for this.

also Indy represent!!!!

@pyr0bot

pyr0bot commented Jun 28, 2026

Copy link
Copy Markdown

Thank you so much for this script!

Going to note this just in case there's anyone else in the same boat: I use a ONEofZERO Si75-HE keyboard (co-developed and manufactured by Keychron) and was having the same issues with ONEofZERO Launcher (which appears to be a modified version of Keychron Launcher), which led me here.

The script in its default state does not work as the board identifies to lsusb as ONEofZERO, but if you change

KEYCHRON_INFO=$(lsusb | grep -i "Keychron" | head -n 1)

to

KEYCHRON_INFO=$(lsusb | grep -i "ONEofZERO" | head -n 1)

it works perfectly (tested with CachyOS and Vivaldi). I hope this is useful for anyone else with this keyboard!

@Razvy01

Razvy01 commented Jul 3, 2026

Copy link
Copy Markdown

Thank you so much for this! It worked on Nobara 43 with Keychron J2 HE.

@sthouement

Copy link
Copy Markdown

Hello,

I have a Linux Ubuntu and had the same issue (not being able to run the keychron launcher and another similar issue : the firmware updates that did not work either:

  1. Unplugged the keyboard
  2. Re-plugged it while pressing the escape key
  3. Match the keyboard as a STM32 device on the keychron launcher firmware updater
  4. The firmware update stayed FROZEN (loading bar stalling at 0%).

Fixed quite the same way with an additional rule. Here is the full udev rule that fixes both issues :

FILE /etc/udev/rules.d/70-keychron.rules

# Keychron keyboards (web launcher / VIA access)
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="3434", MODE="0660", TAG+="uaccess"
EOF

# STM32 DFU bootloader (Keychron firmware flashing)
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="df11", MODE="0660", TAG+="uaccess"

@morkev

morkev commented Jul 16, 2026

Copy link
Copy Markdown
Author

Thanks for your comments, everyone! Really appreciate them.

I updated the code (Revision #6) to handle that special case @pyr0bot mentioned and gave them credits for it- supporting the ONEofZERO boards Keychron manufactures.

@sthouement also found the STM32 DFU bootloader udev rule to fix firmware flashing freezes, at least a behavior that occurs in Ubuntu, and of course also gave them credits for this.

Please let me know if you find anything and will make sure to update this so your efforts help others.

@giubatt

giubatt commented Jul 22, 2026

Copy link
Copy Markdown

Amazing, thank you! This was what made it finally work for me after trying so many things

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment