A Keyboard called Iris

Introduction

I recently bought a Keebio Iris v7 ergonomic split mechanical keyboard. Above is what it looks like.

The iris keyboard has 56 keys, so about 55% of the number of keys found on a standard 101-key keyboard.  You can order this keyboard online here.  I bought mine in kit form. Thankfully, Keebio has already populated the board with all the necessary components and connectors. Assembling the kit consists of adding key switches and screwing the case together.  The vendor gives easy-to-follow instructions. You only need a screwdriver to assemble the kit.

Hardware

Each of the two halves has a small 8-bit Amtel ATmega32U4 microprocessor, that has 32kb of integrated flash.  The processor is installed on each of the keyboard halves and communicates via an I2C bus, the connection is done with USB-C connectors. The keyboard has a normal USB2 keyboard interface to the host. The keyboard also features USB-C type connectors on both keyboard sides. These ports are necessary to talk to the Host computer, and also allow flashing of the QMK compiled binary. The authors wrote QMK in C, a language I programmed in during the ’90s.  The microprocessor also controls the RGB backlighting installed on the PCB.

While you can buy key switches from the vendor, I wanted ‘clicky’ switches, which I ordered from a different reseller. One can just simply insert the switches onto the PCB. They click in, and no soldering is needed. The keyboard does not come with a USB-C to USB-A male-male cable, so I acquired that separately. I also ordered Keycaps as these don’t come with the kit.

Customizing the QMK Software and keyboard layout

The keyboard comes pre-flashed and defaults to a QWERTY layout. While you can use the pre-flashed software, you can do much more with the customization. The keyboard has a smaller number of keys compared to the full-size keyboard.  This means that it is smaller and that all the keys are within easy reach. It also means that you have to use layers to access functionality for which you don’t have physical keys.  The layout is fully customizable. If you wanted all keys just to generate the letter A, you could.  That means that you need to make several choices regarding keyboard layout.  I found a great blog post by a fellow named Ben Williamson that talks about his journey with the Iris and QMK. Please read it, it’s worth your time. I’m not going to repeat what he has written, but I fully share his motivation and goals.

Alternative keyboard layouts

Most people, including me, know and like the standard qwerty layout.  This layout may not be the best, but due to history, it has stuck. Last year, I experimented with a layout called Colemak DM. DM is a Colemak variant that places the D and M keys in different places.  Learning to type on Colemak was an interesting journey.  It is quite hard to unlearn something like muscle memory, but it is possible. Various websites offer free typing tutor programs, it’s just a matter of practice.  I plan on using the Colemak DM layout with the new keyboard, swim or sink.

Compiling QMK

Because the ATMega has its own RISK instruction set, one needs a cross-compiler to compile the C code which includes key assignments and layer configuration.  I found this site that explains in detail how to set things up on a mac host. It should not be hard to do on a Linux or Windows host either.  Once you install the compiler, you can run the QMK setup, then QMK configures the chosen keyboard model and keyboard map.  Issuing ‘qmk compile’ will then build a binary.  The QMK Toolbox is a GUI program that will let you flash the binary to each keyboard half.  For flashing to work, one must tap the micro-reset switch on the bottom of the keyboard. Then it is a matter of finding the produced binary, and clicking the flash button.  Less than 5 seconds later it’s done, and QMK resets the controller.

Mistakes

Before I forget, I do want to share some of the mistakes I made.  First, I bought keycaps for a normal keyboard, and that was not good.  One needs to buy an ortholinear keycap set, in which all the keys have the same width.  The set will typically include keys specially made for keyboard enthusiasts, having 1u keys for Alt, Tab etc.  I also found keys which did not work at all. This was due to bent pins on the key switches. I fixed this with A new key switch. Finding non-working keys can be hard if the key in question is a modifier key like Alt.  To debug, just re-assign a letter to the key, recompile, and re-flash. I also found that the Apple Command key is the same as the Windows key or the Super key in Linux. KC_LGUI is the key assignment in QMK.

Nitty gritty QMK config

I wanted to share a bit about the parts that I found hard.  I’m kind of assuming you have a working knowledge of C, or can at least read and follow C code.

When you clone the qmk repo, you will find the keyboards/keebio/irisfolder, which contains the vendor-specific layout and customization.

The keyboards/keebio/iris/rev7/rules.mkis shown below.  It controls pre-processor directives that enable or disable certain bits of functionality.

# MCU name
MCU = atmega32u4

# Bootloader selection
BOOTLOADER = atmel-dfu

# Build Options
#   change yes to no to disable
#
BOOTMAGIC_ENABLE = no       # Enable Bootmagic Lite
MOUSEKEY_ENABLE = no        # Mouse keys
EXTRAKEY_ENABLE = yes       # Audio control and System control
CONSOLE_ENABLE = yes        # Console for debug
COMMAND_ENABLE = no         # Commands for debug and configuration
NKRO_ENABLE = no            # Enable N-Key Rollover
BACKLIGHT_ENABLE = no       # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no        # Enable keyboard RGB underglow
AUDIO_ENABLE = no           # Audio output
SPLIT_KEYBOARD = yes
ENCODER_ENABLE = no
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = WS2812
LEADER_ENABLE = no
COMBO_ENABLE = yes
TAP_DANCE_ENABLE = yes
LTO_ENABLE = yes

I disabled the optional rotary encoder with ENCODER_ENABLE = no.  The COMBO_ENABLED allows some key chording (pressing 2 or more keys at once) to allow some action.  TAP_DANCE_ENABLE = yesis set to enable the tap-dance feature.

Next, let’s look at keyboards/keebio/iris/rev7/config.h

/*
Copyright 2022 Danny Nguyen <danny@keeb.io>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

/* Number of Combos */
#define COMBO_COUNT 1
#define COMBO_TERM 200

/* key matrix size */
// Rows are doubled-up
#define MATRIX_ROWS 10
#define MATRIX_COLS 6

// wiring of each half
#define MATRIX_ROW_PINS { B1, F0, F5, B4, D7 }
#define MATRIX_COL_PINS { F1, F4, B5, C7, D4, D6 }
#define MATRIX_ROW_PINS_RIGHT { B1, F0, F5, B4, B5 }
#define MATRIX_COL_PINS_RIGHT { D4, D6, D7, C7, F1, F4 }
#define SPLIT_HAND_PIN D5

#define ENCODERS_PAD_A { B3, F6 }
#define ENCODERS_PAD_B { B2, F7 }
#define ENCODERS_PAD_A_RIGHT { B3, F6 }
#define ENCODERS_PAD_B_RIGHT { B2, F7 }

/* COL2ROW or ROW2COL */
#define DIODE_DIRECTION COL2ROW

/* define if matrix has ghost */
//#define MATRIX_HAS_GHOST

/* number of backlight levels */
// #define BACKLIGHT_LEVELS 3

/* Set 0 if debouncing isn't needed */
#define DEBOUNCE 5


/* serial.c configuration for split keyboard */
#define SOFT_SERIAL_PIN D0

/* ws2812 RGB LED */
#define RGB_DI_PIN E6
#ifdef RGB_DI_PIN
#    define RGBLED_NUM 68
#    define RGBLED_SPLIT { 34, 34 }
#    define RGBLIGHT_HUE_STEP 8
#    define RGBLIGHT_SAT_STEP 8
#    define RGBLIGHT_VAL_STEP 8
#    define RGBLIGHT_LIMIT_VAL 120 /* The maximum brightness level */
#    define RGBLIGHT_SLEEP         /* If defined, the RGB lighting will be switched off when the host goes to sleep */
/*== enabled animations ==*/
#    define RGBLIGHT_EFFECT_BREATHING
#    define RGBLIGHT_EFFECT_RAINBOW_MOOD
#    define RGBLIGHT_EFFECT_RAINBOW_SWIRL
#    define RGBLIGHT_EFFECT_SNAKE
#    define RGBLIGHT_EFFECT_KNIGHT
#    define RGBLIGHT_EFFECT_CHRISTMAS
#    define RGBLIGHT_EFFECT_STATIC_GRADIENT
#    define RGBLIGHT_EFFECT_RGB_TEST
#    define RGBLIGHT_EFFECT_ALTERNATING
#    define RGBLIGHT_EFFECT_TWINKLE
#    define RGBLIGHT_DEFAULT_VAL 120
#    define RGBLIGHT_DEFAULT_MODE (RGBLIGHT_MODE_RAINBOW_SWIRL + 2)
// RGB Matrix
//#    ifdef RGB_MATRIX_ENABLE
#        define ENABLE_RGB_MATRIX_ALPHAS_MODS
#        define ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
#        define ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
#        define ENABLE_RGB_MATRIX_BREATHING
#        define ENABLE_RGB_MATRIX_BAND_SAT
#        define ENABLE_RGB_MATRIX_BAND_VAL
#        define ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
#        define ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
#        define ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
#        define ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
#        define ENABLE_RGB_MATRIX_CYCLE_ALL
#        define ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
#        define ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
#        define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
#        define ENABLE_RGB_MATRIX_CYCLE_OUT_IN
#        define ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
#        define ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
#        define ENABLE_RGB_MATRIX_CYCLE_SPIRAL
#        define ENABLE_RGB_MATRIX_DUAL_BEACON
#        define ENABLE_RGB_MATRIX_RAINBOW_BEACON
#        define ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
// enabled only if RGB_MATRIX_FRAMEBUFFER_EFFECTS is defined
#        define ENABLE_RGB_MATRIX_TYPING_HEATMAP
#        define ENABLE_RGB_MATRIX_DIGITAL_RAIN
// enabled only of RGB_MATRIX_KEYPRESSES or RGB_MATRIX_KEYRELEASES is defined
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
#        define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
#        define ENABLE_RGB_MATRIX_SPLASH
#        define ENABLE_RGB_MATRIX_MULTISPLASH
//#        define ENABLE_RGB_MATRIX_SOLID_SPLASH
//#        define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH
#        define RGB_MATRIX_MAXIMUM_BRIGHTNESS 120
#        define RGB_MATRIX_STARTUP_VAL RGB_MATRIX_MAXIMUM_BRIGHTNESS
#        define DRIVER_LED_TOTAL RGBLED_NUM
#        define RGB_MATRIX_SPLIT { 34, 34 }
#        define RGB_DISABLE_WHEN_USB_SUSPENDED
#        define RGB_MATRIX_KEYPRESSES
//#    endif
#endif

This is mostly vanilla, with just a few #defines for the combo functionality.

Next is the keyboards/keebio/iris/rev7/rev7.c file.  I have not changed this one.

Most of the changes are in the user-specific keyboard customization. Mine is here: keyboards/keebio/iris/keymaps/brunzefb/keymap.c

The rendering in the source code view on this WordPress site is not perfect. Having a too-narrow view causes unwanted line-wrapping, which destroys the ASCII art.  This is what the layout definition looks like on my computer (screenshot from VS Code).  On the top, there is an ASCII art rendition of the keyboard.  Here is the definition for the Colmak DM layer.

Here is the listing of my key map.c

#include QMK_KEYBOARD_H

#define _COLEMAK 0
#define _QUERTY 1
#define _LOWER 2
#define _RAISE 3
#define _ADJUST 4
#define KC_SHLK TD(TD_SHFT_CAPS)
#define KC_LOWR MO(_LOWER)
#define KC_RASE MO(_RAISE)

enum custom_keycodes {
  COLEMAK = SAFE_RANGE,
  QUERTY,
  LOWER,
  RAISE,
  ADJUST,
  FIND_G, // VSCode Replace in files Shift+Cmd+H
  FIND_L, // VSCode Replace in this file Option+Cmd+F
};

enum custom_tapdances {
   TD_SHFT_CAPS = 0,
};

// Shift vs. capslock function. From bbaserdem's Planck keymap (since deprecated).
// Tapping left shift twice in a row enables caps lock. Doing it again disables Caps lock mode.
// Holding shift works just like normal.
void caps_tap (qk_tap_dance_state_t *state, void *user_data) {
    if (state->count == 1) {
        register_code (KC_LSFT);
    } else if (state->count == 2) {
        unregister_code (KC_LSFT);
        register_code (KC_CAPS);
    }
}

void caps_tap_end (qk_tap_dance_state_t *state, void *user_data) {
    if (state->count == 1) {
        unregister_code (KC_LSFT);
    } else {
        unregister_code (KC_CAPS);
    }
}

qk_tap_dance_action_t tap_dance_actions[] = {
    // Tap once for Shift, twice for Caps Lock, this is an on off toggle.
    [TD_SHFT_CAPS] = ACTION_TAP_DANCE_FN_ADVANCED( caps_tap, NULL, caps_tap_end)
};

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Colemak DHm
   // keyboard definitions omitted, but like in the screenshot above.
};

// Enable the ctrl+backspace (KC_BSPC) to function as delete forward (KC_DEL)
uint8_t mod_state;
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    mod_state = get_mods();
    switch (keycode) {
        case KC_BSPC: {
            static bool delkey_registered;
            if (record->event.pressed) { // on key-down of Backspace
                if (mod_state & MOD_MASK_CTRL) {
                    // Ctrl + Backspace -> Forward Delete
                    del_mods(MOD_MASK_CTRL);
                    register_code(KC_DEL);
                    delkey_registered = true;
                    set_mods(mod_state);
                    return false;
                }
            } else { // on release of Backspace
                if (delkey_registered) {
                    unregister_code(KC_DEL);
                    delkey_registered = false;
                    return false;
                }
            }
            return true;
        };
        break;
    }
    return true;
};

On lines 3-10, we have #defines for the layers we will use. Lines 8,9 and 10 #define an alias for a macro. We use TD to define the tapdance feature, the TD_SHFT_CAPS enum is on line 23. I use it for my shift key.  When I tap (quickly press and release), like typing a capital letter, the key functions as a normal shift key.  When I hold it longer, then it toggles the Caps Lock function.  One key with two modes, très cool. I copied the caps_tap() and caps_tap_end() and tap_dance_actions() from some other user’s keyboard definition. These methods are necessary to make this functionality work.

On line 12, we have custom_keycodes defined. This includes my default layers, COLEMAK and QUERTY, and a LOWER and RAISE key. These are modifier keys. Pressing and holding the LOWER or RAISE, switches the layer. Any key you press will come from the LOWER or RAISE layer, as long as it has an override key defined.  If not, you get the base layer key.

FIND_G and FIND_L are ‘virtual’ keys that will let you get a keystroke with a modifier, in my case, I have programmed Shift + Cmd + H for FIND_G, which opens the Replace In Files UI. Below you can see the QUERY definition.

You can find the key assignments here. Note on line 100 the TO(_COLEMAK), which switches from the QUERTY layer to the COLEMAK layer. On line 102, KC_LOWR is a momentary activation (while pressed) of the LOWER layer.  KS_RASE is a momentary activation of the RAISE layer.

Below, is my LOWER layer.

On line 127, we have LALT_T(KC_PENT) – Left Alt when held, KC_PENT (enter) when tapped.

The RAISE layer looks like this:

I have mapped the arrow keys like vim. LSG(KC_H) is Left Shift and GUI when held.  Line 191 shows a method that I use to change the definition of the Backspace key.  Backspace deletes the char to the left, while delete, will nix the character to the right.  I can now press Ctrl + Backspace, and I get the delete, or just Backspace, which gets me a backspace.

With QMK, the user can also define keys that will send a string of keys at a key press.

Final thoughts

I am impressed with both the keyboard and the QMK firmware.  The benefit of having a programmable keyboard is that you can take it with you and just plug it into any machine you need to use.  Your familiar layout will be right there, without having to mess with keyboard settings or extra software on a different computer.  Use Mac and Linux? You can define slightly different layouts if needed. Like to switch between Colemak and Qwerty?  No problem. The keyboard, keycaps and switches are not cheap – but good tools never are.  My keyboard configuration journey is not quite over yet – but in the end, I am confident that the result will have been worth the effort and expense.

2 Comments

Lyle 2022-11-27 Reply

Interesting! Where’s the space bar (oops, I mean “key”) – the one labelled Page Down? I guess I (incorrectly) think the space needs to be big but having it in the right place is what really matters.

Friedrich 2022-11-29 Reply

The space key is to the left of the pg down in the picture. I have programmed it to be a space when tapped, a momentary layer switch key (Raise) when held. The keycaps are not an ortholinear set, so some are mislabeled in the photo. I am getting a better keycap set. Keycaps are useful for learning, but memorization is key.

Leave a Reply