Thinking and Occasionally Typing as a Service

In Media Res

I realized that in my first post about my new keyboard, I didn’t really explain the process to build the firmware for the Teensy 2.0 microcontroller. Since then, I’ve modified my keymap to swap caps lock with control, and now I’ve added back in most of the media key functionality. I’ll show you how to do that now, and explain the compilation process.

Getting the Tools

There are two tools required for compiling and installing the firmware to the Teensy. The first is CrossPack by Objective Development. The tools are installed into /usr/local/CrossPack-AVR/bin/, so you’ll want to add that directory to your $PATH environment variable, either permanently or during compilation. The examples below will use the latter.

To install the resulting firmware code onto the Teensy, you’ll need the Teensy Loader application.

Both these tools predate the signing requirements to get past OS X’s quarantine, so you’ll need to open them via context menu in the Finder.

Getting the Code

You’ll need a copy of hasu’s tmk_keyboard project:

$ git clone git@github.com:tmk/tmk_keyboard.git

Modifying the Keymap

We’ll start with the keymap_ansi.c file and modify it. The ANSI layout makes a very sensible default for the stock keyboard, since it uses the locking caps lock.

keymap_ansi.cdownload
#include "keymap_common.h"


const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    KEYMAP_EXT_ANSI(
    ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12,           PSCR,SLCK,PAUS,                   PWR,
    GRV, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSPC,     INS, HOME,PGUP,    NLCK,PEQL,PSLS,PAST,
    TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSLS,     DEL, END, PGDN,    P7,  P8,  P9,  PMNS,
    LCAP,A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN,QUOT,     ENT,                         P4,  P5,  P6,  PPLS,
    LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,          RSFT,          UP,           P1,  P2,  P3,
    LCTL,LALT,LGUI,          SPC,                               RALT,RCTL,     LEFT,DOWN,RGHT,    P0,       PDOT,PENT
    ),
};

const uint16_t PROGMEM fn_actions[] = {
};
$ cd tmk_keyboard/converter/adb_usb/
$ cp keymap_ansi.c keymap_zbir.c

To create media keys, we’ll need to add another keyboard layer to our keymap. We can duplicate the base layer, and change one key’s code to be FN0. In my case, I’ve chosen the Print Screen key. I’ve designated its action to be ACTION_LAYER_MOMENTARY to switch to layer 1, which has the media keys assigned to F7 through F12.

keymap_zbir_2015-01-08.cdownload
#include "keymap_common.h"


const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
    KEYMAP_EXT_ANSI(
    ESC, F1,  F2,  F3,  F4,  F5,  F6,  F7,  F8,  F9,  F10, F11, F12,           FN0, SLCK,PAUS,                   PWR,
    GRV, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSPC,     INS, HOME,PGUP,    NLCK,PEQL,PSLS,PAST,
    TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSLS,     DEL, END, PGDN,    P7,  P8,  P9,  PMNS,
    CAPS,A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN,QUOT,     ENT,                         P4,  P5,  P6,  PPLS,
    LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,          RSFT,          UP,           P1,  P2,  P3,
    LCTL,LALT,LGUI,          SPC,                               RALT,RCTL,     LEFT,DOWN,RGHT,    P0,       PDOT,PENT
    ),

    KEYMAP_EXT_ANSI(
    ESC, F1,  F2,  F3,  F4,  F5,  F6, MPRV,MPLY,MNXT,MUTE, VOLD,VOLU,          FN0, SLCK,PAUS,                   PWR,
    GRV, 1,   2,   3,   4,   5,   6,   7,   8,   9,   0,   MINS,EQL, BSPC,     INS, HOME,PGUP,    NLCK,PEQL,PSLS,PAST,
    TAB, Q,   W,   E,   R,   T,   Y,   U,   I,   O,   P,   LBRC,RBRC,BSLS,     DEL, END, PGDN,    P7,  P8,  P9,  PMNS,
    CAPS,A,   S,   D,   F,   G,   H,   J,   K,   L,   SCLN,QUOT,     ENT,                         P4,  P5,  P6,  PPLS,
    LSFT,Z,   X,   C,   V,   B,   N,   M,   COMM,DOT, SLSH,          RSFT,          UP,           P1,  P2,  P3,
    LCTL,LALT,LGUI,          SPC,                               RALT,RCTL,     LEFT,DOWN,RGHT,    P0,       PDOT,PENT
    ),
};

const uint16_t PROGMEM fn_actions[] = {
    [0] = ACTION_LAYER_MOMENTARY(1),
};

Compiling the Firmware

By default, with nothing specified, the Makefile will compile keymap_ansi.c. You can specify a KEYMAP parameter to make to choose an alternate. It matches the part of the filename like this: keymap_{KEYMAP}.c. Remember to include the CrossPack AVR location in your $PATH:

$ set PATH /usr/local/CrossPack-AVR/bin $PATH; make KEYMAP=zbir

This will create a number of output files, but we’re interested in adb_usb_lufa.hex, as that’s the file format Teensy Loader will install.

Installing the Firmware

Launch the Teensy app. It’s just one little window. Isn’t it cute? Four little buttons along the top. Press the reset button on the Teensy itself to start the conversation. Click the first button to locate your .hex file. Click the second to erase the Teensy and install the new firmware. Click the third button to reboot the Teensy. Don’t bother with Automatic Mode.

You’re done! If you use a layout like mine, pressing Print Screen and F8 will play/pause iTunes. And since it’s part of the firmware, it works and sends the same commands no matter what computer you plug the keyboard into (or if you use a virtual KV like Teleport, no matter which computer is receiving the keyboard and mouse events).