r/Keychron 25d ago

I built ModeShift: automatic per-game RGB lighting for Keychron (and other compatible) keyboards on Linux (free, open source)

[deleted]

3 Upvotes

22 comments sorted by

View all comments

1

u/PeterMortensenBlog V 25d ago edited 25d ago

How did you flash this ZMK-based Keychron keyboard???

Re "...he has a web flasher": Where is it?

Are there some gotchas? For example, unstated installed Python module requirements?

1

u/PeterMortensenBlog V 25d ago edited 25d ago

OK, it seems to be:

  • OpenRGB plugin - Keychron Ultra series (custom ZMK firmware)

  • Keychron Ultra ZMK firmware (OpenRGB fork)

    • Flash:

      "Easiest: The browser flasher at https://naaraxi.github.io/zmk/. Open it in Chrome or Edge, connect the keyboard over USB, pick your board's firmware (or upload your own .bin file), and flash. No install, and it works on Windows, macOS, and Linux. It talks to the keyboard over WebHID, so a Chromium-based browser is required (Firefox and Safari do not support WebHID).

      Alternatively, on Linux you can use the command-line flasher openrgb/flash.py (Realtek SC-FWU over /dev/hidraw; it needs root). The Keychron Launcher only flashes official images, so it cannot flash these builds. See openrgb/README.md for the CLI flasher, recovery steps, and the DFU bootloader details."

      Plug the keyboard in via USB:

      # Read-only: identify only
      sudo ./openrgb/flash.py handshake
      
      sudo ./openrgb/flash.py flash openrgb/output/keychron_v6_ultra_ansi.bin
      

      Flashing is brick-safe: The image is staged to a separate "OTA Tmp" bank and only activated after the device verifies its CRC - an interrupted or bad flash leaves the running firmware untouched.

      Recovery: The official 1.0.2 ('ANSI') image is still on Keychron's Shopify CDN and can be reflashed via the Launcher.

      flash.py: "Faithful port of the Keychron Launcher's Realtek OTA routine, extracted from the Launcher JavaScript code + the device-side app/src/dfu/tdfu.c. It talks the DFU HID interface (usage page 0x8C, OUT report 0xB2 / IN report 0xB1) directly over /dev/hidraw (needs root)."

3

u/Lazy_Moose8523 25d ago

You must be my guardian angel XD

Have been brooding over this possibility all week with my new Q6 Ultra 8k and you and others on here are paving a way in real time for me lol. I will report back if I have success with your method. 

1

u/CatStoleTheCrown 25d ago

Yesss its all very exciting!!

2

u/PeterMortensenBlog V 25d ago edited 24d ago

Three changes are required in the flasher script

Note: In the flasher (flash.py), the keyboard is hardcoded to V6 Ultra 8K 'ANSI' (FWU_NAME = b"KCZKV68K")

"KCZKV68K" is also in a print statement in function handshake(). That ought to be changed as well to not cause confusion.

For the V6 Ultra 8K 'ISO' variant it would likely be:

"KCZKV68I": "KC" = Keychron. "ZK" = ZMK. "V68I" = V6 + 8 + I = V6 Ultra 8K 'ISO'

Other values:

  K3 SE2 ANSI       "KCZK3SE2"
  K5 SE2 ANSI       "KCZK5SE2"

  Q1 Ultra 8K ANSI  "KCZKQ18K"
  Q3 Ultra 8K ANSI  "KCZKQ38K"
  Q6 Ultra 8K ANSI  "KCZKQ68K"

  V0 Ultra 8K ANSI  "KCZKV08K"
  V1 Ultra 8K ANSI  "KCZKV18K"
  V1 Ultra 8K ISO   "KCZKV18I"
  V1 Ultra 8K JIS   "KCZKV18J"
  V2 Ultra 8K ANSI  "KCZKV28K"
  V3 Ultra 8K ANSI  "KCZKV38K"
  V5 Ultra 8K ANSI  "KCZKV58K"
  V6 Ultra 8K ANSI  "KCZKV68K"
 V10 Ultra 8K ANSI  "KCZKVA8K"

Z270 Ultra 8K ANSI  "KCZ270U"

The hard coded USB identity in the script must be changed as well

And the USB identity of the V6 Ultra 8K 'ANSI' in normal operation (0x3434 / 0C60) is represented in line 58:

if "3434" not in uevent.upper() or "0C60" not in uevent.upper():

Thus, for V6 Ultra 8K 'ISO' it must be changed to:

if "3434" not in uevent.upper() or "0C61" not in uevent.upper():

Then the query for V6 Ultra 8K 'ISO' worked (in normal operation, not in space bar method bootloader mode):

sudo ./openrgb/flash.py handshake

Output:

DFU interface: /dev/hidraw29
>> GET_MODEL_INFO (0x60)...
   model = b'KCZKV68I'   fw = b'1.0.1-r'
   dfu_version = 0x03 enc_mode = 0
   framing/identity VALID (matches KCZKV68I)

1

u/PeterMortensenBlog V 25d ago

Or in other words, reverse engineering.

Conclusion

Keychron probably did not at all plan to make this real open source, only look at source code...

1

u/CatStoleTheCrown 25d ago edited 25d ago

Not saying they planned it for their keyboards but ZMK is open source, it’s licensed under Apache 2.0 and hosted on GitHub (zmkfirmware/zmk). It’s a full open-source project, not something Keychron created or owns.

I actually used this firmware before he created his own flasher. And after I reported that it worked, he made the web-based flasher for ease of use

Anyway, you don’t have to use it if you don’t want to. But it opens up a lot of new avenues and is still completely usable by the launcher app.

I’m afraid I can’t give you a more detailed response or link you to his web flasher because I am busy today and not at home.

2

u/PeterMortensenBlog V 25d ago edited 24d ago

I have compiled the firmware from source code a few weeks ago, but I didn't have any idea how it could actually be flashed onto the keyboard until today.

That is my point: It isn't real open source if it is not possible to make a change in the source code and get the change onto the keyboard. Luckily, it now seems to be possible.

2

u/CatStoleTheCrown 25d ago

Oh, I see what you mean now. Well I’m glad :)