The Infinity Ergodox is a split, open hardware, open source keyboard. I purchased mine through the Massdrop group buy.

The online configurator is somewhat limited in it's options, but as far as getting the basic layout you want for basic daily driver usage it should be adequate. I have had issues messing with the international options the page presents. Specifically, the compiler seems to fail when building the firmware when they are included in the layout.

Online configuration

The simplest way to get started with programming the keyboards is to use the online configurator and to read the flashing documentation. The first time you flash you should flash both halves. I intend to always flash both halves, however, just to keep things as consistent as possible.

Environment setup

These instructions are designed for Gentoo and may or may not be useful elsewhere. Note that the official guide can be found in the kiibohd controller Github wiki. It is very detailed and should tell you everything you need to know to get things working. The purpose of this document is primarily to explain the particular customization I'm doing and how to accomplish it.

First you will want to clone the kiibohd controller repo. You'll want to grab the Portage config munging script which splits up your portage configs by target architecture. Should you rather do this by hand, the idea is that we want to change all of the package.* files in /etc/portage to be directories. That means you need to do something along the lines of the following for package.{accept_keywords,env,keywords,mask,unmask,use}. It's easier to just use the script, though...

# cd /etc/portage
# mv package.keywords package.keywords.bak
# mkdir package.keywords
# mv package.keywords.bak package.keywords/monolithic

First, we need to emerge crossdev, which lets us maintain multiple toolchains simultaneously via Portage. Then, we instruct crossdev to build the requisite toolchain. Unfortunately, it seems like the g++ gcc frontend is disabled by default. I haven't been able to find a one liner to build the toolchain with it enabled, so sed is used. Feel free to open /etc/portage/package.use/cross-arm-none-eabi and modify 'nocxx -cxx' to '-nocxx cxx' if you're more comfortable with that. Then we rebuild the toolchain with the new USE flags and the g++ frontend appears as arm-none-eabi-g++.

# emerge crossdev
# ./convert-profile-to-files.sh
# crossdev -S -v -t arm-none-eabi
# sed -i 's/nocxx/-nocxx/' etc/portage/package.use/cross-arm-none-eabi
# sed -i 's/-cxx/cxx/' etc/portage/package.use/cross-arm-none-eabi
# emerge -avt cross-arm-none-eabi/gcc # Rebuild with g++ frontend

Now we should be able to build the project:

$ cd controller # The repo we cloned earlier
$ mkdir build
$ cd build
$ cmake ..
$ make

And the output should look something like:

$ make
[  5%] Generating KLL Layout
Scanning dependencies of target kiibohd.elf
[ 10%] Building C object CMakeFiles/kiibohd.elf.dir/main.c.o
[ 15%] Building C object CMakeFiles/kiibohd.elf.dir/Lib/mk20dx.c.o
[ 20%] Building C object CMakeFiles/kiibohd.elf.dir/Lib/delay.c.o
[ 25%] Building C object CMakeFiles/kiibohd.elf.dir/Scan/MatrixARM/matrix_scan.c.o
[ 30%] Building C object CMakeFiles/kiibohd.elf.dir/Scan/MD1/scan_loop.c.o
[ 35%] Building C object CMakeFiles/kiibohd.elf.dir/Macro/PartialMap/macro.c.o
[ 40%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/output_com.c.o
[ 45%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_desc.c.o
[ 50%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_dev.c.o
[ 55%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_joystick.c.o
[ 60%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_keyboard.c.o
[ 65%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_mem.c.o
[ 70%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_mouse.c.o
[ 75%] Building C object CMakeFiles/kiibohd.elf.dir/Output/pjrcUSB/arm/usb_serial.c.o
[ 80%] Building C object CMakeFiles/kiibohd.elf.dir/Debug/cli/cli.c.o
[ 85%] Building C object CMakeFiles/kiibohd.elf.dir/Debug/led/led.c.o
[ 90%] Building C object CMakeFiles/kiibohd.elf.dir/Debug/print/print.c.o
[ 95%] Linking C executable kiibohd.elf
Create and sign dfu bin file:  kiibohd.dfu.bin
No valid DFU suffix signature
Creating Extended Listing:     kiibohd.lss
Creating Symbol Table:         kiibohd.sym
[ 95%] Built target kiibohd.elf
Scanning dependencies of target SizeAfter
[100%] Chip usage for mk20dx128vlf5
	 SRAM: 	44% 	7244/16384	bytes
	Flash: 	21% 	27216/126976	bytes
[100%] Built target SizeAfter
Basic DIY configuration


Languages (incomplete)

There are several options for language input we could use:

  1. SCIM/IBus
  2. Modify the firmware to register as two keyboards with a key to switch the active virtual keyboard, then register different layouts/languages to each virtual keyboard
  3. Attempt to define a custom keyboard layout from scratch with custom scancodes


SCIM or IBus are pretty standard approachs with reasonably good support. Integration with our keyboard isn't really necessary for a good experience. However, we can have a special macro key for switching to a particular language/input mode or even utilize "international" keys for that purpose. For example, my SCIM configuration by default has these triggers "Control+space," "Zenkaku_Hankaku," and "Hangul" so we could potentially add a mapping for "Zenkaku_Hankaku" to enable/disable Japanese input. Personally, this doesn't particularly appeal to me as it's super straightforward and still only works inside X. That likely also means that this is the approach I'll end up using.

Virtual keyboards

The premise here is to modify the firmware to present itself as multiple keyboards over USB and tie the different "virtual keyboards" to different keyboard layers. Then, you use setxkbmap to modify the keymap for one of the "virtual keyboards." AFAICT this option will also only work reasonably well inside X, due to the required use of xinput and setxkbmap. You could have a macro for the virtual console which would load different locales, but that's no longer a "virtual keyboard," as there's no need to have the separate virtual device exposed over USB.

Custom keyboard layout

I believe this is the only option that would actually work in the virtual console, but it's of questionable compatibility with software. tldp.org has an overview of how keyboards work in virtual consoles. My concerns about compatibility come from sections 2 and 12.


Currently this is as far as I have gotten with firmware customization. I've been reading the documentation for the controller as well as documentation about USB keyboards, international keyboards, etc. The next things I plan on doing are:

  1. Port my current firmware configuration over to the custom build approach
  2. Add complex macros (e.g. /buffer ## for changing weechat windows)
  3. Customize the displays on each keyboard
  4. Complete research into supporting multiple languages