Setting up the Keybow Operating System (OS)

In this tutorial, we'll look a little at how the Keybow OS works (you don't really need to worry about this bit too much, but you might find it interesting and useful), then we'll get onto how to set up a micro-SD card with the software. Last, we'll look at simple examples of how to customise the keys and lights on your Keybow or Keybow MINI.

How it all works

The Keybow OS is a custom OS that runs on the Raspberry Pi Zero WH that's included in your Keybow or Keybow MINI kit. It consists of a few different unique parts:

  1. A stripped-down OS based on Raspbian
  2. A ramdisk, into which the entire OS is loaded at boot
  3. Lua files for setting the key mappings, layouts, and lighting
  4. Some C code behind the scenes that sets up and controls the USB HID that Keybow uses to act as a keyboard

The ramdisk means that once the OS is loaded into it during boot, the SD card is no longer accessed or required. This avoids any problems with SD card corruption that can occur when you unplug your Raspberry Pi without safely shutting down first.

Lua is a basic but powerful programming language that works really well on embedded and low-power devices. It has a clean, simple syntax and is ideal for the interface to Keybows layouts and lighting.

Each of the keys on Keybow and Keybow MINI is linked to a single GPIO pin on the Pi Zero W, and the APA102 LEDs to another two pins (the SPI pins). When a key is pressed, the change on that GPIO pin is detected, translated to a HID keycode by the Lua and C code, then sent out through the USB on-the-go port on the Pi Zero W and to the connected computer.

The LEDs under each key are addressable and in a single chain, so they can be individually controlled. We've got two different ways of setting the LEDs: individually in the keys.lua file, or by creating a 24-bit PNG file that will be animated across the keys (more on that later).

Setting up your Keybow OS micro-SD card

Because the Keybow OS is so stripped-down and small, you can get away with using a fairly low capacity micro-SD card; anything bigger than 1GB will be plenty.

Pop your micro-SD card into your computer, and format it in FAT32 format. We recommend using the SD Association's SD Memory Card Formatter app, which is cross-platform and generally very reliable. You can choose "quick format", and call the card whatever you like, e.g. "keybow".

Download the zip file with the Keybow OS on by clicking here. Unzip it, then drag all of the files inside the "sdcard" folder (i.e. not the folder itself) across to the micro-SD card.

Booting your Keybow or Keybow MINI for the first time!

Eject the prepared micro-SD card and pop it into the micro-SD card slot on the Pi Zero WH. Plug the micro-B end of the USB cable into the on-the-go port on the Pi Zero WH; it's the one that lines up with the cut-out in the Keybow baseplate or, if you're using Keybow MINI, it's the one closest to the centre of the Pi Zero W.

Assuming you've prepared your SD card properly, after about 10-15 seconds, you should see the lights on your Keybow or Keybow MINI animating through some blue, pink, and orange hues. You might see a few LEDs light randomly when you first plug the power in; this is normal and will disappear once it's fully booted.

If you don't see the keys lighting up and animating, then something has gone wrong! Try the following troubleshooting tips:

  • Did you definitely format your micro-SD card with a single FAT32 partition?
  • Make sure that the files on the SD card aren't inside a folder
  • Make sure that you copied all of the files across from the unzipped folder
  • Is the micro-SD card plugged in fully, and is the micro-USB cable plugged in fully?
  • Is the Keybow PCB pushed onto the Pi's pins as far as it will go?
  • Is the green activity LED blinking on your Pi Zero WH? If not, then it should be!
  • Try a different micro-SD card, if you have one
  • Remove the baseplate (you won't need to do this on Keybow MINI), and plug a mini HDMI cable in. When you plug the power into the Pi Zero WH, you should see a bunch of text appearing on the screen.

If, after all of those steps, your Keybow or Keybow MINI is still not working, then pop a post on our forums at and we'll do our best to get it working!

How the key mappings work

Note that if you're using Keybow MINI then you'll need to add the following bit of code just after the require "keybow" in your layout file, and substitute handle_key_00 for handle_minikey_00 in each of your key mapping functions.

function setup()

By default, Keybow is set up as a number pad with the numbers 0-9, full stop, and enter, but you can easily customise the twelve keys on Keybow to be whatever key you like. To do this, you'll need to unplug the USB cable from your Keybow and pop the micro-SD card out and into your computer.

For most users, the only files you'll need to worry about are the keys.lua file and the layout files in the layouts folder. The layouts folder contains some example layouts, with the default.lua layout being the default numberpad.

You'll see that there's a line that says require "layouts/default" towards the top of the keys.lua file. This is linking and enabling the default mapping in layouts/default.lua. Let's look at that default.lua file:

require "keybow"

-- Standard number pad mapping --

-- Key mappings --

function handle_key_00(pressed)
    keybow.set_key("0", pressed)

function handle_key_01(pressed)
    keybow.set_key(".", pressed)

function handle_key_02(pressed)
    keybow.set_key(keybow.ENTER, pressed)

function handle_key_03(pressed)
    keybow.set_key("1", pressed)

function handle_key_04(pressed)
    keybow.set_key("2", pressed)

function handle_key_05(pressed)
    keybow.set_key("3", pressed)

function handle_key_06(pressed)
    keybow.set_key("4", pressed)

function handle_key_07(pressed)
    keybow.set_key("5", pressed)

function handle_key_08(pressed)
    keybow.set_key("6", pressed)

function handle_key_09(pressed)
    keybow.set_key("7", pressed)

function handle_key_10(pressed)
    keybow.set_key("8", pressed)

function handle_key_11(pressed)
    keybow.set_key("9", pressed)

You'll see that there are twelve functions, one for each key on Keybow. They're numbered 00, 01, and so on, up to 11. The numberings go from bottom left to top right, and start at the bottom left key when Keybow is in portrait orientation with the USB cable at the right hand side.

Each function has a single line inside saying e.g. keybow.set_key("0", pressed), which means "set this key to send 0 when pressed". You can change this to any number, letter, punctuation mark, or other character on a standard keyboard (we'll get to special keys like space, control, tab, enter, and so on, in a moment).

Changing the pressed at the end of those lines to not pressed, as follows: keybow.set_key("0", not pressed), will cause the 0 to be sent when the key is released rather than pressed. You can have a pressed and not pressed sent by a single key, just by putting two lines within the function, like this, which will send 0 when the key is pressed and 1 when it is released again:

function handle_key_00(pressed)
    keybow.set_key("0", pressed)
    keybow.set_key("1", not pressed)

Take a look at the handle_key_02 function now. You'll see that, rather than having a character like "0" in quote marks, it has keybow.ENTER. There are a number of special keys defined as variables in the keybow.lua file, that you can map to keys on Keybow:






Note that you don't need quote marks around these, as they're variables.

Creating a custom key layout

Our recommended way of creating your own custom layout is to create a new lua file inside the layouts folder, for instance mylayout.lua, and then link that layout in the keys.lua, so your keys.lua file would look like this:

require "keybow"

-- require "layouts/default" -- Numberpad

-- Custom layouts (uncomment to enable) --

-- require "layouts/boilerplate" -- Handy bits of boilerplate text like Lorem Ipsum
-- require "layouts/lightroom" -- Handy hotkeys for Adobe Lightroom Classic CC
-- require "layouts/pico8" -- Controls for Pico-8

require "layouts/mylayout" -- My custom layout

Notice that we've commented out the line that was linking the default layout by adding two hyphens at the beginning of the line, and that we've left off the .lua from the end of the mylayout.lua filename when linking it on the require... line.

It's important that you only have one layout file linked (i.e. uncommented) in your keys.lua file at any one time, or things will get crazy!

To see some examples of custom layouts, you can look at the other layout files in the layouts folder, like lightroom.lua and pico8.lua. There's also a blank layout, blank.lua, that you can use as a template.

Here are some of the ready-made layouts that we've included with Keybow OS:

  • Default numberpad - numbers 0-9, full stop, and enter
  • Boilerplate - example of how to enter whole strings of text like Lorem Ipsum placeholder text, or frequently-used code like the Python shebang
  • Lightroom - hotkeys for Adobe Lightroom Classic CC
  • Pico-8 - a Pico-8 gamepad with directional, action, and various function keys

  • Mini volume control - a three-key volume control (vol. down, mute, vol. up) for Keybow MINI

  • Mini playback control - a tiny controller for your media e.g. Spotify with prev. track, play/pause, next track for Keybow MINI

Customising the lighting on Keybow

There are two ways to customise the lighting on Keybow or Keybow MINI.

Using a PNG image

The first, and easiest, way to customise the lighting is with a 24-bit PNG file. If you create a PNG file that is 12 pixels wide, then the colours of those 12 pixels will be mapped to each of the 12 LEDs under Keybow's keys. If you make the PNG file taller than 1 pixel, then this will create an animation on each LED, cycling through the colours in each column of the image from top to bottom, then looping back to the top. The animations are displayed at 60fps.

If you're using Keybow MINI, then you can create an image that's three pixels wide and it'll span all three keys properly.

If you create an image that is just 1 pixel wide and several pixels tall, then the animation will be duplicated to all of the LEDs on Keybow.

The pattern that is used by default is default.png on the Keybow micro-SD card, so you can change the pattern simply by replacing that file with another called default.png. We've put a bunch of example patterns in the patterns folder.

Note that if you want your animation to loop smoothly, then you'll have to make the pixels at the very bottom of you PNG match up with those at the very top.

Manually setting each LED

The second method of customising the LEDs on your Keybow is by setting them manually is the setup function of your layout file. Here's an example from our Pico-8 controller layout:

function setup() -- Set custom lights up
    keybow.set_pixel(0, 255, 255, 0) -- Green
    keybow.set_pixel(1, 255, 255, 0) -- Green
    keybow.set_pixel(2, 0, 255, 255) -- Cyan
    keybow.set_pixel(3, 255, 0, 255) -- Magenta
    keybow.set_pixel(4, 0, 255, 255) -- Cyan
    keybow.set_pixel(5, 0, 255, 255) -- Cyan
    keybow.set_pixel(6, 255, 0, 255) -- Magenta
    keybow.set_pixel(7, 255, 0, 255) -- Magenta
    keybow.set_pixel(8, 0, 255, 255) -- Cyan
    keybow.set_pixel(9, 255, 0, 255) -- Magenta
    keybow.set_pixel(10, 0, 255, 255) -- Cyan
    keybow.set_pixel(11, 0, 255, 255) -- Cyan

The setup function is run when the keys.lua file is first loaded. The keybow.auto_lights(false) and keybow.clear_lights() lines disable the PNG animation and clear any LEDs that are lit.

The other lines set each of the twelve pixels using keybow.set_pixel(pixel, r, g, b) where pixel is the pixel number and r, g, and b are RGB colour values from 0 to 255. The LED are numbered in the same order as the keys, from bottom left to top right, and start at the bottom left key when Keybow is in portrait orientation.

Rather than setting these pixels in the setup function, you can set them in the handle_key function for the keys themselves, meaning that you can have them come on, or change colour, when the keys are pressed and/or released. Here's an example where key 0 is red normally, but changes to green when pressed:

function setup() -- Set custom lights up

function handle_key_00(pressed)
    if pressed then
        keybow.set_key("0", pressed)
        keybow.set_pixel(0, 0, 255, 0)
        keybow.set_pixel(0, 255, 0, 0)

Advanced customisation

We'll cover advanced customisation of Keybow or Keybow MINI with snippets and macros in a further tutorial: Using macros and snippets with Keybow.

That tutorial covers binding multiple keypresses to a single key to form macros and the use of our ready-made Windows and Mac snippets. This is where Keybow starts to get really powerful!

That's all folks!

Search above to find more great tutorials and guides.

Plasma 2040

Swathe everything in rainbows with this all-in-one, USB-C powered controller for WS2812/Neopixel and APA102/Dotstar addressable LED strip.