Happy New Year.

Okay here’s a thing. About a year ago I bought a Keyboardio Atreus keyboard.1

I don’t remember what made me think that was a good idea, or how I even found out about it. I did it for my Mental Health? Some people buy a Rolex, others buy a keyboard. Let’s move on.

What’s all this then?

Keyboardio Atreus. Bright keycaps are Massdrop x MiTo XDA Canvas custom keycap set. Black keycaps came on the Atreus.

It’s a tiny little thing.

The Atreus has a learning curve, no question. Space is a key not a bar. Arrow keys, number keys, special characters, function keys, and media controls exist in Layers 1 and 2.2 This means you use Fun E / D / S / F for ↑, ↓, ←, and →. A numpad exists on the right side with its corners defined as Fun M for 1 and Fun O for 9. All special characters are accessed using Fun other keys. To access media controls, function keys, and other lesser used buttons like Page Up and Page Down keys, you need to activate Layer 2 by pressing Fun Esc then releasing them, which locks the keyboard in Layer 2 until you Esc out of it. So if you want to turn up the volume, you press Fun Esc and let go, press X for volume up, then press Esc to go back to the base layer.

It’s a lot, I know. I want to tell you it takes a week or two to get used to it, but the truth is it takes about 3-4 weeks for proficiency in typing prose and maybe double that for proficiency in writing code. That said, I love this thing so much that it activated the principle of “two is one and one is none” and I got myself a second board as a backup.

Programmability

One of the big selling points of the Atreus is that it runs on open source firmware called Kaleidoscope.

Keyboard.io created a GUI interface around Kaleidoscope called Chrysalis which you can use to remap and modify some things on your keyboard without messing around with code, compilations, flashing, etc. The downside of this option is that Chrysalis doesn’t support all of Kaleidoscope’s features (yet–including the one that matters the most to me: Macros).

You might opt for modifying and building Kaleidoscope directly for any of the following reasons: You want to use a feature not exposed in Chrysalis. You want to define a complicated setup in code so you avoid forgetting what you implemented and how you did it, and so you can commit it to a dotfiles repo or something similar. Or maybe you just have a preference for code and live a terminal > GUI lifestyle.

If you’ve ever messed around with an Arduino board, it’s the same idea: you write a script encoding the behavior you want, compile it, then install it to the keyboard. In fact, Arduino software is required if you want to build and install Kaleidoscope yourself.

Quick note on why this matters: some programs will let you create macros or remap your keys. Keyboard Maestro is one example and it can do (probably?) everything Kaleidoscope can. The benefit of programming your keyboard’s firmware is that you can plug that keyboard into anything and have the same behavior come with it. Set it up once, have it everywhere. This is especially useful if you use external keyboard with an iPad like I do, where a utility like Keyboard Maestro cannot exist.

Code

I’ll use the first macro I created in Kaleidoscope as an example.

On a Mac, the common keyboard shortcut to move to the tab to the left or right of the current one is Shift Command [ and Shift Command ] respectively.3 On a normal keyboard this chord is simple enough to type, but on an Atreus, it’s a 4-key contortion: Shift Command Fun Z for previous tab and Shift Command Fun X for next tab.

Here’s how you can modify the Atreus firmware to add a simpler macro – Fun H and Fun ; – that translates to the Mac keyboard shortcuts for switching tabs.

1) Start with the base firmware file.

2) Define the macros in macro_t constant. In this case I named them LEFT_TAB and RIGHT_TAB. This defines which keys are pressed when the macros are triggered.

const macro_t *macroAction(uint8_t macro_id, KeyEvent &event) {
  if (keyToggledOn(event.state)) {
    switch (macro_id) {
    case MACRO_QWERTY:
      Layer.move(QWERTY);
      break;
    case MACRO_VERSION_INFO:
      Macros.type(PSTR("Keyboardio Atreus - Kaleidoscope "));
      Macros.type(PSTR(BUILD_INFORMATION));
      break;
    case LEFT_TAB:
      return MACRO(D(LeftShift), D(LeftGui), D(LeftBracket));
      break;
    case RIGHT_TAB:
      return MACRO(D(LeftShift), D(LeftGui), D(RightBracket));
      break;
    default:
      break;
    }
  }
  return MACRO_NONE;
}

3) Add the macros to the H and ; keys on the second layer (which is triggered by holding the FUN key). Look for M(LEFT_TAB) and M(RIGHT_TAB).

KEYMAPS(
...
  [FUN] = KEYMAP_STACKED
  (
       Key_Exclamation ,Key_At           ,Key_UpArrow   ,Key_Dollar           ,Key_Percent
      ,Key_LeftParen   ,Key_LeftArrow    ,Key_DownArrow ,Key_RightArrow       ,Key_RightParen
      ,Key_LeftBracket ,Key_RightBracket ,Key_Hash      ,Key_LeftCurlyBracket ,Key_RightCurlyBracket ,Key_Caret
      ,TG(UPPER)       ,Key_Insert       ,Key_LeftGui   ,Key_LeftShift        ,Key_Delete         ,Key_LeftControl

                   ,Key_PageUp   ,Key_7 ,Key_8      ,Key_9 ,Key_Backspace
                   ,M(LEFT_TAB)  ,Key_4 ,Key_5      ,Key_6 ,M(RIGHT_TAB)
      ,Key_And     ,Key_Star     ,Key_1 ,Key_2      ,Key_3 ,Key_Plus
      ,Key_LeftAlt ,Key_Space    ,___   ,Key_Period ,Key_0 ,Key_Equals
   ),
...

4) Finally, add the macros to the enum declared towards the beginning of the file.

enum {
  MACRO_QWERTY,
  MACRO_VERSION_INFO,
  LEFT_TAB,
  RIGHT_TAB
};

5) Follow the development guide I linked above to compile and flash this new firmware, and you’ve built your first Atreus macro

See also

  1. I’m glad you asked. Kailh BOX White switches. ↩︎

  2. What you see in the photo is Layer 0, the base layer. Because of course the layers are 0-indexed. ↩︎

  3. I just learned that Control Tab and Shift Control Tab also works. ↩︎