Skip to content

Instantly share code, notes, and snippets.

@morkev
Last active March 12, 2026 18:22
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 FOR 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.
#
# 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. CHECK WE ARE RUNNING AS ROOT ---
if [ "$EUID" -ne 0 ]; then
echo "Please run this script with sudo: sudo ./fix-keychron.sh"
exit 1
fi
# --- 2. VARIABLE CONFIGURATION ---
# This will grab the actual user who ran sudo, not the root user
REAL_USER=${SUDO_USER:-$USER}
USER_GROUP=$(id -gn "$REAL_USER")
RULE_FILE="/etc/udev/rules.d/99-keychron.rules"
# --- 3. FIND THE KEYBOARD ---
echo "Looking for Keychron devices..."
# Find the USB device, but ignore the wireless receiver so we grab the actual keyboard.
# (Credit to SIMULATAN for catching the "Link" device bug!)
KEYCHRON_INFO=$(lsusb | grep -i "Keychron" | grep -vi "Link" | head -n 1)
# Make sure we actually found something
if [ -z "$KEYCHRON_INFO" ]; then
echo "No Keychron keyboard detected. Please ensure it is plugged in via USB."
exit 1
fi
echo "Found: $KEYCHRON_INFO"
# --- 4. EXTRACT SPECIFIC VENDOR AND PRODUCT IDs ---
VENDOR_ID=$(echo "$KEYCHRON_INFO" | awk '{print $6}' | cut -d':' -f1)
PRODUCT_ID=$(echo "$KEYCHRON_INFO" | awk '{print $6}' | cut -d':' -f2)
echo "Vendor ID: $VENDOR_ID"
echo "Product ID: $PRODUCT_ID"
# --- 5. APPLY UDEV RULES ---
echo "Creating udev rule at $RULE_FILE..."
# Now we will write the rule dynamically based on the detected IDs
cat <<EOF > "$RULE_FILE"
# Keychron Keyboard udev rule for VIA / Keychron Launcher
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ATTRS{idVendor}=="$VENDOR_ID", ATTRS{idProduct}=="$PRODUCT_ID", MODE="0660", GROUP="$USER_GROUP", TAG+="uaccess", TAG+="udev-acl"
EOF
# Reset SELinux context to prevent silent blocks, but only if SELinux tools exist on this distro
# (Credit to karoltheguy for this fix)
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
# --- 6. PERMISSIONS ---
# Add user to the input group so the system actually lets them talk to the board.
# (Credit to wanjas for confirming this is useful for distros like Pop_OS)
echo "Adding $REAL_USER to the 'input' group..."
usermod -aG input "$REAL_USER"
# --- 7. WRAP UP ---
echo "Done! Your Keychron should be good now."
echo "IMPORTANT: Please unplug your keyboard and plug it back in for the changes to take full effect."
@SIMULATAN
Copy link

SIMULATAN commented Feb 23, 2026

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
Copy link
Author

morkev commented Feb 24, 2026

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

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
Copy link
Author

morkev commented Mar 12, 2026

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

@wanjas
Copy link

wanjas commented Mar 12, 2026

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
Copy link
Author

morkev commented Mar 12, 2026

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.

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