MoErgo Glove80 programmable ergonomic keyboard

Suraj N. Kurapati

NOTE: Check out the interactive layer map for this keyboard below!

Photograph of my MoErgo Glove80 keyboard.

Is that… Batman’s keyboard?! 🦇 No, but it sure makes me feel like him: sitting in the turquoise glow of the Batcomputer, deep within the quiet solitude of the Batcave, saving the world with this ergonomic marvel!

This is my MoErgo Glove80 keyboard: a split, columnar, contoured, and wireless ergonomic marvel that has become my “endgame” choice for the foreseeable future. Previously, I used an Ergohaven Remnant keyboard for 6 months, a Dactyl Manuform 5x6 keyboard for a year, an ErgoDox EZ keyboard for 6 years, and a Kinesis Advantage keyboard for 11 years prior — all on the quest for better ergonomics.

  1. Review
    1. Impression
      1. Adaptation
        1. Comparison
        2. Layers
          1. Lower layer
            1. Typing layer
              1. Gaming layer
              2. Cursor layer
                1. Mouse usage
                  1. Arrow keys
                    1. Select & edit
                    2. Number layer
                      1. Date & time
                        1. Arithmetic
                          1. Prefix signs
                            1. Inequalities
                              1. Vim navigation
                              2. Function layer
                                1. Symbol layer
                                  1. Base layer affinity
                                    1. Vim editor shortcuts
                                      1. Adjacent key bigrams
                                        1. Outer corner bigrams
                                          1. Inward rolling bigrams
                                            1. Outward rolling bigrams
                                            2. Mouse layer
                                              1. System layer
                                              2. Firmware
                                                1. Custom Defined Behaviors
                                                  1. Mirroring horizontally

                                                  Review

                                                  Embodying a thoughtful, humanistic design that is forgiving (accommodating a broad range of hand sizes and shapes), inviting (like a lounge chair whose intuitive shape beckons weary hands to perch down for some well deserved rest), and futuristic (like some advanced Space Age technology that Batman would use), the Glove80 provides a comfortable, efficient, and delightful typing experience.

                                                  For me, the Glove80 is like a dream come true because it brings together the best features of all the keyboards I’ve used so far on my quest for ergonomics:

                                                  Ergonomic keyboard Duration of use Split design? Contoured keywells? Columnar layout? Programmable firmware? Low height? Wireless capable?
                                                  MoErgo Glove80 🏆 1 month
                                                  Ergohaven Remnant 6 months
                                                  Dactyl Manuform 5x6 1 year
                                                  ZSA ErgoDox EZ 6 years
                                                  Kinesis Advantage 11 years 🌔 🌒
                                                  Goldtouch Adjustable 1 year 🌓
                                                  Microsoft Natural Elite 2 years 🌒

                                                  I especially revered the Kinesis Advantage for its unconventional yet ingenious design, but I often wished it were split so that I could separate the keywells at shoulder width apart for a more relaxed, natural stance. Thus I embarked on a split keyboard journey, sacrificing keywells in favor of a split design. 💔 Fortunately, my original wish has now been granted: the Glove80 delivers it all!

                                                  Impression

                                                  My first impressions of this keyboard, after connecting it to my computer, were:

                                                  Adaptation

                                                  On my first day using the Glove80, coming from an Ergohaven Remnant keyboard, I felt right at home: achieving 100 WPM on MonkeyType, as shown below. And this speed is with home row mods, disambiguated by ZMK’s global-quick-tap feature! 🚀

                                                  First day on Glove80: achieved 100 WPM on MonkeyType!

                                                  Key travel is definitely less pronounced on the Glove80’s special-order Choc v1 Red key switches, which allows for a more rapid inter-key typing speed, and the tighter key spacing afforded by Choc switches (compared to MX switches) along with the Glove80’s ergonomic curvature are helping to minimize finger travel around the keyboard. With more practice (just normal usage over time), I feel confident that I can increase my touch-typing speed even further on the Glove80.

                                                  Porting my QMK keymap from the Remnant over to ZMK on the Glove80 was challenging, mainly because my home row mods disambiguation logic is so complex. Notably, I worried whether I would be able to translate all the nuances of my QMK patch (which took over 6 months of occasional development to master) to ZMK, but thankfully it was significantly simpler than what I had imagined: without modifying ZMK source code or writing C extensions, I was able to port nearly all of that monstrous sophistication using declarative snippets of custom behaviors!

                                                  Comparison

                                                  Bird's eye view of my Glove80 and Remnant keyboards.

                                                  In terms of quality, the Glove80 is strong yet light: hallmarks of high-end polycarbonate material, which is also used to make optical lenses in eyeglasses. This stands opposite to the Remnant’s light yet fragile 3D-printed construction, which requires careful handling since it can be damaged easily, say, if dropped.

                                                  In terms of height, the Glove80 achieves a lower height profile due to its center of gravity (its keywell nearly touches the desk!) in combination with low-profile Choc switches and keycaps. Even at its tallest point, the Glove80 still stands below the height of the Remnant’s top-inner corner key (number 5).

                                                  Outer profile: looking from the left side toward the center.

                                                  👆 Outer profile: looking from the left side toward the center.

                                                  Inner profile: looking from the center toward the left side.

                                                  👆 Inner profile: looking from the center toward the left side.

                                                  Front profile: looking from the palm rest toward the back.

                                                  👆 Front profile: looking from the palm rest toward the back.

                                                  Back profile: looking from the back toward the palm rest.

                                                  👆 Back profile: looking from the back toward the palm rest.

                                                  In terms of weight, the Glove80 feels much lighter than the Remnant even though it weighs negligibly more: using a kitchen scale, I observed that the right half of the Glove80 (with palm rest) weighed 9.7oz / 275g whereas the Remnant’s (without palm rest) weighed 9.6oz / 272g. However, the Glove80’s weight is more evenly distributed over its surface so it doesn’t feel as heavy when you lift it up; whereas the Remnant’s shape is more condensed, bulkier, and harder to grasp.

                                                  In terms of mobility, the Glove80’s two halves always communicate wirelessly whereas the left half can be wired, wireless, or both (since it supports connecting to 5 devices simultaneously: 4 Bluetooth devices and 1 USB device). This allows both halves, especially the right half, to be repositioned at will. For instance, I sometimes need more writing space on my desk to take notes or doodle, so I simply lift the right half up & away to make room for my notebook. And when I’m finished, I simply move the right half back into position: setting it down wherever I find is comfortable for me, approximately at shoulder width. This is in stark contrast to the Remnant, which is always and only wired to USB. As a result, I’m hesitant to reposition the Remnant’s two halves freely because that may disturb their perfect symmetry, which is tedious to restore accurately.

                                                  In terms of compatibility, the Glove80 works flawlessly with wireless Bluetooth devices, like smartphones, as well as wired USB devices, like laptops. The former is especially remarkable: I connected my Glove80 to my smartphone as an experiment to type in a passphrase (why struggle with a virtual on-screen keyboard when you’ve got the real thing Bluetooth-enabled?) and I was amazed! 🤩 This has unlocked a massive productivity boost for the otherwise inefficient smartphone user interface. It’s quite the game changer: Glove80 for the win! ❤️‍🔥

                                                  In terms of firmware, the Glove80’s online layout editor makes it easy to customize the keymap and share it with others: there is a free-form text box for notes alongside a “Custom Defined Behaviors” box for ZMK configuration snippets, which lets you implement advanced features such as home row mods disambiguation. And once you’ve built and downloaded your keymap from the online layout editor, flashing the resulting *.uf2 file is a simple drag & drop operation after entering bootloader mode, which has a robust hardware fail-safe of holding particular keys while powering on the keyboard, as documented in the user guide.

                                                  In terms of documentation, the Glove80 comes with a comprehensive user guide that covers everything from ergonomics to soldering; gentle introductory emails when your order is being prepared for shipment; and a helpful Discord community so thoughtful and engaging that I look forward to participating in it every day.

                                                  In terms of support, the Glove80’s inventors are active participants in the Discord community, and they’re reachable directly by email and other means too; their professional demeanor and responsiveness is often applauded by customers. This is significantly better than the Remnant’s support, where language and cultural differences sometimes complicate communication and problem resolution.

                                                  Overall, the Glove80 is a phenomenal upgrade over the Remnant and all other ergonomic keyboards I’ve used before. It’s like a dream come true: I love it! 👌

                                                  Layers

                                                  The keyboard boots up into the following default “base” layer when powered on. When held, the purple keys in the thumb clusters activate the subsequent layers according to the legendary Miryoku’s 6-layer design with 3-key thumb activation.

                                                  Interactive: Hover your mouse over the purple keys to see each layer!

                                                  The keys are arranged in my variation of Arno Klein’s Engram 2.0 layout and they’re imbued with the legendary Miryoku home row mods tamed with enhancements.

                                                  Going beyond Miryoku, I have added a custom layer locking feature whereby a Miryoku layer can be set to remain active even after you release its thumb key: while holding the Lower key, simply tap your desired Miryoku layer’s thumb key. To unlock the layer, tap the Lower key again on the same hand as its thumb key.

                                                  Lower layer

                                                  Diagram of the lower layer.

                                                  This layer provides a layer locking facility for the other layers in the keymap:

                                                  Typing layer

                                                  Diagram of the typing layer.

                                                  This layer temporarily disables Miryoku layers and home row modifiers so that you can focus on typing, without the risk of activating them unintentionally. It’s meant for practicing your touch-typing skills and is helpful for newcomers.

                                                  Gaming layer

                                                  Diagram of the gaming layer.

                                                  This layer repositions the WASD cluster to better fit the Glove80’s ergonomic curvature while retaining the conventional placement of the pinky finger’s keys. Consequently, the index finger’s home position is shifted down by one row (on the “D” key) instead of the home row (on the “E” key), as marked in the diagram.

                                                  It also replicates the first column of the right half of the keyboard on the left half because it’s common practice in games to place hotkeys on both central columns as they assume close proximity on conventional row-staggered keyboards. For example, notice how the home row ends with F and so the G wraps back around.

                                                  Similarly, it also replicates nearby hotkeys (such as M for map) on the top.

                                                  Cursor layer

                                                  Diagram of the cursor layer.

                                                  Mouse usage

                                                  Many keys from the right half are mirrored on the left half for more convenient right-handed mouse usage. For example, you can select and drag with your right hand on the mouse while cutting, copying, and pasting with your left hand on the keyboard. Similarly, you can undo & redo and run the text selection macros too.

                                                  Arrow keys

                                                  The up/down arrow keys on the right-hand home row diverge from Vim’s HJKL order because it feels more natural to follow the inward-rising curve of the keyboard’s contoured keywell, which elevates the thumb above the pinky finger and, similarly, the middle finger (up arrow) above the ring finger (down arrow).

                                                  This is a longstanding preference that I formed 17 years ago, in my early days of using the Kinesis Advantage with the Dvorak layout, whose lack of HJKL provided the freedom to reimagine the arrangement of arrow keys on the home row.

                                                  Select & edit

                                                  Editing (index finger) and selection (thumb cluster) keys line the inner wall. This opposition allows for pinching, where selections can be followed by edits. For example, to copy everything, I would first tap the “Select all” key with my thumb and then pinch slightly inward to tap the “Copy” key with my index finger.

                                                  The copy and paste keys are stacked vertically, in that order, to allow the index finger to rake down upon them in a natural curling motion toward the palm. This order is also logical, since pasting requires something to be copied first.

                                                  The select & extend word/line keys on the thumb cluster are ZMK macros that approximate Pascal Getreuer’s word selection QMK macro, which automates common selection tasks that require holding down Control and Shift with the arrow keys:

                                                  Video demonstration of Pascal Getreuer's word selection QMK macro

                                                  These keys can be combined with the Shift modifier to reverse their direction. In some apps, the select word key cycles to the next successive word each time!

                                                  Number layer

                                                  Diagram of the number layer.

                                                  A 3x3 numeric keypad (using the standard 10-key layout) occupies the home block. The period and comma keys are positioned near the zero key on the thumb cluster.

                                                  Date & time

                                                  The slash and minus keys are positioned for MM/DD and YYYY-MM-DD date entry. Similarly, the colon key is positioned above them for HH:MM:SS time stamp entry.

                                                  Arithmetic

                                                  Common arithmetic operators pair along the sides of the 3x3 numeric keypad.

                                                  Prefix signs

                                                  Signs that commonly prefix numbers line the top of the 3x3 numeric keypad.

                                                  Inequalities

                                                  Comparison operators are positioned along the perimeter of the home block.

                                                  Vim navigation

                                                  Vim navigation operators (prefixed by a number N) fill the rightmost column:

                                                  Function layer

                                                  Diagram of the function layer.

                                                  The function keys are arranged in the same 10-key layout as the Number layer’s 3x3 numeric keypad so that you can develop common muscle memory for both layers. The remaining F10-F12 keys wrap around the home block because they’re found in shortcuts such as BIOS save/quit, fullscreen toggle, and devtools, respectively.

                                                  Symbol layer

                                                  This is the crown jewel of my keyboard’s configuration: an entire layer dedicated to the entry of symbols that are essential for computer programming. It’s the result of several hundreds of layout iterations over the last 9 years.

                                                  Diagram of the symbol layer.

                                                  👉 Red quotes. Green arrows. Blue groups. Purple flips. Yellow Vim.

                                                  Base layer affinity

                                                  Vim editor shortcuts

                                                  Adjacent key bigrams

                                                  Outer corner bigrams

                                                  These are easy to find because they’re on the outer corners of the keyboard.

                                                  Inward rolling bigrams

                                                  Outward rolling bigrams

                                                  Mouse layer

                                                  NOTE: Unlike QMK firmware, ZMK doesn’t support mouse keys yet… so treat this as a design concept of what’s coming in the near future!

                                                  Diagram of the mouse layer.

                                                  Movement keys are located centrally in the home block, resembling WASD keys, and mouse acceleration controls are poised for pinky finger access, so you can independently move the mouse pointer and also change its speed at the same time.

                                                  Mousewheel down/up keys are also placed on the home block, specifically on the same keys as J/K (down/up in Vim) on the base layer for muscle memory reuse.

                                                  System layer

                                                  Diagram of the system layer.

                                                  Keys for controlling RGB matrix settings line the central rows of home block. Keys for power and the traditional print->pause triplet line the thumb cluster.

                                                  Firmware

                                                  My keyboard’s entire firmware is available on GitHub and discussed on Discord.

                                                  Custom Defined Behaviors

                                                  Here is the relevant ZMK configuration snippet that is saved inside the “Custom Defined Behaviors” textbox in the Glove80 Layout Editor keymaps linked above:

                                                  //////////////////////////////////////////////////////////////////////
                                                  // NOTE: Use the `#define` settings below to customize this keymap! //
                                                  //////////////////////////////////////////////////////////////////////
                                                  // IMPORTANT: You need to set Firmware Version to "pr19.zephyr-3-2" //
                                                  // under Settings > Advanced Settings in the Glove80 Layout Editor  //
                                                  // if you want to use the `hold-trigger-on-release` feature in ZMK. //
                                                  //////////////////////////////////////////////////////////////////////
                                                  // CAUTION: PR19 firmware is not production quality; it has issues: //
                                                  // https://discord.com/channels/877392805654306816/1137025078979203142
                                                  //////////////////////////////////////////////////////////////////////
                                                  //
                                                  // Sunaku's Layout v22 featuring Engram(mer) layout and Miryoku system
                                                  // - https://sunaku.github.io/moergo-glove80-keyboard.html
                                                  // - https://discord.com/channels/877392805654306816/1111469812850380831
                                                  //
                                                  
                                                  behaviors {
                                                  
                                                      //////////////////////////////////////////////////////////////////
                                                      // Miryoku layers (thumb keys) and home row mods (non-thumb keys)
                                                      // - https://sunaku.github.io/home-row-mods.html
                                                      // - https://github.com/urob/zmk-config#timeless-homerow-mods
                                                      //////////////////////////////////////////////////////////////////
                                                      //
                                                      // TYPING_STREAK_TERM defines how long you need to wait (milliseconds)
                                                      // after typing before you can use home row mods again.  It prevents
                                                      // unintended activation of home row mods when you're actively typing.
                                                      //
                                                      #define TYPING_STREAK_TERM 160 // global-quick-tap-ms
                                                      //
                                                      // KEY_REPEATING_TERM defines how much time you have left (milliseconds)
                                                      // after tapping a key to hold it again in order to make it auto-repeat.
                                                      //
                                                      #define KEY_REPEATING_TERM 300 // "tap then hold" for key auto-repeat
                                                      //
                                                      // HOMEY_TAPPING_TERM defines how long you need to hold (milliseconds)
                                                      // home row mod keys in order to send their modifiers to the computer
                                                      // (i.e. "register" them) for mod-click mouse usage (e.g. Ctrl-Click).
                                                      //
                                                      #define HOMEY_TAPPING_TERM 260 // TAPPING_TERM + ALLOW_CROSSOVER_AFTER
                                                      //
                                                      // HOMEY_HOLDING_TYPE defines the flavor of ZMK hold-tap behavior to use
                                                      // for the pinky, ring, and middle fingers (which are assigned to Super,
                                                      // Alt, and Ctrl respectively in the Miryoku system) on home row keys.
                                                      //
                                                      #define HOMEY_HOLDING_TYPE "tap-preferred"
                                                      //
                                                      // INDEX_TAPPING_TERM defines how long you need to hold (milliseconds)
                                                      // index finger keys in order to send their modifiers to the computer
                                                      // (i.e. "register" them) for mod-click mouse usage (e.g. Shift-Click).
                                                      //
                                                      // CAUTION: You'll need to perform inward rolls from pinky->ring->middle
                                                      // fingers toward the index fingers when activating multiple modifiers
                                                      // because `hold-trigger-on-release` is disabled for the index fingers.
                                                      // Otherwise, you may be surprised that the index fingers' modifier is
                                                      // sent immediately without the rest of your multi-mod chord when you
                                                      // perform outward rolls from your index fingers toward your pinkies.
                                                      //
                                                      #define INDEX_TAPPING_TERM 180
                                                      //
                                                      // INDEX_HOLDING_TYPE defines the flavor of ZMK hold-tap behavior to use
                                                      // for index fingers (which Miryoku assigns to Shift) on home row keys.
                                                      //
                                                      // NOTE: The "tap-preferred" flavor of ZMK hold-tap for index finger keys
                                                      // allows faster activation of the Shift modifier (without having to wait
                                                      // for the modified key to be released as the "balanced" flavor requires).
                                                      // Typing streaks and the `hold-trigger-on-release` setting are disabled
                                                      // for the index fingers so as not to hinder their speed and dexterity.
                                                      //
                                                      #define INDEX_HOLDING_TYPE "tap-preferred"
                                                      //
                                                      // THUMB_TAPPING_TERM defines how long you need to hold (milliseconds)
                                                      // a thumb key to activate a layer.  Shorter holds are treated as taps.
                                                      //
                                                      #define THUMB_TAPPING_TERM 200
                                                      //
                                                      // THUMB_HOLDING_TYPE defines the flavor of ZMK hold-tap behavior to use
                                                      // for the thumbs (which are assigned to 6 layers in the Miryoku system).
                                                      //
                                                      // NOTE: The "balanced" flavor of ZMK hold-tap provides instant modifier
                                                      // activation for the symbol layer (if the tapped symbol key is released
                                                      // while the thumb layer key is still held down) for quicker programming.
                                                      //
                                                      #define THUMB_HOLDING_TYPE "balanced"
                                                      //
                                                      // Glove80 key positions index for positional hold-tap
                                                      // - https://discord.com/channels/877392805654306816/937645688244826154/1066713913351221248
                                                      // - https://media.discordapp.net/attachments/937645688244826154/1066713913133121556/image.png
                                                      //
                                                      // |------------------------|------------------------|
                                                      // | LEFT_HAND_KEYS         |        RIGHT_HAND_KEYS |
                                                      // |                        |                        |
                                                      // |  0  1  2  3  4         |          5  6  7  8  9 |
                                                      // | 10 11 12 13 14 15      |      16 17 18 19 20 21 |
                                                      // | 22 23 24 25 26 27      |      28 29 30 31 32 33 |
                                                      // | 34 35 36 37 38 39      |      40 41 42 43 44 45 |
                                                      // | 46 47 48 49 50 51      |      58 59 60 61 62 63 |
                                                      // | 64 65 66 67 68         |         75 76 77 78 79 |
                                                      // |                69 52   |   57 74                |
                                                      // |                 70 53  |  56 73                 |
                                                      // |                  71 54 | 55 72                  |
                                                      // |------------------------|------------------------|
                                                      //
                                                      #define LEFT_HAND_KEYS      \
                                                            0  1  2  3  4         \
                                                           10 11 12 13 14 15      \
                                                           22 23 24 25 26 27      \
                                                           34 35 36 37 38 39      \
                                                           46 47 48 49 50 51      \
                                                           64 65 66 67 68
                                                      #define RIGHT_HAND_KEYS     \
                                                                                             5  6  7  8  9 \
                                                                                         16 17 18 19 20 21 \
                                                                                         28 29 30 31 32 33 \
                                                                                         40 41 42 43 44 45 \
                                                                                         58 59 60 61 62 63 \
                                                                                            75 76 77 78 79
                                                      #define THUMB_KEYS          \
                                                                          69 52       57 74                \
                                                                           70 53     56 73                 \
                                                                            71 54   55 72
                                                      //
                                                      // Home row mod-tap keys for all except index fingers
                                                      //
                                                      homey_left: miryoku_home_row_mods_left_hand {
                                                          compatible = "zmk,behavior-hold-tap";
                                                          label = "HOME_ROW_MODS_LEFT_HAND";
                                                          flavor = HOMEY_HOLDING_TYPE;
                                                          hold-trigger-key-positions = <RIGHT_HAND_KEYS THUMB_KEYS>;
                                                          hold-trigger-on-release; // wait for other home row mods
                                                          tapping-term-ms = <HOMEY_TAPPING_TERM>;
                                                          quick-tap-ms = <TYPING_STREAK_TERM>;
                                                          global-quick-tap; // with typing streak
                                                          #binding-cells = <2>;
                                                          bindings = <&kp>, <&kp>;
                                                      };
                                                      homey_right: miryoku_home_row_mods_right_hand {
                                                          compatible = "zmk,behavior-hold-tap";
                                                          label = "HOME_ROW_MODS_RIGHT_HAND";
                                                          flavor = HOMEY_HOLDING_TYPE;
                                                          hold-trigger-key-positions = <LEFT_HAND_KEYS THUMB_KEYS>;
                                                          hold-trigger-on-release; // wait for other home row mods
                                                          tapping-term-ms = <HOMEY_TAPPING_TERM>;
                                                          quick-tap-ms = <TYPING_STREAK_TERM>;
                                                          global-quick-tap; // with typing streak
                                                          #binding-cells = <2>;
                                                          bindings = <&kp>, <&kp>;
                                                      };
                                                      //
                                                      // Special home row mod-tap keys for the index fingers
                                                      //
                                                      index_left: miryoku_home_row_mods_left_index_shift {
                                                          compatible = "zmk,behavior-hold-tap";
                                                          label = "HOME_ROW_MODS_LEFT_INDEX_SHIFT";
                                                          flavor = INDEX_HOLDING_TYPE;
                                                          hold-trigger-key-positions = <RIGHT_HAND_KEYS THUMB_KEYS>;
                                                          //hold-trigger-on-release; // don't wait for other mods
                                                          tapping-term-ms = <INDEX_TAPPING_TERM>;
                                                          quick-tap-ms = <KEY_REPEATING_TERM>; // enable repeat
                                                          //global-quick-tap; // no typing streak
                                                          #binding-cells = <2>;
                                                          bindings = <&kp>, <&kp>;
                                                      };
                                                      index_right: miryoku_home_row_mods_right_index_shift {
                                                          compatible = "zmk,behavior-hold-tap";
                                                          label = "HOME_ROW_MODS_RIGHT_INDEX_SHIFT";
                                                          flavor = INDEX_HOLDING_TYPE;
                                                          hold-trigger-key-positions = <LEFT_HAND_KEYS THUMB_KEYS>;
                                                          //hold-trigger-on-release; // don't wait for other mods
                                                          tapping-term-ms = <INDEX_TAPPING_TERM>;
                                                          quick-tap-ms = <KEY_REPEATING_TERM>; // enable repeat
                                                          //global-quick-tap; // no typing streak
                                                          #binding-cells = <2>;
                                                          bindings = <&kp>, <&kp>;
                                                      };
                                                      //
                                                      // Thumb cluster hold-tap keys for Miryoku layers
                                                      //
                                                      thumb: miryoku_thumb_layer {
                                                          compatible = "zmk,behavior-hold-tap";
                                                          label = "MIRYOKU_LAYER_TAP_WITH_REPEAT";
                                                          flavor = THUMB_HOLDING_TYPE;
                                                          tapping-term-ms = <THUMB_TAPPING_TERM>;
                                                          quick-tap-ms = <KEY_REPEATING_TERM>; // enable repeat
                                                          //global-quick-tap; // no typing streak
                                                          #binding-cells = <2>;
                                                          bindings = <&mo>, <&kp>;
                                                      };
                                                  
                                                      // Shift + LEFT_PARENTHESIS = LESS_THAN
                                                      parang_left: left_parenthesis_and_less_than {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "LEFT_PARENTHESIS_AND_LESS_THAN";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp LEFT_PARENTHESIS>, <&kp LESS_THAN>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                  
                                                      // Shift + RIGHT_PARENTHESIS = GREATER_THAN
                                                      parang_right: right_parenthesis_and_greater_than {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "RIGHT_PARENTHESIS_AND_GREATER_THAN";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp RIGHT_PARENTHESIS>, <&kp GREATER_THAN>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                  
                                                      // Shift + CapsWord = CapsLock
                                                      cappy: capsword_and_capslock {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "CAPSWORD_AND_CAPSLOCK";
                                                          #binding-cells = <0>;
                                                          bindings = <&caps_word>, <&kp CAPSLOCK>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                  
                                                      //
                                                      // CapsWord - ported from Pascal Getreuer's extension for QMK
                                                      // - https://zmk.dev/docs/behaviors/caps-word
                                                      // - https://getreuer.info/posts/keyboards/caps-word/index.html
                                                      //
                                                      behavior_caps_word {
                                                          continue-list = <UNDERSCORE MINUS BACKSPACE DELETE N1 N2 N3 N4 N5 N6 N7 N8 N9 N0>;
                                                      };
                                                  
                                                      //
                                                      // Custom shifted pairs for the Engram layout
                                                      // - https://engram.dev/
                                                      // - https://sunaku.github.io/engram-keyboard-layout.html
                                                      //
                                                      one: engram_one_and_pipe {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_ONE_AND_PIPE";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N1>, <&kp PIPE>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      two: engram_two_and_equal {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_TWO_AND_EQUAL";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N2>, <&kp EQUAL>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      three: engram_three_and_tilde {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_THREE_AND_TILDE";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N3>, <&kp TILDE>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      four: engram_four_and_plus {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_FOUR_AND_PLUS";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N4>, <&kp PLUS>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      five: engram_five_and_less_than {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_FIVE_AND_LESS_THAN";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N5>, <&kp LESS_THAN>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      six: engram_six_and_greater_than {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_SIX_AND_GREATER_THAN";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N6>, <&kp GREATER_THAN>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      seven: engram_seven_and_caret {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_SEVEN_AND_CARET";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N7>, <&kp CARET>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      eight: engram_eight_and_ampersand {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_EIGHT_AND_AMPERSAND";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N8>, <&kp AMPERSAND>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      nine: engram_nine_and_percent {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_NINE_AND_PERCENT";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N9>, <&kp PERCENT>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      zero: engram_zero_and_asterisk {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_ZERO_AND_ASTERISK";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp N0>, <&kp ASTERISK>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      apos: engram_apostrophe_and_left_parenthesis {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_APOSTROPHE_AND_LEFT_PARENTHESIS";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp APOSTROPHE>, <&kp LEFT_PARENTHESIS>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      dquote: engram_double_quotes_and_right_parenthesis {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_DOUBLE_QUOTES_AND_RIGHT_PARENTHESIS";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp DOUBLE_QUOTES>, <&kp RIGHT_PARENTHESIS>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      comma: engram_comma_and_semicolon {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_COMMA_AND_SEMICOLON";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp COMMA>, <&kp SEMICOLON>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      period: engram_period_and_colon {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_PERIOD_AND_COLON";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp PERIOD>, <&kp COLON>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      question: engram_question_and_exclamation {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_QUESTION_AND_EXCLAMATION";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp QUESTION>, <&kp EXCLAMATION>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      hash: engram_hash_and_dollar {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_HASH_AND_DOLLAR";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp HASH>, <&kp DOLLAR>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      at: engram_at_and_grave {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_AT_AND_GRAVE";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp AT>, <&kp GRAVE>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      slash: engram_slash_and_backslash {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "ENGRAM_SLASH_AND_BACKSLASH";
                                                          #binding-cells = <0>;
                                                          bindings = <&kp SLASH>, <&kp BACKSLASH>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                  
                                                  };
                                                  
                                                  macros {
                                                  
                                                      //////////////////////////////////////////////////////////////////
                                                      // Approximation of Pascal Getreuer's Select Word macro from QMK
                                                      // - https://getreuer.info/posts/keyboards/select-word/index.html
                                                      //////////////////////////////////////////////////////////////////
                                                      //
                                                      // SELECT_WORD_DELAY defines how long the macro waits (milliseconds)
                                                      // after moving the cursor before it selects a word.  A larger delay
                                                      // may allow the macro to move to the next word upon each invocation.
                                                      //
                                                      #define SELECT_WORD_DELAY 10
                                                  
                                                      select_word_right: select_word_right {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "SELECT_WORD_RIGHT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LC(RIGHT)>
                                                          , <&macro_wait_time SELECT_WORD_DELAY> // let cursor move to the next word!
                                                          , <&macro_tap &kp LC(LEFT) &kp LC(LS(RIGHT))>
                                                          ;
                                                      };
                                                      extend_word_right: extend_word_right {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "EXTEND_WORD_RIGHT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LC(LS(RIGHT))>
                                                          ;
                                                      };
                                                      select_line_right: select_line_right {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "SELECT_LINE_RIGHT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp HOME &kp LS(END)>
                                                          ;
                                                      };
                                                      extend_line_right: extend_line_right {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "EXTEND_LINE_RIGHT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LS(DOWN) &kp LS(END)>
                                                          ;
                                                      };
                                                      select_word_left: select_word_left {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "SELECT_WORD_LEFT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LC(LEFT)>
                                                          , <&macro_wait_time SELECT_WORD_DELAY> // let cursor move to the next word!
                                                          , <&macro_tap &kp LC(RIGHT) &kp LC(LS(LEFT))>
                                                          ;
                                                      };
                                                      extend_word_left: extend_word_left {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "EXTEND_WORD_LEFT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LC(LS(LEFT))>
                                                          ;
                                                      };
                                                      select_line_left: select_line_left {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "SELECT_LINE_LEFT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp END &kp LS(HOME)>
                                                          ;
                                                      };
                                                      extend_line_left: extend_line_left {
                                                          compatible = "zmk,behavior-macro";
                                                          label = "EXTEND_LINE_LEFT";
                                                          #binding-cells = <0>;
                                                          tap-ms = <0>;
                                                          wait-ms = <0>;
                                                          bindings
                                                          = <&macro_tap &kp LS(UP) &kp LS(HOME)>
                                                          ;
                                                      };
                                                      select_word: select_word {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "SELECT_WORD";
                                                          #binding-cells = <0>;
                                                          bindings = <&select_word_right>, <&select_word_left>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      extend_word: extend_word {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "EXTEND_WORD";
                                                          #binding-cells = <0>;
                                                          bindings = <&extend_word_right>, <&extend_word_left>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      select_line: select_line {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "SELECT_LINE";
                                                          #binding-cells = <0>;
                                                          bindings = <&select_line_right>, <&select_line_left>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                      extend_line: extend_line {
                                                          compatible = "zmk,behavior-mod-morph";
                                                          label = "EXTEND_LINE";
                                                          #binding-cells = <0>;
                                                          bindings = <&extend_line_right>, <&extend_line_left>;
                                                          mods = <(MOD_LSFT|MOD_RSFT)>;
                                                      };
                                                  
                                                  };
                                                  

                                                  Mirroring horizontally

                                                  To horizontally mirror a keymap’s physical layout in the Glove80 Layout Editor:

                                                  1. Activate the “Enable local config” option in the Glove80 Layout Editor’s settings panel under the “Experimental Settings” section.
                                                  2. Return to the editor and export your keymap to a JSON file by clicking on the “Download” button.
                                                  3. Paste the contents of the exported JSON file into your Web browser’s JavaScript console (found in the “Developer Tools” panel, typically activated by pressing Ctrl+F12) at the location indicated by the comment in the first line of the following code snippet.
                                                  4. Right-click the result, copy to clipboard, save to file, and upload into the Glove80 Layout Editor. 🫰 Presto! Everything should be mirrored now.
                                                  layout = /* paste contents of exported JSON file here */;
                                                  mirroring_transformation = {
                                                  //
                                                  // |------------------------|------------------------|
                                                  // | LEFT_HAND_KEYS         |        RIGHT_HAND_KEYS |
                                                  // |                        |                        |
                                                  // |  0  1  2  3  4         |          5  6  7  8  9 |
                                                  // | 10 11 12 13 14 15      |      16 17 18 19 20 21 |
                                                  // | 22 23 24 25 26 27      |      28 29 30 31 32 33 |
                                                  // | 34 35 36 37 38 39      |      40 41 42 43 44 45 |
                                                  // | 46 47 48 49 50 51      |      58 59 60 61 62 63 |
                                                  // | 64 65 66 67 68         |         75 76 77 78 79 |
                                                  // |                69 52   |   57 74                |
                                                  // |                 70 53  |  56 73                 |
                                                  // |                  71 54 | 55 72                  |
                                                  // |------------------------|------------------------|
                                                  // | LEFT_HAND_MIRRORED     |    RIGHT_HAND_MIRRORED |
                                                  // |                        |                        |
                                                  // |  9  8  7  6  5         |          4  3  2  1  0 |
                                                  // | 21 20 19 18 17 16      |      15 14 13 12 11 10 |
                                                  // | 33 32 31 30 29 28      |      27 26 25 24 23 22 |
                                                  // | 45 44 43 42 41 40      |      39 38 37 36 35 34 |
                                                  // | 63 62 61 60 59 58      |      51 50 49 48 47 46 |
                                                  // | 79 78 77 76 75         |         68 67 66 65 64 |
                                                  // |                74 57   |   52 69                |
                                                  // |                 73 56  |  53 70                 |
                                                  // |                  71 54 | 55 72                  |
                                                  // |------------------------|------------------------|
                                                  //
                                                     0: 9,  1: 8,  2: 7,  3: 6,  4: 5,                              5: 4,  6: 3,  7: 2,  8: 1,  9: 0,
                                                    10:21, 11:20, 12:19, 13:18, 14:17, 15:16,               16:15, 17:14, 18:13, 19:12, 20:11, 21:10,
                                                    22:33, 23:32, 24:31, 25:30, 26:29, 27:28,               28:27, 29:26, 30:25, 31:24, 32:23, 33:22,
                                                    34:45, 35:44, 36:43, 37:42, 38:41, 39:40,               40:39, 41:38, 42:37, 43:36, 44:35, 45:34,
                                                    46:63, 47:62, 48:61, 49:60, 50:59, 51:58,               58:51, 59:50, 60:49, 61:48, 62:47, 63:46,
                                                    64:79, 65:78, 66:77, 67:76, 68:75,                             75:68, 76:67, 77:66, 78:65, 79:64,
                                                                                       69:74, 52:57, 57:52, 74:69,
                                                                                       70:73, 53:56, 56:53, 73:70,
                                                                                       71:72, 54:55, 55:54, 72:71,
                                                  };
                                                  mirrored_layers = layout["layers"].map((layer) => {
                                                    return layer.map((key,pos) => {
                                                      return layer[mirroring_transformation[pos]];
                                                    });
                                                  });
                                                  mirrored_layout = Object.assign({}, layout);
                                                  mirrored_layout["layers"] = mirrored_layers;
                                                  mirrored_layout; /* dumps to the console for copying */
                                                  

                                                  Updates