10 min read

From the Ground Up: How I Built the Developer's Dream Keyboard

View all articles

Working one day in August of 2007, I couldn’t help but realize that my regular PC keyboard didn’t serve me as much as possible. I had to move my hands between the various blocks of my keyboard excessively, hundreds if not thousands of times per day, and my hands were uncomfortably close to each other. There must be a better way, I thought.

This realization was followed by an overwhelming feeling of excitement as I thought about customizing the best keyboard for developers - and later, the realization that, as a freelance embedded software developer, I was hopelessly clueless about hardware.

At the time, I was quite busy with other projects, but not a day passed when I didn’t think about building the hacker keyboard. Soon I started dedicating my free time to working on the project. I managed to learn a whole new skill set, persuade a friend of mine, András Völgyi, mechanical engineer extraordinaire, to join to the project, gather some key people, and devote enough time to creating working prototypes. Nowadays, the Ultimate Hacking Keyboard is a reality. We’re making daily progress, and the launch of our crowdfunding campaign is within reach.

I started by thinking about how to change the keyboard layout, and finished with this!

Going from a software background, knowing nothing about electronics, to designing and building a powerful, marketable hardware device, is an interesting and fascinating experience. In this article, I’ll describe the design of how this electronic masterpiece works. A basic understanding of electronic circuit diagrams may help you follow along.

How do you make a keyboard?

After dedicating thousands of hours of my life to this topic, it’s a hefty challenge for me to give a short answer, but there’s an interesting way to answer to this question. What if we start with something simple, like an Arduino board, and gradually build it up to be the Ultimate Hacking Keyboard? It should not only be more digestible but extremely educational. Therefore, let our keyboard tutorial journey begin!

Step One: A Keyboard Without Keys

First up, let’s make a USB keyboard that emits the x character on a once-per-second basis. The Arduino Micro development board is an ideal candidate for this purpose, because it features the ATmega32U4 microcontroller - an AVR microcrontroller and the same processor that is the brains of the UHK.

The Arduino Micro board was the basis for building my keyboard for developers.

When it comes to USB-capable AVR microcontrollers, the Lightweight USB Framework for AVRs (LUFA) is the library of choice. It enables these processors to become the brains of printers, MIDI devices, keyboards, or almost any other type of USB device.

When plugging a device into the USB port, the device has to transfer some special data structures called USB descriptors. These descriptors tell the host computer the type and properties of the device being connected, and are represented by a tree structure. To make matters even more complex, a device can implement not only one but multiple functions. Let’s see the descriptors structure of the UHK:

  • Device descriptor
    • Configuration descriptor
      • Interface descriptor 0: GenericHID
        • Endpoint descriptor
      • Interface descriptor 1: Keyboard
        • Endpoint descriptor
      • Interface descriptor 2: Mouse
        • Endpoint descriptor

Most standard keyboards only expose a single keyboard interface descriptor, which makes sense. However, as a custom programming keyboard, the UHK also exposes a mouse interface descriptor, because the user can program arbitrary keys of the keyboard to control the mouse pointer so the keyboard can be used as a mouse. The GenericHID interface serves as a communication channel, to exchange configuration information for all the special features of the keyboard. You can see the full implementation of the device and configuration descriptors of the UHK in LUFA here.

Now that we’ve created the descriptors, it’s time to send the x character in every second.

uint8_t isSecondElapsed = 0;
int main(void)
    while (1) {
        isSecondElapsed = 1;
bool CALLBACK_HID_Device_CreateHIDReport(USB_ClassInfo_HID_Device_t* const HIDInterfaceInfo,
                                         uint8_t* const ReportID,
                                         const uint8_t ReportType,
                                         void* ReportData,
                                         uint16_t* const ReportSize)
    USB_KeyboardReport_Data_t* KeyboardReport = (USB_KeyboardReport_Data_t*)ReportData;
    if (isSecondElapsed) {
        KeyboardReport->KeyCode[0] = HID_KEYBOARD_SC_X;
        isSecondElapsed = 0;
    *ReportSize = sizeof(USB_KeyboardReport_Data_t);
    return false;

USB is a polled protocol, which means that the host computer queries the device on a regular interval (usually 125 times per second) to find out whether there’s any new data to send. The relevant callback is the CALLBACK_HID_Device_CreateHIDReport() function, which in this case sends the scancode of the x character to the host whenever the isSecondElapsed variable contains 1. isSecondElapsed gets set to 1 from the main loop on a per second basis, and set to 0 from the callback.

Step Two: A Keyboard of Four Keys

At this point our keyboard is not terribly useful. It’d be nice if we could actually type on it. But for that we need keys, and the keys have to be arranged into a keyboard matrix. A full-sized 104-key keyboard could have 18 rows and 6 columns but we’ll simply have a humble 2x2 keyboard matrix for starting up. This is the schematic:

To customize a hacker keyboard, you have to carefully consider the key matrix.

And this is how it looks on a breadboard:

Configuring the breadboard is a critical step in building a keyboard for developers.

Assuming that ROW1 is connected to PINA0, ROW2 to PINA1, COL1 to PORTB0 and COL2 to PORTB1, here’s what the scanning code looks like:

/* A single pin of the microcontroller to which a row or column is connected. */
typedef struct {
    volatile uint8_t *Direction;
    volatile uint8_t *Name;
    uint8_t Number;
} Pin_t;
/* This part of the key matrix is stored in the Flash to save SRAM space. */
typedef struct {
    const uint8_t ColNum;
    const uint8_t RowNum;
    const Pin_t *ColPorts;
    const Pin_t *RowPins;
} KeyMatrixInfo_t;
/* This Part of the key matrix is stored in the SRAM. */
typedef struct {
    const __flash KeyMatrixInfo_t *Info;
    uint8_t *Matrix;
} KeyMatrix_t;
const __flash KeyMatrixInfo_t KeyMatrix = {
    .ColNum = 2,
    .RowNum = 2,
    .RowPins = (Pin_t[]) {
        { .Direction=&DDRA, .Name=&PINA, .Number=PINA0 },
        { .Direction=&DDRA, .Name=&PINA, .Number=PINA1 }
    .ColPorts = (Pin_t[]) {
        { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB0 },
        { .Direction=&DDRB, .Name=&PORTB, .Number=PORTB1 },
void KeyMatrix_Scan(KeyMatrix_t *KeyMatrix)
    for (uint8_t Col=0; Col<KeyMatrix->Info->ColNum; Col++) {
        const Pin_t *ColPort = KeyMatrix->Info->ColPorts + Col;
        for (uint8_t Row=0; Row<KeyMatrix->Info->RowNum; Row++) {
            const Pin_t *RowPin = KeyMatrix->Info->RowPins + Row;
            uint8_t IsKeyPressed = *RowPin->Name & 1<<RowPin->Number;
            KeyMatrix_SetElement(KeyMatrix, Row, Col, IsKeyPressed);

The code scans one column at a time and within that column it reads the states of the individual key switches. The state of the key switches then gets saved into an array. Within our previous CALLBACK_HID_Device_CreateHIDReport() function the relevant scan codes will then be sent out based on the state of that array.

Step Three: A Keyboard with Two Halves

So far, we’ve created the beginnings of a normal keyboard. But in this keyboard tutorial we’re aiming for advanced ergonomics, and given that people have two hands we better add another keyboard half to the mix.

The other half will feature another keyboard matrix, working the same way as the previous one. The exciting new thing is the communication between the keyboard halves. The three most popular protocols to interconnect electronics devices are SPI, I2C and UART. For practical purposes we will use UART in this case.

To be a good programming keyboard, there has to be stellar communication between both halves.

Bidirectional communication flows through RX rightwards and through TX leftwards according to the above diagram. VCC and GND is necessary to transfer power. UART needs the peers to use the same baud rate, number of data bits and number of stop bits. Once the UART transceiver of both peers gets set up, communication can start to flow.

For now, the left keyboard half sends one-byte messages to the right keyboard half through UART, representing key press or key release events. The right keyboard half processes these messages and manipulates the state of the full keyboard matrix array in memory accordingly. This is how left keyboard half send messages:

USART_SendByte(IsKeyPressed<<7 | Row*COLS_NUM + Col);

The code for the right keyboard half to receive the message looks like this:

void KeyboardRxCallback(void)
    uint8_t Event = USART_ReceiveByte();
    if (!MessageBuffer_IsFull(&KeyStateBuffer)) {
        MessageBuffer_Insert(&KeyStateBuffer, Event);

The KeyboardRxCallback() interrupt handler gets triggered whenever a byte is received through UART. Given that interrupt handlers should execute as quickly as possible, the received message is put into a ring buffer for later processing. The ring buffer eventually gets processed from within the main loop and the keyboard matrix will be updated based on the message.

The above is the simplest way to make this happen, but the final protocol will be somewhat more complex. Multi-byte messages will have to be handled, and the individual messages will have to be checked for integrity by using CRC-CCITT checksums.

At this point, our breadboard prototype is looking pretty impressive:

The breadboard prototype is beginning to take the shape of a customized keyboard for developers.

Step Four: Meet the LED Display

One of our goals with the UHK was to enable the user to define multiple application-specific keyboard maps to further boost productivity. The user needs some way to be aware of the actual keymap being used, so an integrated LED display is built into the keyboard. Here is a prototype display with all LEDs lit:

The LED display is central to building the best keyboard for developers in this tutorial.

The LED display is implemented by a 8x6 LED matrix:

Hacker keyboards wouldn’t be complete without a 8x6 LED matrix.

Every two rows of red-colored LED symbols represents the segments of one of the 14-segment LED displays. The white LED symbols represent the additional three status indicators.

To drive current through an LED and light it up, the corresponding column is set to high voltage, and the corresponding row to low voltage. An interesting consequence of this system is that, at any given moment, only one column can be enabled (all of the LEDs on that column that should be lit have their corresponding rows set to low voltage), while the rest of the columns are disabled. One might think that this system cannot work to use the full set of LEDs, but in reality the columns and rows are updated so quickly that no flickering can be seen by the human eye.

The LED matrix is driven by two integrated circuits (ICs), one driving its rows and the other driving its columns. The source IC that drives the columns is the PCA9634 I2C LED driver:

Two integrated circuits drive the LED matrix on the Ultimate Hacker Keyboard.

The LED matrix sink IC that drives the rows is the TPIC6C595 power shift register:

The IC that drives the rows of LEDs looks like this.

Let’s see the relevant code:

uint8_t LedStates[LED_MATRIX_ROWS_NUM];

void LedMatrix_UpdateNextRow(bool IsKeyboardColEnabled)
    PCA9634_Transmit(1 << ActiveLedMatrixRow);

    if (++ActiveLedMatrixRow == LED_MATRIX_ROWS_NUM) {
          ActiveLedMatrixRow = 0;

LedMatrix_UpdateNextRow() gets called about every millisecond, updating a row of the LED matrix. The LedStates array stores the state of the individual LEDs, is updated via UART based on messages originated from the right keyboard half, pretty much the same way as in the case of the key press/key release event.

The Big Picture

By now we have gradually built up all the necessary components for our custom hacker keyboard, and it’s time to see the big picture. The inside of the keyboard is like a mini computer network: lots of nodes interconnected. The difference is that the distance between the nodes is measured not in metres or kilometres, but in centimetres, and the nodes are not fully-fledged computers, but tiny integrated circuits.

The inside of our tutorial keyboard is made up of interconnected nodes.

A lot has been said so far about the device-side details of the developer’s keyboard, but not so much about UHK Agent, the host-side software. The reason is that, unlike the hardware and the firmware, Agent is very rudimentary at this point. However, the high-level architecture of Agent is decided upon, which I’d like to share.

UHK Agent is the configurator application via which the keyboard can be customized to fit the needs of the user. Despite being a rich client, Agent uses web technologies and runs on top of the node-webkit platform.

Agent communicates with the keyboard using the node-usb library by sending special, device-specific USB control requests and processing their results. It uses Express.js to expose a REST API for consumption by third-party applications. It also uses Angular.js to provide a neat user interface.

var enumerationModes = {
    'keyboard'         : 0,
    'bootloader-right' : 1,
    'bootloader-left'  : 2

function sendReenumerateCommand(enumerationMode, callback)
    sendAgentCommand(AGENT_COMMAND_REENUMERATE, enumerationMode, callback);

function sendAgentCommand(command, arg, callback)
    setReport(new Buffer([command, arg]), callback);

function setReport(message, callback)
        0x21,             // bmRequestType (constant for this control request)
        0x09,             // bmRequest (constant for this control request)
        0,                // wValue (MSB is report type, LSB is report number)
        interfaceNumber,  // wIndex (interface number)
        message,          // message to be sent

Every command has an 8-bit identifier and a set of command-specific arguments. Currently, only the re-enumerate command is implemented. The sendReenumerateCommand() makes the device re-enumerate as the left bootloader or the right bootloader, for upgrading the firmware, or as a keyboard device.

One might have no idea about the advanced features that can be achieved by this software, so I’ll name a few: Agent will be able to visualize the wear of the individual keys and notify the user about their life expectancy, so the user could purchase a couple of new key switches for the impending repair. Agent will also provide a user interface for configuring the various keymaps and layers of the hacker keyboard. The speed and acceleration of the mouse pointer could also be set, along with loads of other uber features. Sky’s the limit.

Creating the Prototype

A lot of work goes into creating customized keyboard prototypes. First of all, the mechanical design has to be finalized which, is pretty complex in itself and involves custom-designed plastic parts, laser-cut stainless steel plates, precision-milled steel guides and neodymium magnets that hold together the two keyboard halves. Everything is designed in CAD before fabrication begins.

The CAD drawing assists in building a keyboard that functions well for developers.

This is how the 3D printed keyboard case looks:

We began by 3D printing the programming keyboard case.

Based on the mechanical design and the schematic, the printed circuit board has to be designed. The right-hand PCB looks like this in KiCad:

Programming a keyboard starts with designing a printed circuit board.

Then the PCB gets fabricated and the surface-mounted components must be soldered by hand:

Soldering the custom keyboard components ensures it works properly once it’s in the case.

Finally, after fabricating all the parts, including 3D printing, polishing and painting the plastic parts and assembling everything, we end up with a working hacker keyboard prototype like this one:


I like to compare developers’ keyboards to the instruments of musicians. Keyboards are fairly intimate objects if you think about it. After all, we use them all day to craft the software of tomorrow, character by character.

Probably because of the above, I consider developing the Ultimate Hacking Keyboard a privilege, and despite all the hardship, more often than not it’s been a very exciting journey and an incredibly intense learning experience.

This is a broad topic, and I could only scratch the surface here. My hope is that this article was a lot of fun and full of interesting material. Should you have any questions, please let me know in the comments.

Lastly, you’re welcome to visit https://ultimatehackingkeyboard.com for more info, and subscribe there to be notified about the launch of our campaign.

About the author

László Monda, Hungary
member since September 1, 2013
László is a full stack developer experienced in a wide range of languages and frameworks. He boasts a system-wide understanding and comfortably moves across the various layers of the stack. [click to continue...]
Hiring? Meet the Top 10 Freelance Embedded Software Engineers for Hire in May 2019


Graham Seymour
Next-level awesome. I can't wait to hop on the Kickstarter for this. Traditional split-keyboards have never felt quite right to me, because of the static positioning of the halves... between that and built-in mouse control, UHK is going to rock!
Gavin Engel
Hmm, I'd prefer CTL key on the corners. Creative keyboard keep it up!
Nikos Kanellopoulos
Very interesting. I want one of these keyboards. One issue though: one day Microsoft decided that the Shift key should be bigger than the Enter key, and suddenly all followed. I find this really silly.
Pedro Werneck
Awesome. Thanks for the isolation diodes.
Alexey Lunacharsky
Nice idea, why don't make it wireless?
László Monda
Good point! The decision of putting the ctrl keys closer to the center of the keyboard was made because ctrl is supposed to be used more frequently than the windows keys so this way ctrl keys are easier to access. In any case, you're able to reconfigure the UHK to fit your needs.
László Monda
I'm wondering whether Shift was always bigger than Enter. Even on the ancient IBM model M keyboard Shift is bigger than Enter. What is the alternative layout that you'd prefer?
Nikos Kanellopoulos
Here is the 1981 IBM PC Keyboard: http://upload.wikimedia.org/wikipedia/commons/8/85/IBM_5150_Keyboard.jpg This is what I remember from around 1985, too.
László Monda
You're right! I meant the first 101 keys model. Pretty good summary at http://en.wikipedia.org/wiki/IBM_PC_keyboard Still wondering whether the long Shift key was affected by Microsoft.
László Monda
Bluetooth is definitely one of our future plans but the USB version is already pretty complex and adding encrypted wireless communication to the mix along with battery management would be too much for the first go.
Gavin Engel
Laszlo, is it possible to make the top of a single key a tiny touchpad for pointer movement? For example the 'J' key.
László Monda
I'm pretty sure that it's possible and I like the idea but I'd expect the R&D costs to be in the hundreds of thousands if not millions of dollars. Fabricating tiny, custom sensors like this is typically fabulously expensive.
Great article, great idea. My suggestion, as you are doing this, and if you want to go to market it, as you are doing the casings by 3D printer anyway, allow people to choose the layout of their keys, make it customizable. Some people want a big Enter (like myself), some want it small, and have the "\" key big. Some like large Shifts, some like small ones. Some like the Ctrl in the corner, some like the Fn key in the corer (and those people need to be shot!) So, think about perhaps making it possible to customize your own layout. Again, awesome job, great article!
László Monda
Thanks for your compliments and suggestions! As for the physical layout we only plan to provide ANSI layout (featuring bar-shaped Enter) which is unlike the ISO layout (that features the larger L-shaped Enter). Providing ISO would be an additional hassle and I'm not sure whether we'll ever do it. Maybe later. As for the key mapping the UHK is fully customizable meaning that you can remap any key as any other key (even modifiers) on the hardware level. You're welcome to take a look at the Ultimate Configurability section of our main page regarding this topic.
Why is the 6 key on the left side? It's very weird to have a "developer" keyboard developed by one who don't touch-type.
Shaun Patterson
Because you hit the 6 with your left index finger...
ux/0057 21BB
http://www.newegg.com/Product/Product.aspx?Item=N82E16823109148 I've used a split keyboard for ~20 years. I fail to see the novelty of your project.
László Monda
It's a more complicated matter than one might think. Right-handed 6 is the American way. Left-handed 6 is the Hungarian way. In any case, left-handed 6 is more ergonomical because you don't have to reach out so far. More info at http://deskthority.net/keyboards-f2/should-the-6-key-be-pressed-with-the-left-or-the-right-hand-t9816.html
Shaun Patterson
Only stupid Americans type the 6 with their right index finger. Where the hell did they learn to type?
This is a great project, but really not "the developers dream keyboard" No dedicated arrows, page up/down, escape or even function keys? Looks like you had fun building it, but it is much more of a pet project than anything more broadly useful.
If you make it backlit, then you will have a truly unique product. I've been patiently waiting forever for a split, backlit, mechanical keyboard. the ergonomic 4000 is already split as is the Goldtouch keyboard as are many many others. But there does not exist a split mechanical *backlit keyboard. us programmers like to dwell in dark places
David Harkness
Great concept so far! I would love to see a version with a vertical key layout like the sadly defunct SmartBoard from DataDesk. Don't let the toy-looking site fool you; this thing rocked and saved my wrists for ten years. http://www.datadesktech.com/desktop_sb.html
That's because you're either blind or just not looking. This split keyboard allows you to choose the angle and amount of split (which no other does - and the angle of the Microsoft one, for example, has always put me off). In addition, this one can handle all keys down, which matters when you start typing fast enough of for gaming. In addition, this one is highly programmable. Comparing this masterpiece to a Microsoft natural keyboard is like comparing your computer to a mechanical typewriter. Yes, both can get you a typefaced document. But I don't see many people ditching their computers for mechanical typewriters.
Sorry, but I'll never consider a keyboard without numpad to be useful. Also, a split keyboard is silly just as limiting either side of a keyboard to one hand is silly. In any real typing, your hands should be shifting naturally as you type and the left or right hand will be in a much better position to hit that next key on the right or left side of the keyboard. Also, no arrow keys. For the 99.9999999% of applications that aren't vi and won't take hjkl as navigation keys, I don't think you've thought this "Ultimate" keyboard through at all.
Of course it is the other way round on OS X. The Command key is used all the time.
Interesting claim that all touch typists only press space with either the left or right thumb. I don't, never have, and if I caught myself doing it I'd be sure to go back to using both.
Are the letters, numbers and so on printed on the keys? A customisable keyboard really should have a small display in each key.
László Monda
It's what I saw when observing others but we plan to make some further research about this. Just take a look at the space bars of your colleagues. I'm fairly confident that one side of those space bars will be a lot more shinier than the other, meaning that the the user in question is a left-handed / right-handed space user.
László Monda
I'm not sure whether we will ever integrate backlighting. The UHK is primarily meant for touch typists and as such it'd increase the price without improving usability. I understand that it'd look fancy, though.
László Monda
Yes, the symbols are printed on the keys. What you are suggesting is doable but incredibly expensive. Take a look at the Optimus Maximus keyboard. It'll set you back with $1,600.
László Monda
I'm quite interested in columnar keyboard layouts and plan to try a couple of columnar keyboards, just don't expect a columnar version of UHK any time soon. :)
László Monda
There are a couple 60% keyboards on the market lacking the dedicated keys that you mentioned above, some of them being rather prestigious. It's a design tradeoff that probably doesn't appeal for the masses but for a select few.
I know that to be true. They are not "the developers dream keyboard" either.
I think its a mistake to assume touch typing means there is no need for backlighting, and backlighting doesn't improve usability. I program best in a dark room as its easier to see my monitor, but moving my hand to grab my beer and then getting my fingers back on home row takes way more time than it should. Good luck on your project
László Monda
I don't think that a totally dark room is good for your eyes. I personally prefer a dim room and some light around the screen so I put some DIY bias lighting on the back of my monitor. For me it's certainly a much better experience. https://plus.google.com/u/0/photos/106435362157390351263/albums/6119923947027041441 Antec also has a pretty sleek looking bias lighting kit: http://www.antec.com/soundscience/products_Bias-Lighting.php Regardless, I'm sure keyboard backlighting has its place but I consider it rather fancy than practical given an ergonomical working environment. Your mileage may vary. Careful with the beer - too much of it can lead to buggy code ;)
fair enough I'm not out to tell you how to run your show- appreciate the links, cheers
This is the closest thing I've ever seen to the developers dream keyboard. Over the years I've thought of a few keyboard designs and this blows anything I've thought of out of the water. I definitely do not want the keys you've mentioned. They take up space and aren't used if you're using vim-like softwares to develop with. Most IDEs support vim plugins so that you're moving your hand off the homerow keys less. The function keys are there if you use a modifier. Those keys aren't pressed often enough to warrant dedicated keys IMO.
It seems that arrow keys can be accessed via a modifier key; that seems sufficient considering their rare use. Also, most development software I've seen nowadays has support either directly or indirectly through plugins for vi commands. As for the split keyboard design, it should prove to be much better ergonomically speaking. I personally don't shift as I type, nor do I think that's standard practice (though to be fair it sounds like it could be pretty efficient). I think the ergonomics outweigh what probably amounts to only a slight loss in WPM.
Sean Peery
Trying to figure out how to do PCB designing to create my own personalized keyboard. What did you use as a component for your keys, or did you just put circles and lines. I ask because I'm worried if I send something to a PCB printing company they'll put the wrong thing in or won't understand the design.
László Monda
You can draw a component for Cherry MX switches in no time but you can also download it. We have yet to release our KiCad files but in the meantime you can download the design files of the GH60 keyboard. http://blog.komar.be/projects/gh60-programmable-keyboard/
I like the general design--this gave me some ideas for building small keyboards of my own (for special purposes). I hadn't considered using a 3D-printed frame for the keyswitches. There are certain tools/programs that would be very difficult to use without a numeric keypad, such as Sibelius music notation software. I suppose you could add an external keypad for those cases if you needed to.
comments powered by Disqus
Free email updates
Get the latest content first.
No spam. Just great articles & insights.
Free email updates
Get the latest content first.
Thank you for subscribing!
Check your inbox to confirm subscription. You'll start receiving posts after you confirm.
Trending articles
Relevant Technologies
About the author
László Monda
Bash Developer
László is a full stack developer experienced in a wide range of languages and frameworks. He boasts a system-wide understanding and comfortably moves across the various layers of the stack.