This guide documents the installation of a custom HHKB keymap that combines three legendary elements:
- The timeless HHKB layout by Eiiti Wada
- Hasu’s revolutionary mouse control layer
- The efficiency of SpaceFN
The result is a zero-compromise configuration that enhances the HHKB while preserving its philosophical purity.
- HHKB Professional (any version)
- USB cable
- Hasu Controller
Choose your preferred environment:
The cleanest and most reliable setup:
# Enter a shell with QMK tools
nix-shell -p qmk
If you prefer the traditional approach:
# Clone QMK Firmware repository
git clone https://github.com/qmk/qmk_firmware.git
cd qmk_firmware
# Install dependencies
util/qmk_install.sh # For Linux/macOS users
This file is an .org!! if you use emacs you can tangle the code and use it directly in your qmk_firmware folder and use literate programming to document your keymap.
Create a dedicated space for your custom keymap:
# Create the keymap directory
mkdir -p keyboards/hhkb/ansi/32u4/keymaps/ultimate
cd keyboards/hhkb/ansi/32u4/keymaps/ultimate
This enables the necessary QMK features:
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
COMMAND_ENABLE = yes # Commands for debug and configuration
NKRO_ENABLE = yes # USB Nkey Rollover
The heart of the configuration. Copy our complete keymap here. The file includes:
- Base HHKB layer
- Function layer with media controls
- Mouse control layer (activated by holding ;)
- VI-style navigation (activated by holding /)
- SpaceFN layer for quick access to function keys
Compile your custom firmware:
# Compile the keymap
qmk compile -kb hhkb/ansi/32u4 -km ultimate
- Remove the HHKB’s back cover
- Locate the reset button (small button near the USB port)
- Connect your HHKB to your computer
- Press the reset button
- Flash the firmware:
qmk flash -kb hhkb/ansi/32u4 -km ultimate
Layer | Activation | Primary Use |
---|---|---|
Base | Default | Standard HHKB typing |
Fn | Fn key | Media & function keys |
Mouse | Hold ; | Complete mouse control |
VI | Hold / | Efficient navigation |
SpaceFN | Hold Space | Quick access to function keys |
- Full mouse control without leaving the home row
- VI-style navigation for efficient text editing
- One-handed F-key access via SpaceFN
- All HHKB standard functions preserved
The keymap is designed to be built upon. Common customizations include:
- Adjusting mouse movement speed
- Changing layer activation keys
- Adding new layers
- Creating custom macros
- Eiiti Wada for the HHKB design philosophy
- Hasu for the alternate controller and mouse layer concept
- QMK Documentation: https://docs.qmk.fm/
- Hasu’s Thread: https://geekhack.org/index.php?topic=12047.0
Your keymap.c content goes here for org-babel-tangle.
/*
██╗ ██╗██╗ ██╗██╗ ██╗██████╗ ██╗ ██╗██╗ ████████╗██╗███╗ ███╗ █████╗ ████████╗███████╗
██║ ██║██║ ██║██║ ██╔╝██╔══██╗ ██║ ██║██║ ╚══██╔══╝██║████╗ ████║██╔══██╗╚══██╔══╝██╔════╝
███████║███████║█████╔╝ ██████╔╝ ██║ ██║██║ ██║ ██║██╔████╔██║███████║ ██║ █████╗
██╔══██║██╔══██║██╔═██╗ ██╔══██╗ ██║ ██║██║ ██║ ██║██║╚██╔╝██║██╔══██║ ██║ ██╔══╝
██║ ██║██║ ██║██║ ██╗██████╔╝ ╚██████╔╝███████╗██║ ██║██║ ╚═╝ ██║██║ ██║ ██║ ███████╗
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚══════╝
*
* [Previous documentation remains exactly the same...]
*/
#include QMK_KEYBOARD_H
enum layers { BASE = 0, FN = 1, MOUSE = 2, VI = 3, SPACE_FN = 4 };
enum custom_keycodes { SPACEFN_TOGGLE = SAFE_RANGE, BT_TOGGLE_KEY, BT_PAIR_KEY };
static bool spacefn_enabled = true;
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Base Layer
* ,-----------------------------------------------------------.
* |Esc| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =| \| `|
* |-----------------------------------------------------------|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Backs|
* |-----------------------------------------------------------|
* |Contro| A| S| D| F| G| H| J| K| L| ;*| '|Enter |
* |-----------------------------------------------------------|
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn|
* `-----------------------------------------------------------'
* |Alt|Gui | Space |SFTog|Alt|
* `-------------------------------------------'
* * ; = Tap for ; or Hold for Mouse Layer
* * / = Tap for / or Hold for VI Layer
* * Space = Tap for Space or Hold for SpaceFN (when enabled)
*/
[BASE] = LAYOUT(KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSLS, KC_GRV, KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSPC, KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, LT(MOUSE, KC_SCLN), KC_QUOT, KC_ENT, KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, LT(VI, KC_SLSH), KC_RSFT, MO(FN), KC_LALT, KC_LGUI, LT(SPACE_FN, KC_SPC), SPACEFN_TOGGLE, KC_RALT),
/* Fn Layer
* ,-----------------------------------------------------------.
* |Pwr| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |-----------------------------------------------------------|
* |Caps | | | | | | | |PSc|SLk|Pus|Up | | |
* |-----------------------------------------------------------|
* | |VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter |
* |-----------------------------------------------------------|
* | |BTP| | | | | +| -|End|PgD|Dow| | |
* `-----------------------------------------------------------'
* |BTS| | Space | | |
* `-------------------------------------------'
* BTS = Bluetooth Toggle Switch
* BTP = Bluetooth Toggle Pair
*/
[FN] = LAYOUT(KC_PWR, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_DEL, KC_CAPS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PSCR, KC_SCRL, KC_PAUS, KC_UP, KC_TRNS, KC_TRNS, KC_TRNS, KC_VOLD, KC_VOLU, KC_MUTE, KC_TRNS, KC_TRNS, KC_PAST, KC_PSLS, KC_HOME, KC_PGUP, KC_LEFT, KC_RGHT, KC_PENT, KC_TRNS, BT_PAIR_KEY, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PPLS, KC_PMNS, KC_END, KC_PGDN, KC_DOWN, KC_TRNS, KC_TRNS, BT_TOGGLE_KEY, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
/* Mouse Layer (Hold ;)
* ,-----------------------------------------------------------.
* | | | | | | | | | | | | | | | |
* |-----------------------------------------------------------|
* | | | | | | |WhL|WhD|MsU|WhU|WhR| | | |
* |-----------------------------------------------------------|
* | |Ac0|Ac1|Ac2| | | |MsL|MsD|MsR| | | |
* |-----------------------------------------------------------|
* | | | | | | |Mb3|Mb2|Mb1|Mb4|Mb5| | |
* `-----------------------------------------------------------'
* | | | Mb1 | | |
* `-------------------------------------------'
* Mb = Mouse Button | Ms = Mouse Movement
* Wh = Mouse Wheel | Ac = Mouse Acceleration
*/
[MOUSE] = LAYOUT(KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_WH_L, KC_WH_D, KC_MS_U, KC_WH_U, KC_WH_R, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_ACL0, KC_ACL1, KC_ACL2, KC_TRNS, KC_TRNS, KC_TRNS, KC_MS_L, KC_MS_D, KC_MS_R, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN3, KC_BTN2, KC_BTN1, KC_BTN4, KC_BTN5, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_BTN1, KC_TRNS, KC_TRNS),
/* Vi Layer (Hold /)
* ,-----------------------------------------------------------.
* | | | | | | | | | | | | | | | |
* |-----------------------------------------------------------|
* | | | | | | | |Hom|Up |End| | | | |
* |-----------------------------------------------------------|
* | | | | | | |PgU|Lef|Dow|Rig| | | |
* |-----------------------------------------------------------|
* | | | | | | |PgD| | | | | | |
* `-----------------------------------------------------------'
* | | | Space | | |
* `-------------------------------------------'
*/
[VI] = LAYOUT(KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_UP, KC_END, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGDN, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS),
/* SpaceFN Layer (Hold Space)
* ,-----------------------------------------------------------.
* |` | F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
* |-----------------------------------------------------------|
* | | | |Esc| | | |Hom|Up |End|PSc|SLk|Pau| |
* |-----------------------------------------------------------|
* | | | | | | |PgU|Lef|Dow|Rig| | | |
* |-----------------------------------------------------------|
* | | | | | |Spc|PgD| | | | | | |
* `-----------------------------------------------------------'
* | | | Space | | |
* `-------------------------------------------'
*/
[SPACE_FN] = LAYOUT(KC_GRV, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_INS, KC_DEL, KC_TRNS, KC_TRNS, KC_TRNS, KC_ESC, KC_TRNS, KC_TRNS, KC_TRNS, KC_HOME, KC_UP, KC_END, KC_PSCR, KC_SCRL, KC_PAUS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_PGUP, KC_LEFT, KC_DOWN, KC_RGHT, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_SPC, KC_PGDN, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS)};
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case SPACEFN_TOGGLE:
if (record->event.pressed) {
spacefn_enabled = !spacefn_enabled;
if (!spacefn_enabled) {
layer_off(SPACE_FN);
}
}
return false;
case BT_TOGGLE_KEY:
if (record->event.pressed) {
SEND_STRING("$" SS_DELAY(100) "sw");
}
return false;
case BT_PAIR_KEY:
if (record->event.pressed) {
SEND_STRING("$" SS_DELAY(100) "pair");
}
return false;
case LT(SPACE_FN, KC_SPC):
if (spacefn_enabled) {
return true;
} else {
if (record->event.pressed) {
register_code(KC_SPC);
} else {
unregister_code(KC_SPC);
}
return false;
}
default:
return true;
}
}
/*
* 🔧 Usage Guide 🔧
* ================
*
* This keymap combines multiple powerful features:
*
* 1. Classic HHKB Layer (Always active)
* - Your familiar HHKB layout, untouched in its perfection
* - SpaceFN can be toggled on/off using the dedicated key
*
* 2. Mouse Control (Hold Semicolon)
* - Mouse movement: IJKL
* - Mouse buttons: M, <, >
* - Wheel: YUIO
* - Adjustable speed: ASD
*
* 3. VI Navigation (Hold Slash)
* - Cursor: HJKL (VI style)
* - Page Up/Down, Home/End easily accessible
* - Perfect for text editing and coding
*
* 4. SpaceFN Features (Hold Space)
* - F1-F12 keys in number row
* - Navigation cluster around IJKL
* - System keys (Print Screen, Scroll Lock, Pause)
* - Can be disabled with SpaceFN Toggle key
*
* 5. Traditional Fn Layer (Fn Key)
* - Standard HHKB function layer
* - Media controls
* - Arrow keys
* - Bluetooth controls:
* + Fn + Left Alt: Toggle Bluetooth
* + Fn + Z: Pair Bluetooth
*
* 💫 Pro Tips:
* - Use Mouse layer for precise pointer control
* - VI layer is perfect for code navigation
* - SpaceFN gives you lightning-fast access to F-keys
* - Toggle SpaceFN off temporarily when needed
* - Use Bluetooth controls for quick device switching
* - Combine layers creatively for maximum efficiency
*
* Remember Wada-san's wisdom: mastery takes time, but the results are worth it.
*
* Happy Hacking! ⌨
*
* Special thanks to Hasu for the original alternate controller
* and his invaluable help in the geekhack forums.
*
* Version: 1.1
* Author: Pascual Muñoz Galián
* Source: https://github.com/pascualmg/hhkb-ultimate
*
* This keymap is shared with the community in the spirit of
* open source and the HHKB philosophy. Feel free to modify
* and improve upon it!
*/