aboutsummaryrefslogtreecommitdiffstats
path: root/keyboards/ergodox_ez/keymaps/bdk/keymap.c
blob: 20af6c18ed4000526a5798aa2d9d9075c7107f7a (plain) (blame)
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include QMK_KEYBOARD_H

#define SHIFT_DOWN() (get_mods() & (MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)))
#define KC_FKEYS MO(FKEYS)

// Layers
enum {
    BASE=0,
    SYMNUM,  // Symbols and numbers (activated by holding enter)
    FKEYS,   // Function keys (activated by a thumb button)
};

// counter that increments on all key press events.  This is needed for our LT
// handling
uint16_t press_counter = 0;

const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {

// Keymap 0: Base layer

[BASE] = LAYOUT_ergodox(
  // left hand ---------------------------------------------------------------------------------------------------
  KC_NO,          KC_EXLM,        KC_AT,          KC_HASH,        KC_DLR,         KC_PERC,        KC_NO,
  KC_GRV,         KC_QUOT,        KC_COMM,        KC_DOT,         KC_P,           KC_Y,           KC_LGUI,
  KC_SLSH,        KC_A,           KC_O,           KC_E,           KC_U,           KC_I,
  KC_LSFT,        KC_SCLN,        KC_Q,           KC_J,           KC_K,           KC_X,           KC_HOME,
  KC_LCTL,        KC_LALT,        KC_PGUP,        KC_PGDN,        KC_NO,
  // left thumb --------------------------------------------------------------------------------------------------
                                                                                  KC_NO,          KC_NO,
                                                                                                  KC_NO,
                                                                  KC_SPC,         KC_TAB,         KC_FKEYS,
  // right hand --------------------------------------------------------------------------------------------------
  KC_NO,          KC_CIRC,        KC_AMPR,        KC_ASTR,        KC_LPRN,        KC_RPRN,        KC_NO,
  KC_RGUI,        KC_F,           KC_G,           KC_C,           KC_R,           KC_L,           KC_BSLS,
                  KC_D,           KC_H,           KC_T,           KC_N,           KC_S,           KC_MINS,
  KC_END,         KC_B,           KC_M,           KC_W,           KC_V,           KC_Z,           KC_RSFT,
                  KC_LEFT,        KC_UP,          KC_DOWN,        KC_RIGHT,       KC_RCTL,
  // right thumb -------------------------------------------------------------------------------------------------
  KC_NO,          KC_NO,
  KC_NO,
  KC_DEL,         KC_BSPC,        KC_ENT
),
// SYMNUM -- numpad and function keys
[SYMNUM] = LAYOUT_ergodox(
  // left hand ---------------------------------------------------------------------------------------------------
  KC_TRNS,        LALT(KC_1),     LALT(KC_2),     LALT(KC_3),     LALT(KC_4),     LALT(KC_5),     KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_AMPR,        KC_TRNS,        KC_TRNS,
  KC_TRNS,        KC_LCBR,        KC_LBRC,        KC_LPRN,        KC_0,           KC_MINS,
  KC_TRNS,        KC_6,           KC_7,           KC_8,           KC_9,           KC_SLSH,        KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  // left thumb --------------------------------------------------------------------------------------------------
                                                                                  KC_TRNS,        KC_TRNS,
                                                                                                  KC_TRNS,
                                                                  KC_TRNS,        KC_TRNS,        KC_TRNS,
  // right hand --------------------------------------------------------------------------------------------------
  KC_TRNS,        LALT(KC_6),     LALT(KC_7),     LALT(KC_8),     LALT(KC_9),     LALT(KC_0),     KC_TRNS,
  KC_TRNS,        KC_PERC,        KC_EQL,         KC_LT,          KC_GT,          KC_EXLM,        KC_TRNS,
                  KC_PLUS,        KC_1,           KC_RPRN,        KC_RBRC,        KC_RCBR,        KC_TRNS,
  KC_TRNS,        KC_ASTR,        KC_2,           KC_3,           KC_4,           KC_5,           KC_TRNS,
                  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  // right thumb -------------------------------------------------------------------------------------------------
  KC_TRNS,        KC_TRNS,
  KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS
),
// FKEYS -- function keys
[FKEYS] = LAYOUT_ergodox(
  // left hand ---------------------------------------------------------------------------------------------------
  KC_TRNS,        KC_F1,          KC_F2,          KC_F3,          KC_F4,          KC_F5,          KC_F6,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  // left thumb --------------------------------------------------------------------------------------------------
                                                                                  KC_TRNS,        KC_TRNS,
                                                                                                  KC_TRNS,
                                                                  KC_TRNS,        KC_TRNS,        KC_TRNS,
  // right hand --------------------------------------------------------------------------------------------------
  KC_F7,          KC_F8,          KC_F9,          KC_F10,         KC_F11,         KC_F12,         KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
                  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
                  KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,        KC_TRNS,
  // right thumb -------------------------------------------------------------------------------------------------
  KC_TRNS,        KC_TRNS,
  KC_TRNS,
  KC_TRNS,        KC_TRNS,        KC_TRNS
),
};

// Code to handle layer tap.
//
// The default code doesn't work for me, so I rolled my own code.  The main
// difference is that it always tries to send modifier+key combination, rather
// than two keys.  One place where this is noticable is if you tap the key,
// then try hold it.

struct tap_start_info {
    uint16_t timer;
    uint16_t initial_press_counter;
};

static struct tap_start_info tap_start_infos[5];

// Quick check to see if a key is down.  Note that this requires NKRO enabled
static bool key_down(uint8_t code) {
    return (keyboard_report->nkro.bits[code>>3] & 1<<(code&7)) != 0;
}

static bool handle_lt(uint16_t keycode, keyrecord_t *record, uint8_t layer, uint8_t index) {
    struct tap_start_info* tap_start = tap_start_infos + index;

    if(record->event.pressed) {
        layer_on(layer);
        tap_start->timer = timer_read();
        tap_start->initial_press_counter = press_counter;
    } else {
        layer_off(layer);
        // Only click the key if:
        //   - No other keys are pressed between the press and release events
        //   - The release happens before the ONESHOT_TIMEOUT
        if(press_counter == tap_start->initial_press_counter && timer_elapsed(tap_start->timer) < ONESHOT_TIMEOUT) {
            register_code16(keycode);
            unregister_code16(keycode);
        }
    }
    return false;
}

static bool handle_mt(uint16_t keycode, keyrecord_t *record, uint8_t mods, uint8_t index) {
    struct tap_start_info* tap_start = tap_start_infos + index;

    if(record->event.pressed) {
        register_mods(mods);
        tap_start->timer = timer_read();
        tap_start->initial_press_counter = press_counter;
    } else {
        unregister_mods(mods);
        // Only click the key if:
        //   - No other keys are pressed between the press and release events
        //   - The release happens before the ONESHOT_TIMEOUT
        if(press_counter == tap_start->initial_press_counter && timer_elapsed(tap_start->timer) < ONESHOT_TIMEOUT) {
            register_code16(keycode);
            unregister_code16(keycode);
        }
    }
    return false;
}

bool process_record_user(uint16_t keycode, keyrecord_t *record) {
    if(record->event.pressed) {
        press_counter++;
        // The symbol layer allows sequences repeat the same "physical" key.
        // For example "0)", which is like pressing the "0" key twice in a
        // row.  It's very easy to make a sequence of these where the ")"
        // press comes before the "0" release.  If that happens, force a
        // release of the "0" key, otherwise nothing will happen.
        uint8_t shortcode = keycode & 0xFF;
        if(key_down(shortcode)) {
            unregister_code(shortcode);
        }
    }

    switch(keycode) {
        case KC_ENTER:
            return handle_lt(keycode, record, SYMNUM, 0);

        case KC_TAB:
            return handle_mt(keycode, record, MOD_BIT(KC_LCTL), 1);

        case KC_LSFT:
        case KC_RSFT:
            return handle_mt(KC_ESC, record, MOD_BIT(keycode), 2);
    }
    return true;
}