~ruther/qmk_firmware

bb8e3796a7902eac8a7d47d5c6f514e50e7658b8 — Tony Zorman 1 year, 11 months ago d461090
[Keymap] Add slotThe keyboardio/atreus keymap (#21274)

A keyboards/keyboardio/atreus/keymaps/slotthe/autocorrect_data.h => keyboards/keyboardio/atreus/keymaps/slotthe/autocorrect_data.h +44 -0
@@ 0,0 1,44 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later

/*******************************************************************************
  88888888888 888      d8b                .d888 d8b 888               d8b
      888     888      Y8P               d88P"  Y8P 888               Y8P
      888     888                        888        888
      888     88888b.  888 .d8888b       888888 888 888  .d88b.       888 .d8888b
      888     888 "88b 888 88K           888    888 888 d8P  Y8b      888 88K
      888     888  888 888 "Y8888b.      888    888 888 88888888      888 "Y8888b.
      888     888  888 888      X88      888    888 888 Y8b.          888      X88
      888     888  888 888  88888P'      888    888 888  "Y8888       888  88888P'
                                                        888                 888
                                                        888                 888
                                                        888                 888
     .d88b.   .d88b.  88888b.   .d88b.  888d888 8888b.  888888 .d88b.   .d88888
    d88P"88b d8P  Y8b 888 "88b d8P  Y8b 888P"      "88b 888   d8P  Y8b d88" 888
    888  888 88888888 888  888 88888888 888    .d888888 888   88888888 888  888
    Y88b 888 Y8b.     888  888 Y8b.     888    888  888 Y88b. Y8b.     Y88b 888
     "Y88888  "Y8888  888  888  "Y8888  888    "Y888888  "Y888 "Y8888   "Y88888
         888
    Y8b d88P
     "Y88P"
*******************************************************************************/

#pragma once

// Autocorrection dictionary (4 entries):
//   :alot      -> a lot
//   accesories -> accessories
//   accomodate -> accommodate
//   alledge    -> allege

#define AUTOCORRECT_MIN_LENGTH 5 // ":alot"
#define AUTOCORRECT_MAX_LENGTH 10 // "accesories"
#define DICTIONARY_SIZE 73

static const uint8_t autocorrect_data[DICTIONARY_SIZE] PROGMEM = {
    0x48, 0x0A, 0x00, 0x16, 0x2C, 0x00, 0x17, 0x3E, 0x00, 0x00, 0x4A, 0x11, 0x00, 0x17, 0x1B, 0x00,
    0x00, 0x07, 0x08, 0x0F, 0x0F, 0x04, 0x00, 0x82, 0x67, 0x65, 0x00, 0x04, 0x07, 0x12, 0x10, 0x12,
    0x06, 0x06, 0x04, 0x00, 0x84, 0x6D, 0x6F, 0x64, 0x61, 0x74, 0x65, 0x00, 0x08, 0x0C, 0x15, 0x12,
    0x16, 0x08, 0x06, 0x06, 0x04, 0x00, 0x84, 0x73, 0x6F, 0x72, 0x69, 0x65, 0x73, 0x00, 0x12, 0x0F,
    0x04, 0x2C, 0x00, 0x82, 0x20, 0x6C, 0x6F, 0x74, 0x00
};

A keyboards/keyboardio/atreus/keymaps/slotthe/config.h => keyboards/keyboardio/atreus/keymaps/slotthe/config.h +19 -0
@@ 0,0 1,19 @@
/* © 2023  Tony Zorman <soliditsallgood@mailbox.org> (@slotThe)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

#define BOTH_SHIFTS_TURNS_ON_CAPS_WORD
#define TAPPING_TERM 175
#define HOLD_ON_OTHER_KEY_PRESS

A keyboards/keyboardio/atreus/keymaps/slotthe/keymap.c => keyboards/keyboardio/atreus/keymaps/slotthe/keymap.c +328 -0
@@ 0,0 1,328 @@
/* © 2023  Tony Zorman <soliditsallgood@mailbox.org> (@slotThe)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include QMK_KEYBOARD_H

// NOTE: `M-x occur RET /// RET' gives a good overview.

/// General macros

#define LSPR_SC  LGUI_T(KC_SCLN)
#define LALT_BR  LALT_T(KC_LBRC)
#define LSFT_INS LSFT(KC_INS)
#define OSMSFT   OSM(MOD_LSFT)
#define Z_SFT    LSFT_T(KC_Z)
#define ZE_SFT   LSFT_T(KC_0)
#define SL_SFT   RSFT_T(KC_SLSH)
#define RETSPR   LGUI_T(KC_ENT)

/// Tap dance declarations

// So far, tap dances do different things on
//
//   - a single press,
//   - a double press,
//   - when held,
//
// so expect this many keys as comments.
enum tap_dances {
  ALT_BR,  // [ ] lalt  (also works shifted, which gets us { and } for free)
  CTL_PR,  // ( ) lctl
  SFT_CI,  // ^ ^ lsft  (working around LSFT_T not being able to output shifted keys)
  SFT_EX,  // ! ! lsft  (ditto)
};

#define CTLPAR TD(CTL_PR)
#define ALTBRC TD(ALT_BR)
#define SFTCRC TD(SFT_CI)
#define SFTEXL TD(SFT_EX)

/// Macro declarations

enum custom_keycodes {
  // ->              <-    =<<   >>=   <*>  <*    *>    <$>   <&>   <|>   =>     ::
  RARR = SAFE_RANGE, LARR, LBND, RBND, APP, RAPP, LAPP, FMAP, PAMF, AALT, IMPLS, DCOL,
};

/// Key overrides

const key_override_t **key_overrides = (const key_override_t *[]){
  &ko_make_basic(MOD_MASK_SHIFT, KC_BSPC, KC_DEL), // S-BSP ≡ DEL
  // Emacs got me used to these, so let's convince other programs that
  // we are in fact sending the correct keys.
  &ko_make_basic(MOD_MASK_CTRL, KC_I, KC_TAB),     // C-i ≡ Tab
  &ko_make_basic(MOD_MASK_CTRL, KC_M, KC_ENT),     // C-m ≡ Return
  NULL // Null terminate the array of overrides
};

/// Layers

enum layer_names { _COLEMAK_DH, _LOWER, _RAISE, _ADJUST };

#define LOWER    MO(_LOWER)
#define RAISE    MO(_RAISE)
#define ADJUST   MO(_ADJUST)
#define D_RAISE  LT(_RAISE, KC_DOT)

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  /* Colemak base layer
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |  Q  |  W  |  F  |  P  |  B  |           |  J  |  L  |  U  |  Y  | ;+S |
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |  A  |  R  |  S  |  T  |  G  |           |  M  |  N  |  E  |  I  |  O  |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     | S+Z |  X  |  C  |  D  |  V  | ARP | REP |  K  |  H  |  ,  |  .  | S+/ |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     | ESC | TAB | SPR | L1  | SPC | A[] | BSC | C() | L2  |  -  |  '  | RET |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
  */
  [_COLEMAK_DH] = LAYOUT(
    KC_Q,    KC_W,    KC_F,    KC_P,    KC_B,                      KC_J,    KC_L,    KC_U,    KC_Y,    LSPR_SC,
    KC_A,    KC_R,    KC_S,    KC_T,    KC_G,                      KC_M,    KC_N,    KC_E,    KC_I,    KC_O,
    Z_SFT,   KC_X,    KC_C,    KC_D,    KC_V,    QK_AREP, QK_REP,  KC_K,    KC_H,    KC_COMM, D_RAISE, SL_SFT,
    KC_ESC,  KC_TAB,  KC_LGUI, LOWER,   KC_SPC,  ALTBRC,  KC_BSPC, CTLPAR,  RAISE,   KC_MINS, KC_QUOT, KC_ENT),

  /* Layer 1 (LOWER)
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-------.
     |  &  | *>  | >>= | <&> |     |           |  =  |  +  |  *  |  -  | RET+M |
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-------.
     | ::  | =>  | =<< | <|> |  @  |           | LFT |  UP | DWN | RGT |   \   |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.
     | !+S | <*  | <*> | <$> | <-  |     | MEN |  -> |  $  |  #  |  %  |  ^+S  |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.
     |     |     |     |     |     |     |     |     | L3  | ALT |     |  S-I  |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.
  */
  [_LOWER] = LAYOUT(
    KC_AMPR, RAPP,    RBND,    PAMF,    _______,                   KC_EQL,  KC_PLUS, KC_ASTR, KC_MINS, RETSPR,
    DCOL,    IMPLS,   LBND,    AALT,    KC_AT,                     KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT, KC_BSLS,
    SFTEXL,  LAPP,    APP,     FMAP,    LARR,    _______, KC_APP,  RARR,    KC_DLR,  KC_HASH, KC_PERC, SFTCRC,
    _______, _______, _______, _______, _______, _______, _______, _______, ADJUST,  KC_LALT, _______, LSFT_INS),

  /* Layer 2 (RAISE)
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |     |  7  |  8  |  9  |     |           |     |  +  |  *  |  -  |     |
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |  :  |  4  |  5  |  6  |  =  |           |  &  |  `  |  _  |  '  |  "  |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     | 0+S |  1  |  2  |  3  |     |     |     |     |  !  |  #  |  %  | ^+S |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     |     |     |     | L3  |     |     |     |     |     |     |     |     |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
  */
  [_RAISE] = LAYOUT(
    KC_DOT,  KC_7,    KC_8,    KC_9,    _______,                   _______, KC_PLUS, KC_ASTR, KC_MINS, _______,
    KC_COLN, KC_4,    KC_5,    KC_6,    KC_EQL,                    KC_AMPR, KC_GRV,  KC_UNDS, KC_QUOT, KC_DQT,
    ZE_SFT,  KC_1,    KC_2,    KC_3,    _______, _______, _______, _______, KC_EXLM, KC_HASH, KC_PERC, SFTCRC,
    _______, _______, _______, ADJUST,  _______, _______, _______, _______, _______, _______, _______, _______),

  /* Layer 3 (ADJUST)
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |     |     |     |     |     |           |     | F7  | F8  | F9  | F10 |
     .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
     |     |     |     |     |     |           |     | F4  | F5  | F6  | F11 |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     |     |     |     |     |     |     |     |     | F1  | F2  | F3  | F12 |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
     |     |     |     |     |     |     |     |     |     |     |     |     |
     .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
  */
  [_ADJUST] = LAYOUT(
    _______, _______, _______, _______, AC_TOGG,                   _______, KC_F7,   KC_F8,   KC_F9,   KC_F10,
    _______, _______, _______, _______, _______,                   _______, KC_F4,   KC_F5,   KC_F6,   KC_F11,
    _______, _______, _______, _______, _______, _______, _______, _______, KC_F1,   KC_F2,   KC_F3,   KC_F12,
    _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______)
};

/// Macro definitions

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  switch (keycode) {
  case RARR:
    if (record->event.pressed) SEND_STRING("->");  break;
  case LARR:
    if (record->event.pressed) SEND_STRING("<-");  break;
  case LBND:
    if (record->event.pressed) SEND_STRING("=<<"); break;
  case RBND:
    if (record->event.pressed) SEND_STRING(">>="); break;
  case APP:
    if (record->event.pressed) SEND_STRING("<*>"); break;
  case RAPP:
    if (record->event.pressed) SEND_STRING("*>");  break;
  case LAPP:
    if (record->event.pressed) SEND_STRING("<*");  break;
  case FMAP:
    if (record->event.pressed) SEND_STRING("<$>"); break;
  case PAMF:
    if (record->event.pressed) SEND_STRING("<&>"); break;
  case AALT:
    if (record->event.pressed) SEND_STRING("<|>"); break;
  case IMPLS:
    if (record->event.pressed) SEND_STRING("=>");  break;
  case DCOL:
    if (record->event.pressed) SEND_STRING("::");  break;
  }
  return true;
};

//// Tap dance definitions

// Heavily inspired by:
//
//     https://docs.qmk.fm/?ref=blog.splitkb.com#/feature_tap_dance?id=example-4

typedef enum {
  TD_NONE,
  TD_UNKNOWN,
  TD_SINGLE_TAP,
  TD_SINGLE_HOLD,
  TD_DOUBLE_TAP,
} td_state_t;

typedef struct {
  bool is_press_action;
  td_state_t state;
} td_tap_t;

// Return an integer that corresponds to what kind of tap dance should
// be executed.
//
// Interrupted: If the state of a dance is "interrupted", that means
//  that another key has been hit under the tapping term.
//
// Pressed: Whether or not the key is still being pressed. If this value
//  is true, that means the tapping term has ended, but the key is still
//  being pressed down. This generally means the key is being "held".
td_state_t cur_dance(tap_dance_state_t *state) {
  if (state->count == 1) {
    if (state->pressed)         return TD_SINGLE_HOLD;
    else                        return TD_SINGLE_TAP;
  } else if (state->count == 2) return TD_DOUBLE_TAP;
  else                          return TD_UNKNOWN;
}

//// ALT_BR

static td_tap_t alt_br_state = {
  .is_press_action = true,
  .state = TD_NONE
};

void lalt_br_finished(tap_dance_state_t *state, void *user_data) {
  alt_br_state.state = cur_dance(state);
  switch (alt_br_state.state) {
  case TD_SINGLE_TAP:  register_code(KC_LBRC); break;
  case TD_SINGLE_HOLD: register_code(KC_LALT); break;
  case TD_DOUBLE_TAP:  register_code(KC_RBRC); break;
  default:             break;
  }
}

void lalt_br_reset(tap_dance_state_t *state, void *user_data) {
  switch (alt_br_state.state) {
  case TD_SINGLE_TAP:  unregister_code(KC_LBRC); break;
  case TD_SINGLE_HOLD: unregister_code(KC_LALT); break;
  case TD_DOUBLE_TAP:  unregister_code(KC_RBRC); break;
  default:             break;
  }
  alt_br_state.state = TD_NONE;
}

//// LCTL_PR

static td_tap_t lctl_pr_state = {
  .is_press_action = true,
  .state = TD_NONE
};

void lctl_pr_finished(tap_dance_state_t *state, void *user_data) {
  lctl_pr_state.state = cur_dance(state);
  switch (lctl_pr_state.state) {
  case TD_SINGLE_TAP:  register_code16(KC_LPRN); break;
  case TD_SINGLE_HOLD: register_code(KC_LCTL);   break;
  case TD_DOUBLE_TAP:  register_code16(KC_RPRN); break;
  default:             break;
  }
}

void lctl_pr_reset(tap_dance_state_t *state, void *user_data) {
  switch (lctl_pr_state.state) {
  case TD_SINGLE_TAP:  unregister_code16(KC_LPRN); break;
  case TD_SINGLE_HOLD: unregister_code(KC_LCTL);   break;
  case TD_DOUBLE_TAP:  unregister_code16(KC_RPRN); break;
  default:             break;
  }
  lctl_pr_state.state = TD_NONE;
}

//// SFT_CI

static td_tap_t lsft_ci_state = {
  .is_press_action = true,
  .state = TD_NONE
};

void lsft_ci_finished(tap_dance_state_t *state, void *user_data) {
  lsft_ci_state.state = cur_dance(state);
  switch (lsft_ci_state.state) {
  case TD_SINGLE_TAP:  register_code16(KC_CIRC); break;
  case TD_SINGLE_HOLD: register_code(KC_LSFT);   break;
  default:             break;
  }
}

void lsft_ci_reset(tap_dance_state_t *state, void *user_data) {
  switch (lsft_ci_state.state) {
  case TD_SINGLE_TAP:  unregister_code16(KC_CIRC); break;
  case TD_SINGLE_HOLD: unregister_code(KC_LSFT);   break;
  default:             break;
  }
  lsft_ci_state.state = TD_NONE;
}

//// SFT_EX

static td_tap_t lsft_ex_state = {
  .is_press_action = true,
  .state = TD_NONE
};

void lsft_ex_finished(tap_dance_state_t *state, void *user_data) {
  lsft_ex_state.state = cur_dance(state);
  switch (lsft_ex_state.state) {
  case TD_SINGLE_TAP:  register_code16(KC_EXLM); break;
  case TD_SINGLE_HOLD: register_code(KC_LSFT);   break;
  default:             break;
  }
}

void lsft_ex_reset(tap_dance_state_t *state, void *user_data) {
  switch (lsft_ex_state.state) {
  case TD_SINGLE_TAP:  unregister_code16(KC_EXLM); break;
  case TD_SINGLE_HOLD: unregister_code(KC_LSFT);   break;
  default:             break;
  }
  lsft_ex_state.state = TD_NONE;
}

//// Actually define the tap-dance actions

tap_dance_action_t tap_dance_actions[] = {
  [ALT_BR] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lalt_br_finished, lalt_br_reset),
  [CTL_PR] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lctl_pr_finished, lctl_pr_reset),
  [SFT_CI] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lsft_ci_finished, lsft_ci_reset),
  [SFT_EX] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, lsft_ex_finished, lsft_ex_reset),
};

A keyboards/keyboardio/atreus/keymaps/slotthe/readme.md => keyboards/keyboardio/atreus/keymaps/slotthe/readme.md +251 -0
@@ 0,0 1,251 @@
# SlotThe's Keyboardio Atreus Keymap

Note: the following is (a relevant and shortened) excerpt from [this
rewiev](https://tony-zorman.com/posts/atreus-review.html) of the
keyboard itself. See there for, e.g., some thoughts about modifier
placement.

## Base layer

    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.------.
    |  Q  |  W  |  F  |  P  |  B  |           |  J  |  L  |  U  |  Y  | M4+; |
    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.------.
    |  A  |  R  |  S  |  T  |  G  |           |  M  |  N  |  E  |  I  |  O   |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.------.
    | S+Z |  X  |  C  |  D  |  V  | ARP | REP |  K  |  H  |  ,  |  .  | S+/  |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.------.
    | ESC | TAB | M4  | L1  | SPC | A[] | BSC | C() | L2  |  -  |  '  | RET  |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.------.

I use [Colemak Mod-DH][colemak-dh] as my layout, so this takes up most of the base of the keyboard.

Perhaps strikingly, I opted for not putting Shift on the thumb,
but recreating the "ordinary" one-on-each-side setup from the good old typewriter days.
While I already have a key to access the `LOWER` (L1) layer with my left thumb,
I had to sacrifice Shift so I could fit a key to the `RAISE` (L2) layer on the right thumb.
This also jumps to the `ADJUST` (L3) layer when both `LOWER` and `RAISE` are held at the same time.
I will gladly trade two layers for one Shift key.

One of the most basic things—besides having layers—that one can do with QMK is [mod-taps][qmk:mod-tap].
These are keys that act as modifiers when held, and as "ordinary" keys when pressed.
For example, all of the `S+«key»` keys emit Shift when held and `«key»` when pressed.
There is a slight delay between pressing the key and the press registering,
since we have to wait for a possible tap,
which keeps me from using modifiers on the home-row, as some people like to do.
Likewise, the `M4+;` key acts as Super when held and as `;` when pressed.
At this point, it is actually my main way to press the Super key,
even though I don't find the real `M4` key particularly hard to hit with my thumb.
Sometimes these things just happen,
I suppose,
though it may help that I press both outer keys of the top row (that is, `q` and `;`) with my ring finger
instead of my pinky.

The `A[]` and `C()` keys are utilising [tap dances][qmk:tap-dance],
in order to do even more.
Tap dances are very similar to mod-taps,
only in addition to just differentiating between a "pressed" and a "held" state,
QMK now also keeps track of *how often* a key has been tapped.
So far, [my setup][qmk:slotthe:tapdances] here is quite basic;
I only check whether a key was pressed once, twice, or is being held.
This allows me to not need extra keys for parentheses,
as they can fit on the modifier keys:

  - `A[]`: Alt when held, `[` when pressed once, and `]` when pressed twice.
    This one is especially neat, since tap dances play well with other modifiers,
    so pressing `S-M1` once will result in `{` and pressing it twice gives `}`.

  - `C()`: Control when held, `(` when pressed once, and `)` when pressed twice.

I don't mind having the extra indirection for the respective closed delimiter,
as [paredit][emacs:paredit],
[puni][emacs:puni],
`electric-pair-mode`,
or a different package of choice usually takes care of inserting it.

The `REP` and `AREP` keys make use of the [Repeat Key][qmk:repeat-key] functionality;
basically, `REP` executes the key chord that was last pressed.
On the other hand,
`AREP` is an alternative, configurable, of "repeating" things;
by default, it turns some directional movements
around—e.g., `M-f` becomes `M-b`—but
it can be made to pretty much input anything one wants.

## Layer 1

    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-------.
    |  &  | *>  | >>= | <&> |     |           |  =  |  +  |  *  |  -  | M4+RT |
    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-------.
    | ::  | =>  | =<< | <|> |  @  |           | LFT |  UP | DWN | RGT |   \   |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.
    | S+! | <*  | <*> | <$> | <-  |     | MEN |  -> |  $  |  #  |  %  |  S+^  |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.
    |     |     |     |     |     |     |     |     | L3  | ALT |     | S-Ins |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-------.

Guess which programming language I like based on this layer's [macros][qmk:macros] :).

Crucially, keys that were "Shift when held,
*something* when pressed" on the base layer retain the Shift part of that functionality.
This is used for the commutativity of the modifier
keys—i.e., it does not matter whether I press `S-L1-«key»` or `L1-S-«key»`—which
would otherwise drive me insane.
The same goes for all fall-through keys:
keys that appear blank in the above layout.
These aren't blocked or anything,
just no new functionality is added
so the key falls back to what's on the next lowest layer.
In plain terms,
the key to the left of `L3` will still be Control,
as I can comfortably press that while holding down something with my left hand.
The same can't be said for the Alt key,
which is on the left hand by default,
so a separate binding for it has to be created on the right hand.
Thus,
as the two don't commute,
key chords involving the LOWER layer and Alt are to be avoided if possible.

The `S-Ins` key is not some sort of tap,
but actually just emits a Shift-Insert,
which can be used to paste stuff from the [X11 primary selection][x11:clipboard].

## Layer 2

    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
    |     |  7  |  8  |  9  |     |           |     |  +  |  *  |  -  |     |
    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
    |  :  |  4  |  5  |  6  |  =  |           |     |  `  |  _  |  '  |  "  |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
    | S+0 |  1  |  2  |  3  |     |     |     |     |     |  #  |  %  | S+^ |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
    |     |     |     | L3  |     |     |     |     |     |     |     |     |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.

A relatively unspectacular layer,
RAISE is mainly used for numbers,
and number adjacent things.
Some symbols related to this,
like `=`, `+`, `*`, and `-`,
are replicated from the LOWER layer.
This is due to the above mentioned issues of inserting arithmetic.
This layer also features \` and `'` quite prominently,
as these are important for [CDLaTeX].
Plus, putting `'` and `"` on this layer circumvents the difficult to hit key on the base layer.

## Layer 3

    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
    |     |     |     |     |     |           |     | F7  | F8  | F9  | F10 |
    .-----.-----.-----.-----.-----.           .-----.-----.-----.-----.-----.
    |     |     |     |     |     |           |     | F4  | F5  | F6  | F11 |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
    |     |     |     |     |     |     |     |     | F1  | F2  | F3  | F12 |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.
    |     |     |     |     |     |     |     |     |     |     |     |     |
    .-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.-----.

So far, only the seldom used F-keys are present here.
As should be obvious, this is the least developed layer,
and also the one that'll probably change the most in the future.
Currently, I'm thinking of putting some XMonad specific bindings on here,
which could even to free up the Super key to be used inside of Emacs
for certain things—that would certainly be a worthwhile experiment.
Other thoughts include things like volume and brightness controls,
although this is less critical since my laptop keyboard is never far away.

## Other features

There are some features that aren't necessarily reflected in the keys themselves,
yet are quite essential for day-to-day use.
The TL;DR can be found in [rules.mk][./rules.mk].

### [Key overrides][qmk:key-overrides]

Quoting from the documentation

> Key overrides allow you to override modifier-key combinations to send a different modifier-key combination
> or perform completely custom actions.

Some keys on the keyboard are quite hard to hit.
On the default layout,
one of these turns out to be the Tab key,
which is nonetheless important in a lot of situations.
Conveniently, Emacs interprets `C-i` as Tab, so there is less need to actually hit the "real" key.
However, not all programs are quite so understanding—or old, I guess.
With key overrides, one can send a real `TAB` whenever `C-i` is pressed;
no special convention on how to interpret certain key chords required!
I also rebound `C-m` to `RET` (with the same justification), and `S-BSP` to `DEL`.

This is one of those features that I didn't know I needed,
yet now couldn't live without anymore.
I'm definitely looking forward to discovering new and interesting ways of using this!

### [Autocorrect][qmk:autocorrect]

This is a quaint little feature: auto-correct inside of your keyboard's firmware!
I promise that it's not as bad as it sounds.
It does not work automatically, thankfully, but is based off a given list of replacements.
For example,

    widht -> width

would fire anytime one writes `widht`, which then gets replaced by `width`.
This is based on (a trie of) the most recently pressed keys,
so whenever one actually wants to write `widht`
all that's needed is pressing, for example, any modifier during the insertion.

As I've really just been trying this out for a laugh, my current word list is quite short:

    :alot       ->  a lot
    accesories  ->  accessories
    accomodate  ->  accommodate
    alledge     ->  allege

In general,
I think the solution to stop misspelling a word is not to remap key sequences on the firmware level,
but to—you know—learn how to spell that word.
Still,
I can imagine at least one or two use-cases where something like this could be useful,
so I figured it might be nice to make people aware of this features' existence.

In addition—as I've found out on three separate occasions so far—using the words "auto-correct, but in firmware"
makes people stare in utter disbelief and/or disgust at your keyboard.
That alone makes this feature worth it.

### [Caps Word][qmk:caps-word]

Caps Word is a clever alternative to Caps Lock,
which I enable by pressing both Shift keys together.
After that,
all of the letter keys are shifted,
and `-` becomes `_`
until a different key (excluding common sense ones like backspace) is pressed.
This is very useful for, e.g.,
writing long constants,
as these tend to have capital names separated with underscores:
writing `BOTH_SHIFTS_TURNS_ON_CAPS_WORD` has never been easier!

One thing to note is that,
while layer switching works just fine in "Caps Word mode",
the [Tri Layer][qmk:tri-layer] feature does not seem to play nicely with it;
i.e., the mode gets disabled when switching to these layers.
This is also the reason why I have an explicit LOWER, RAISE, and ADJUST setup,
instead of just using Tri Layer.
One could fiddle with the `caps_word_press_user` callback,
but it seemed much easier to just create one additional layer toggle instead.
I haven't looked at how hard it would be to hack this into Caps Word,
so maybe this is a future pull request.

[CDLaTeX]: https://github.com/cdominik/cdlatex
[colemak-dh]: https://colemakmods.github.io/mod-dh/
[emacs:paredit]: https://paredit.org/
[emacs:puni]: https://github.com/AmaiKinono/puni
[qmk:autocorrect]: https://docs.qmk.fm/#/feature_autocorrect
[qmk:caps-word]: https://docs.qmk.fm/#/feature_caps_word
[qmk:key-overrides]: https://docs.qmk.fm/#/feature_key_overrides
[qmk:macros]: https://docs.qmk.fm/#/feature_macros
[qmk:mod-tap]: https://docs.qmk.fm/#/mod_tap
[qmk:repeat-key]: https://docs.qmk.fm/#/feature_repeat_key
[qmk:slotthe:tapdances]: https://github.com/slotThe/qmk_firmware/blob/keyboardio/atreus/slotThe/keyboards/keyboardio/atreus/keymaps/slotThe/keymap.c#L187
[qmk:tap-dance]: https://docs.qmk.fm/#/feature_tap_dance
[qmk:tri-layer]: https://docs.qmk.fm/#/feature_tri_layer
[x11:clipboard]: https://www.uninformativ.de/blog/postings/2017-04-02/0/POSTING-en.html

A keyboards/keyboardio/atreus/keymaps/slotthe/rules.mk => keyboards/keyboardio/atreus/keymaps/slotthe/rules.mk +9 -0
@@ 0,0 1,9 @@
TAP_DANCE_ENABLE    = yes
KEY_OVERRIDE_ENABLE = yes
AUTOCORRECT_ENABLE  = yes
CAPS_WORD_ENABLE    = yes
REPEAT_KEY_ENABLE   = yes

LTO_ENABLE      = yes
COMMAND_ENABLE  = no
MOUSEKEY_ENABLE = no

Do not follow this link