3 The miryoku layout is an ergonomic, minimal, orthogonal layout for ergo or ortho
4 keyboards, implemented as part of the QMK firmware. The layout is maintained in
5 emacs org-mode tables and converted to QMK keymap data structures using embedded
6 python scripts. The layout is mapped onto keyboards with different physical
7 layouts as a subset without code duplication using the QMK userland feature and
8 C macros. Versions of the layout can also be seen outside of the QMK source at
9 [[https://github.com/manna-harbour/miryoku/]].
14 - [[#code-generation][Code Generation]]
15 - [[#subset-mapping][Subset Mapping]]
25 *** General Principles
27 - Use layers instead of reaching.
28 - Use both hands instead of contortions.
29 - Use the home positions as much as possible.
30 - Make full use of the thumbs.
31 - Avoid unnecessary complication.
36 - 5 columns, 3 rows, 3 thumb keys, 2 hands.
37 - Can be used on almost any split or non-split ergo or ortho keyboard.
38 - Includes all keys found on a US layout TKL keyboard, plus media keys and
40 - Home row is the middle row, home thumb key is the middle thumb key.
41 - Maximum 1-u movement from home position for fingers and thumbs, and only
42 along one axis (except for the inner index finger column which is
43 deprioritised compared with the home columns).
44 - Dual-function modifiers on home row, mirrored on both hands.
45 - Dual-function layer change on thumbs.
46 - Layers are designed orthogonally with a single purpose per hand and are
47 accessed by holding a thumb key on the opposite hand.
48 - Holding layer change and modifiers on one hand combined with a single key
49 press on the other hand can produce any combination of modifiers and
50 single keys without any finger contortions.
51 - Single function mods are also defined on layers on the same hand as the
52 layer change thumb key so layer change and mods can be held in any order
53 or simultaneously without race conditions.
54 - As mods are only enabled on the opposite hand, auto-repeat is available on
55 the home row on layers for use with cursor and mouse keys.
56 - Tap-hold auto-repeat is disabled to enable faster tap-hold switching on
57 thumbs but thumb tap keys are mirrored onto some layers for use with
63 The layers are maintained in tables, with the thumb keys on the bottom row. NP
64 indicates the key is not present and is used to fill in the table around the
65 thumb keys. The grid arrangement of the tables does not imply a particular
68 Basic keycodes are entered without the KC_ prefix. Symbols can be entered as-is
69 (excepting '"' (DQUO) and '|' (PIPE)). Empty cells are unused.
71 The base layer has both halves of the layout joined for convenience. Other
72 layers are specified as a single hand.
77 The base layer is maintained as separate tap and hold tables and are combined
78 into the corresponding tap-hold keycodes for mods and layer change. RST and
79 mods will be available on sub layers on the same hand as the layer change thumb
80 key. Unknown names are considered to be layer names.
82 Base layer alphas are Colemak DHm. Thumb keys are backspace, enter, delete on
83 the right and space, tab, escape on the left. Dot, comma and apostrophe are
84 included for prose, dot and slash for file and directory names.
87 | Q | W | F | P | B | J | L | U | Y | ' |
88 | A | R | S | T | G | M | N | E | I | O |
89 | Z | X | C | D | V | K | H | , | . | / |
90 | NP | NP | ESC | SPC | TAB | ENT | BSPC | DEL | NP | NP |
93 | RST | | | | | | | | | RST |
94 | LGUI | LALT | LCTL | LSFT | | | LSFT | LCTL | LALT | LGUI |
96 | NP | NP | MEDR | NAVR | MOUR | NSSL | NSL | FUNL | NP | NP |
101 Primary right-hand layer (left home thumb) is navigation and editing. Cursor
102 keys are on the home position, line and page movement below, clipboard above,
103 caps and insert on the inner column. Thumb keys are duplicated from the base
104 layer to avoid having to layer change mid edit and to enable auto-repeat.
107 | AGIN | UNDO | CUT | COPY | PSTE |
108 | CAPS | LEFT | DOWN | UP | RGHT |
109 | INS | HOME | PGDN | PGUP | END |
110 | ENT | BSPC | DEL | NP | NP |
115 Secondary RH layer is mouse emulation. Mouse movement mirrors cursor navigation
116 on home and wheel mirrors line / page movement below. Buttons are on the
117 thumbs. Mouse movement, click, and drag with modifiers can be performed from
118 the home position. Unused keys are available for other related functions.
122 | | MS_L | MS_D | MS_U | MS_R |
123 | | WH_L | WH_D | WH_U | WH_R |
124 | BTN3 | BTN1 | BTN2 | NP | NP |
129 Tertiary RH layer is media control, with volume up / down and next / prev
130 mirroring the navigation keys. Pause, stop and mute are on thumbs. Unused keys
131 are available for other related functions.
135 | | MPRV | VOLD | VOLU | MNXT |
137 | MSTP | MPLY | MUTE | NP | NP |
140 *** Numerals and Symbols (NSL)
142 Primary left-hand layer (right home thumb) is numerals and symbols. Numerals
143 are in the standard numpad locations with symbols in the remaining positions.
144 Dot is duplicated from the base layer for convenience.
147 | [ | 7 | 8 | 9 | ] |
148 | ; | 4 | 5 | 6 | = |
149 | ` | 1 | 2 | 3 | \ |
150 | NP | NP | . | 0 | - |
153 *** Shifted Numerals and Symbols (NSSL)
155 Secondary LH layer has shifted symbols in the same locations to reduce chording
156 when using mods with shifted symbols. Automatically generated from unshifted
160 *** Function and System (FUNL)
162 Tertiary LH layer has function keys mirroring the numerals on the primary layer
163 with extras on the pinkie column, plus system keys on the inner column. App
164 (menu) is on the tertiary thumb key and other thumb keys are duplicated from the
165 base layer to enable auto-repeat.
169 | F12 | F7 | F8 | F9 | PSCR |
170 | F11 | F4 | F5 | F6 | SLCK |
171 | F10 | F1 | F2 | F3 | PAUS |
172 | NP | NP | APP | SPC | TAB |
175 *** COMMENT Templates
178 | <l4> | <l4> | <l4> | <l4> | <l4> | <l4> | <l4> | <l4> | <l4> | <l4> |
179 |------+------+------+------+------+------+------+------+------+------|
180 | | | | | | | | | | |
181 | | | | | | | | | | |
182 | | | | | | | | | | |
183 | NP | NP | | | | | | | NP | NP |
186 Duplicate base layer tap keys on thumbs rather than trans to enable auto-repeat.
189 | <l4> | <l4> | <l4> | <l4> | <l4> |
190 |------+------+------+------+------|
194 | ENT | BSPC | DEL | NP | NP |
197 | <l4> | <l4> | <l4> | <l4> | <l4> |
198 |------+------+------+------+------|
202 | NP | NP | ESC | SPC | TAB |
207 :CUSTOM_ID: code-generation
210 ** Table Conversion Scripts
212 *** table-layout-taphold
214 Produce base layer from separate tap and hold tables.
216 #+NAME: table-layout-taphold
217 #+BEGIN_SRC python :var tap_table=tap :var hold_table=hold :var symbol_names_table=symbol-names :var mods_list=mods :tangle no :results verbatim
219 mods_dict = dict.fromkeys(mods_list)
220 symbol_names_dict = {}
221 for symbol, name, shifted_symbol, shifted_name in symbol_names_table:
222 symbol_names_dict[symbol] = name
223 symbol_names_dict[shifted_symbol] = shifted_name
224 results = ' [BASE] = LAYOUT_miryoku(\n'
225 for tap_row, hold_row in map(None, tap_table, hold_table):
227 for tap, hold in map(None, tap_row, hold_row):
230 elif tap in symbol_names_dict:
231 code = symbol_names_dict[tap]
234 code = 'KC_' + str(code)
235 if hold in mods_dict:
236 code = str(hold) + '_T(' + code + ')'
237 elif hold != '' and hold != 'NP' and hold != 'RST':
238 code = 'LT(' + str(hold) + ', ' + code + ')'
239 results += (code + ', ').ljust(width)
240 results = results.rstrip(' ') + '\n'
241 results = results.rstrip('\n, ') + '\n )'
245 #+RESULTS: table-layout-taphold
246 : [BASE] = LAYOUT_miryoku(
247 : KC_Q, KC_W, KC_F, KC_P, KC_B, KC_J, KC_L, KC_U, KC_Y, KC_QUOT,
248 : LGUI_T(KC_A), LALT_T(KC_R), LCTL_T(KC_S), LSFT_T(KC_T), KC_G, KC_M, LSFT_T(KC_N), LCTL_T(KC_E), LALT_T(KC_I), LGUI_T(KC_O),
249 : KC_Z, KC_X, KC_C, KC_D, KC_V, KC_K, KC_H, KC_COMM, KC_DOT, KC_SLSH,
250 : KC_NP, KC_NP, LT(MEDR, KC_ESC), LT(NAVR, KC_SPC), LT(MOUR, KC_TAB), LT(NSSL, KC_ENT), LT(NSL, KC_BSPC), LT(FUNL, KC_DEL), KC_NP, KC_NP
254 *** table-layout-half
256 Produce sub layers given layer name and corresponding table for single hand and
257 incorporating mods and reset from base layer. Layer names must end with R or L.
258 A layer with shifted symbols can also be generated.
260 #+NAME: table-layout-half
261 #+BEGIN_SRC python :var hold_table=hold :var layer_name="NSL" :var half_table=nsl :var symbol_names_table=symbol-names :var mods_list=mods :var shift="false" :tangle no :results verbatim
263 mods_dict = dict.fromkeys(mods_list)
264 symbol_names_dict = {}
265 shifted_symbol_names_dict = {}
266 for symbol, name, shifted_symbol, shifted_name in symbol_names_table:
267 symbol_names_dict[symbol] = name
268 symbol_names_dict[shifted_symbol] = shifted_name
269 shifted_symbol_names_dict[symbol] = shifted_name
270 length = len(half_table[0])
271 mode = layer_name[-1:].lower()
272 results = ' [' + layer_name + '] = LAYOUT_miryoku(\n'
273 for half_row, hold_row in map(None, half_table, hold_table):
275 hold_row_l, hold_row_r = hold_row[:length], hold_row[length:]
276 for lr, hold_row_lr in ('l', hold_row_l), ('r', hold_row_r):
278 for half in half_row:
281 elif shift == "true" and half in shifted_symbol_names_dict:
282 code = shifted_symbol_names_dict[half]
283 elif half in symbol_names_dict:
284 code = symbol_names_dict[half]
287 results += ('KC_' + str(code) + ', ').ljust(width)
289 for hold in hold_row_lr:
290 if hold == '' or hold != 'NP' and hold != 'RST' and hold not in mods_dict:
294 results += ('KC_' + str(code) + ', ').ljust(width)
295 results = results.rstrip(' ') + '\n'
296 results = results.rstrip('\n, ') + '\n )'
300 #+RESULTS: table-layout-half
301 : [NSL] = LAYOUT_miryoku(
302 : KC_LBRC, KC_7, KC_8, KC_9, KC_RBRC, KC_NA, KC_NA, KC_NA, KC_NA, KC_RST,
303 : KC_SCLN, KC_4, KC_5, KC_6, KC_EQL, KC_NA, KC_LSFT, KC_LCTL, KC_LALT, KC_LGUI,
304 : KC_GRV, KC_1, KC_2, KC_3, KC_BSLS, KC_NA, KC_NA, KC_NA, KC_NA, KC_NA,
305 : KC_NP, KC_NP, KC_DOT, KC_0, KC_MINS, KC_NA, KC_NA, KC_NA, KC_NP, KC_NP
311 Produce layer enums from layer names in hold table.
314 #+BEGIN_SRC python :var hold_table=hold :var mods_list=mods :tangle no
315 mods_dict = dict.fromkeys(mods_list)
316 results = 'enum layers { BASE, '
317 for hold_row in hold_table:
318 for hold in hold_row:
319 if hold not in mods_dict and hold != '' and hold != 'NP' and hold != 'RST':
320 results += hold + ', '
321 results = results.rstrip(', ') + ' };'
325 #+RESULTS: table-enums
326 : enum layers { BASE, MEDR, NAVR, MOUR, NSSL, NSL, FUNL };
333 Symbol, name, and shifted symbol mappings for use in tables.
336 | ` | GRV | ~ | TILD |
337 | - | MINS | _ | UNDS |
338 | = | EQL | + | PLUS |
339 | [ | LBRC | { | LCBR |
340 | ] | RBRC | } | RCBR |
341 | \ | BSLS | PIPE | PIPE |
342 | ; | SCLN | : | COLN |
343 | ' | QUOT | DQUO | DQUO |
344 | , | COMM | < | LT |
346 | / | SLSH | ? | QUES |
361 Modifiers usable in hold table. Need to have the same name for KC_ and _T versions.
375 Header for tangled src files.
378 #+BEGIN_SRC C :tangle no
379 generated from users/manna-harbour_miryoku/miryoku.org
385 :CUSTOM_ID: subset-mapping
390 The keymap and configuration are shared between keyboards. The keymap is
391 defined for LAYOUT_miryoku which is 10x4, with the outer 2 positions on the
392 bottom row unused and the rest of the bottom row are the thumb keys.
395 *** manna-harbour_miryoku.c
397 Contains the keymap. Included from keymap.c
399 [[./manna-harbour_miryoku.c][users/manna-harbour_miryoku/manna-harbour_miryoku.c]]
400 #+BEGIN_SRC C :noweb yes :tangle manna-harbour_miryoku.c
404 #include QMK_KEYBOARD_H
406 #define KC_NP KC_NO // key is not present
407 #define KC_NA KC_NO // present but not available for use
408 #define KC_NU KC_NO // available but not used
413 const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
414 <<table-layout-taphold()>>,
415 <<table-layout-half(layer_name="NAVR", half_table=navr)>>,
416 <<table-layout-half(layer_name="MOUR", half_table=mour)>>,
417 <<table-layout-half(layer_name="MEDR", half_table=medr)>>,
418 <<table-layout-half(layer_name="FUNL", half_table=funl)>>,
419 <<table-layout-half(layer_name="NSL", half_table=nsl)>>,
420 <<table-layout-half(layer_name="NSSL", half_table=nsl, shift="true")>>
427 Config options. Automatically included.
429 [[./config.h][users/manna-harbour_miryoku/config.h]]
430 #+BEGIN_SRC C :noweb yes :tangle config.h
436 // Prevent normal rollover on alphas from accidentally triggering mods.
437 #define IGNORE_MOD_TAP_INTERRUPT
439 // Enable rapid switch from tap to hold, disables double tap hold auto-repeat.
440 #define TAPPING_FORCE_HOLD
442 // Recommended for heavy chording.
443 #define QMK_KEYS_PER_SCAN 4
450 Build options. Automatically included.
452 [[./rules.mk][users/manna-harbour_miryoku/rules.mk]]
453 #+BEGIN_SRC makefile :noweb yes :tangle rules.mk
457 MOUSEKEY_ENABLE = yes # Mouse keys(+4700)
458 EXTRAKEY_ENABLE = yes # Audio control and System control(+450)
465 To use the keymap on a keyboard supporting the layouts feature, LAYOUT_miryoku
466 is defined as a macro mapping onto the layout's own LAYOUT macro, leaving the
467 unused keys as KC_NO. The userspace keymap is then included.
471 For the ergodox layout, the main 5x3 alphas are used as usual. The primary and
472 secondary thumb keys are the inner and outer 2u thumb keys and the tertiary
473 thumb key is the innermost key of the partial bottom row. The remaining keys
476 [[../../layouts/community/ergodox/manna-harbour_miryoku/keymap.c][layouts/community/ergodox/manna-harbour_miryoku/keymap.c]]
477 #+BEGIN_SRC C :noweb yes :tangle ../../layouts/community/ergodox/manna-harbour_miryoku/keymap.c
481 #define LAYOUT_miryoku(\
482 K00, K01, K02, K03, K04, K05, K06, K07, K08, K09,\
483 K10, K11, K12, K13, K14, K15, K16, K17, K18, K19,\
484 K20, K21, K22, K23, K24, K25, K26, K27, K28, K29,\
485 N30, N31, K32, K33, K34, K35, K36, K37, N38, N39\
487 LAYOUT_ergodox_pretty( \
488 KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, \
489 KC_NO, K00, K01, K02, K03, K04, KC_NO, KC_NO, K05, K06, K07, K08, K09, KC_NO, \
490 KC_NO, K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, KC_NO, \
491 KC_NO, K20, K21, K22, K23, K24, KC_NO, KC_NO, K25, K26, K27, K28, K29, KC_NO, \
492 KC_NO, KC_NO, KC_NO, KC_NO, K32, K37, KC_NO, KC_NO, KC_NO, KC_NO, \
493 KC_NO, KC_NO, KC_NO, KC_NO, \
495 K33, K34, KC_NO, KC_NO, K35, K36 \
498 #include "manna-harbour_miryoku.c"
502 To build for any keyboard using the this layout (ergodone, ergodox_ez,
503 ergodox_infinity, hotdox) e.g. the ergodox_ez,
505 #+BEGIN_SRC sh :tangle no
506 cd ../.. && make ergodox_ez:manna-harbour_miryoku:teensy
513 For the ortho_4x12 layout, the right half as is as follows: The rightmost column
514 bottom 3 rows is the pinkie column. The middle 4 columns top 3 rows are for the
515 remaining fingers. The bottom row left 3 columns are the thumb keys. The
516 remaining keys are unused.
518 [[../../layouts/community/ortho_4x12/manna-harbour_miryoku/keymap.c][layouts/community/ortho_4x12/manna-harbour_miryoku/keymap.c]]
519 #+BEGIN_SRC C :noweb yes :tangle ../../layouts/community/ortho_4x12/manna-harbour_miryoku/keymap.c
523 #define LAYOUT_miryoku(\
524 K00, K01, K02, K03, K04, K05, K06, K07, K08, K09,\
525 K10, K11, K12, K13, K14, K15, K16, K17, K18, K19,\
526 K20, K21, K22, K23, K24, K25, K26, K27, K28, K29,\
527 N30, N31, K32, K33, K34, K35, K36, K37, N38, N39\
530 KC_NO, K01, K02, K03, K04, KC_NO, KC_NO, K05, K06, K07, K08, KC_NO,\
531 K00, K11, K12, K13, K14, KC_NO, KC_NO, K15, K16, K17, K18, K09,\
532 K10, K21, K22, K23, K24, KC_NO, KC_NO, K25, K26, K27, K28, K19,\
533 K20, KC_NO, KC_NO, K32, K33, K34, K35, K36, K37, KC_NO, KC_NO, K29\
536 #include "manna-harbour_miryoku.c"
540 To build for any keyboard using this layout (4x4, nori, chimera_ls, contra,
541 divergetm2, jj40, lets_split, lets_split_eh, meira, niu_mini, planck, telophase,
542 vitamins_included, zinc, zlant, ortho48, kbd4x, levinson, wavelet, plaid)
545 #+BEGIN_SRC sh :tangle no
546 make keebio/levinson:manna-harbour_miryoku:avrdude
552 To use the keymap on a keyboard which does not support the layouts feature,
553 LAYOUT_miryoku is defined as a macro mapping onto the keyboard's own LAYOUT
554 macro, leaving the unused keys as KC_NO. The userspace keymap is then included.
559 The outer columns are unused.
561 [[../../keyboards/crkbd/keymaps/manna-harbour_miryoku/keymap.c][keyboards/crkbd/keymaps/manna-harbour_miryoku/keymap.c]]
562 #+BEGIN_SRC C :noweb yes :tangle ../../keyboards/crkbd/keymaps/manna-harbour_miryoku/keymap.c
566 #define LAYOUT_miryoku( \
567 K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, \
568 K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, \
569 K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, \
570 N30, N31, K32, K33, K34, K35, K36, K37, N38, N39 \
573 KC_NO, K00, K01, K02, K03, K04, K05, K06, K07, K08, K09, KC_NO, \
574 KC_NO, K10, K11, K12, K13, K14, K15, K16, K17, K18, K19, KC_NO, \
575 KC_NO, K20, K21, K22, K23, K24, K25, K26, K27, K28, K29, KC_NO, \
576 K32, K33, K34, K35, K36, K37 \
579 #include "manna-harbour_miryoku.c"
583 To build for this keyboard,
585 #+BEGIN_SRC sh :tangle no
586 cd ../.. && make crkbd:manna-harbour_miryoku:avrdude
590 * Related Documentation
595 - https://docs.qmk.fm/#/getting_started_introduction
596 - https://docs.qmk.fm/#/hardware_keyboard_guidelines
597 - https://docs.qmk.fm/#/config_options
598 - https://docs.qmk.fm/#/keycodes
599 - https://docs.qmk.fm/#/feature_advanced_keycodes
600 - https://docs.qmk.fm/#/feature_layouts
601 - https://docs.qmk.fm/#/feature_userspace
602 - https://docs.qmk.fm/#/getting_started_make_guide
607 - https://orgmode.org/
608 - https://orgmode.org/manual/Tables.html
609 - https://orgmode.org/manual/Working-with-Source-Code.html