diff options
| -rw-r--r-- | keyboards/handwired/hexon38/config.h | 60 | ||||
| -rw-r--r-- | keyboards/handwired/hexon38/hexon38.c | 3 | ||||
| -rw-r--r-- | keyboards/handwired/hexon38/hexon38.h | 17 | ||||
| -rw-r--r-- | keyboards/handwired/hexon38/keymaps/default/keymap.c | 407 | ||||
| -rw-r--r-- | keyboards/handwired/hexon38/readme.md | 11 | ||||
| -rw-r--r-- | keyboards/handwired/hexon38/rules.mk | 64 |
6 files changed, 562 insertions, 0 deletions
diff --git a/keyboards/handwired/hexon38/config.h b/keyboards/handwired/hexon38/config.h new file mode 100644 index 000000000..23eb51e01 --- /dev/null +++ b/keyboards/handwired/hexon38/config.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // see https://github.com/pepaslabs/hexon38 | ||
| 2 | |||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "config_common.h" | ||
| 6 | |||
| 7 | /* USB Device descriptor parameter */ | ||
| 8 | #define VENDOR_ID 0xFEED | ||
| 9 | #define PRODUCT_ID 0x6060 | ||
| 10 | #define DEVICE_VER 0x0001 | ||
| 11 | #define MANUFACTURER pepaslabs | ||
| 12 | #define PRODUCT hexon38 | ||
| 13 | #define DESCRIPTION "A handmade non-split ergonomic 38-key keyboard, inspired by the lil38. See https://github.com/pepaslabs/hexon38." | ||
| 14 | |||
| 15 | /* key matrix size */ | ||
| 16 | #define MATRIX_ROWS 4 | ||
| 17 | #define MATRIX_COLS 12 | ||
| 18 | |||
| 19 | /* key matrix pins */ | ||
| 20 | #define MATRIX_ROW_PINS { B0, F0, B2, F4 } | ||
| 21 | #define MATRIX_COL_PINS { C6, D3, D2, D1, D0, B7, F6, F7, B6, B5, B4, D7 } | ||
| 22 | #define UNUSED_PINS | ||
| 23 | |||
| 24 | /* COL2ROW or ROW2COL */ | ||
| 25 | #define DIODE_DIRECTION ROW2COL | ||
| 26 | |||
| 27 | /* number of backlight levels */ | ||
| 28 | |||
| 29 | #ifdef BACKLIGHT_PIN | ||
| 30 | #define BACKLIGHT_LEVELS 0 | ||
| 31 | #endif | ||
| 32 | |||
| 33 | /* Set 0 if debouncing isn't needed */ | ||
| 34 | #define DEBOUNCING_DELAY 5 | ||
| 35 | |||
| 36 | |||
| 37 | /* key combination for command */ | ||
| 38 | #define IS_COMMAND() ( \ | ||
| 39 | keyboard_report->mods == (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT)) \ | ||
| 40 | ) | ||
| 41 | |||
| 42 | #ifdef RGB_DI_PIN | ||
| 43 | #define RGBLIGHT_ANIMATIONS | ||
| 44 | #define RGBLED_NUM 0 | ||
| 45 | #define RGBLIGHT_HUE_STEP 8 | ||
| 46 | #define RGBLIGHT_SAT_STEP 8 | ||
| 47 | #define RGBLIGHT_VAL_STEP 8 | ||
| 48 | #endif | ||
| 49 | |||
| 50 | |||
| 51 | // Disabled features: | ||
| 52 | |||
| 53 | /* Mechanical locking support. Use KC_LCAP, KC_LNUM or KC_LSCR instead in keymap */ | ||
| 54 | //#define LOCKING_SUPPORT_ENABLE | ||
| 55 | |||
| 56 | /* Locking resynchronize hack */ | ||
| 57 | //#define LOCKING_RESYNC_ENABLE | ||
| 58 | |||
| 59 | /* prevent stuck modifiers */ | ||
| 60 | //#define PREVENT_STUCK_MODIFIERS | ||
diff --git a/keyboards/handwired/hexon38/hexon38.c b/keyboards/handwired/hexon38/hexon38.c new file mode 100644 index 000000000..d830adef3 --- /dev/null +++ b/keyboards/handwired/hexon38/hexon38.c | |||
| @@ -0,0 +1,3 @@ | |||
| 1 | // see https://github.com/pepaslabs/hexon38 | ||
| 2 | |||
| 3 | #include "hexon38.h" | ||
diff --git a/keyboards/handwired/hexon38/hexon38.h b/keyboards/handwired/hexon38/hexon38.h new file mode 100644 index 000000000..f98f460fa --- /dev/null +++ b/keyboards/handwired/hexon38/hexon38.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | // see https://github.com/pepaslabs/hexon38 | ||
| 2 | |||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include "quantum.h" | ||
| 6 | |||
| 7 | #define LAYOUT( \ | ||
| 8 | K002, K003, K004, K005, K006, K007, K008, K009, \ | ||
| 9 | K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111, \ | ||
| 10 | K200, K201, K202, K203, K204, K207, K208, K209, K210, K211, \ | ||
| 11 | K302, K303, K304, K305, K306, K307, K308, K309 \ | ||
| 12 | ) { \ | ||
| 13 | { KC_NO, KC_NO, K002, K003, K004, K005, K006, K007, K008, K009, KC_NO, KC_NO }, \ | ||
| 14 | { K100, K101, K102, K103, K104, K105, K106, K107, K108, K109, K110, K111 }, \ | ||
| 15 | { K200, K201, K202, K203, K204, KC_NO, KC_NO, K207, K208, K209, K210, K211 }, \ | ||
| 16 | { KC_NO, KC_NO, K302, K303, K304, K305, K306, K307, K308, K309, KC_NO, KC_NO } \ | ||
| 17 | } | ||
diff --git a/keyboards/handwired/hexon38/keymaps/default/keymap.c b/keyboards/handwired/hexon38/keymaps/default/keymap.c new file mode 100644 index 000000000..c3805991f --- /dev/null +++ b/keyboards/handwired/hexon38/keymaps/default/keymap.c | |||
| @@ -0,0 +1,407 @@ | |||
| 1 | // see https://github.com/pepaslabs/hexon38 | ||
| 2 | |||
| 3 | #include "hexon38.h" | ||
| 4 | |||
| 5 | #define A_ KC_A | ||
| 6 | #define B_ KC_B | ||
| 7 | #define C_ KC_C | ||
| 8 | #define D_ KC_D | ||
| 9 | #define E_ KC_E | ||
| 10 | #define F_ KC_F | ||
| 11 | #define G_ KC_G | ||
| 12 | #define H_ KC_H | ||
| 13 | #define I_ KC_I | ||
| 14 | #define J_ KC_J | ||
| 15 | #define K_ KC_K | ||
| 16 | #define L_ KC_L | ||
| 17 | #define M_ KC_M | ||
| 18 | #define N_ KC_N | ||
| 19 | #define O_ KC_O | ||
| 20 | #define P_ KC_P | ||
| 21 | #define Q_ KC_Q | ||
| 22 | #define R_ KC_R | ||
| 23 | #define S_ KC_S | ||
| 24 | #define T_ KC_T | ||
| 25 | #define U_ KC_U | ||
| 26 | #define V_ KC_V | ||
| 27 | #define W_ KC_W | ||
| 28 | #define X_ KC_X | ||
| 29 | #define Y_ KC_Y | ||
| 30 | #define Z_ KC_Z | ||
| 31 | |||
| 32 | // Dual-role keys: modifier when held, alpha when tapped. | ||
| 33 | #define A_CTL CTL_T(KC_A) | ||
| 34 | #define S_ALT ALT_T(KC_S) | ||
| 35 | #define D_GUI GUI_T(KC_D) | ||
| 36 | #define F_SFT SFT_T(KC_F) | ||
| 37 | #define J_SFT SFT_T(KC_J) | ||
| 38 | #define K_GUI GUI_T(KC_K) | ||
| 39 | #define L_ALT ALT_T(KC_L) | ||
| 40 | #define COLN_CTL CTL_T(KC_SCLN) | ||
| 41 | |||
| 42 | #define ______ KC_TRNS | ||
| 43 | #define LSHIFT KC_LSHIFT | ||
| 44 | #define RSHIFT KC_RSHIFT | ||
| 45 | #define COMMA KC_COMM | ||
| 46 | #define SLASH KC_SLSH | ||
| 47 | #define SPACE KC_SPC | ||
| 48 | #define TAB KC_TAB | ||
| 49 | #define BKSPC KC_BSPC | ||
| 50 | #define ENTER KC_ENT | ||
| 51 | #define PERIOD KC_DOT | ||
| 52 | |||
| 53 | #define BASE_LAYER LAYOUT | ||
| 54 | #define BLANK_LAYER LAYOUT | ||
| 55 | |||
| 56 | |||
| 57 | const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | ||
| 58 | |||
| 59 | BASE_LAYER( | ||
| 60 | // ,--------+--------+--------+--------. ,--------+--------+--------+--------. | ||
| 61 | W_ , E_ , R_ , T_ , Y_ , U_ , I_ , O_ , | ||
| 62 | //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------. | ||
| 63 | Q_ , A_CTL , S_ALT , D_GUI , F_SFT , G_ , H_ , J_SFT , K_GUI , L_ALT ,COLN_CTL, P_ , | ||
| 64 | //|--------+--------+--------+--------+--------+--------' `--------+--------+--------+--------+--------+--------| | ||
| 65 | B_ , Z_ , X_ , C_ , V_ , M_ , COMMA , PERIOD , SLASH , N_ , | ||
| 66 | //`--------+--------+--------+--------+--------' `--------+--------+--------+--------+--------' | ||
| 67 | |||
| 68 | // ,--------+--------+--------+--------. ,--------+--------+--------+--------. | ||
| 69 | LSHIFT , SPACE , TAB , DEBUG , SPACE , BKSPC , ENTER , RSHIFT | ||
| 70 | // `--------+--------+--------+--------' `--------+--------+--------+--------' | ||
| 71 | ), | ||
| 72 | |||
| 73 | BLANK_LAYER( | ||
| 74 | // ,--------+--------+--------+--------. ,--------+--------+--------+--------. | ||
| 75 | ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , | ||
| 76 | //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------. | ||
| 77 | ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , | ||
| 78 | //|--------+--------+--------+--------+--------+--------' `--------+--------+--------+--------+--------+--------| | ||
| 79 | ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ , | ||
| 80 | //`--------+--------+--------+--------+--------' `--------+--------+--------+--------+--------' | ||
| 81 | |||
| 82 | // ,--------+--------+--------+--------. ,--------+--------+--------+--------. | ||
| 83 | ______ , ______ , ______ , ______ , ______ , ______ , ______ , ______ | ||
| 84 | // `--------+--------+--------+--------' `--------+--------+--------+--------' | ||
| 85 | ) | ||
| 86 | |||
| 87 | }; | ||
| 88 | |||
| 89 | // a linked list of pending key events (press or release) which we haven't processed yet. | ||
| 90 | struct _pending_key_t { | ||
| 91 | uint16_t keycode; | ||
| 92 | keyrecord_t record; | ||
| 93 | struct _pending_key_t *next; | ||
| 94 | }; | ||
| 95 | typedef struct _pending_key_t pending_key_t; | ||
| 96 | |||
| 97 | // worst case is 10 down strokes and 1 up stroke before we can start disambiguating. | ||
| 98 | #define RINGSIZE 11 | ||
| 99 | |||
| 100 | // a ring buffer and linked list to store pending key events (presses and releases). | ||
| 101 | // (basically, this is a fixed-allocation linked list.) | ||
| 102 | struct _kring_t { | ||
| 103 | // the actual key events. | ||
| 104 | pending_key_t items[RINGSIZE]; | ||
| 105 | // the index of the oldest item, or -1 if no items. | ||
| 106 | int8_t ifirst; | ||
| 107 | // the index of the most recently added item, or -1 if no items. | ||
| 108 | int8_t ilast; | ||
| 109 | // the number of items in the ring. | ||
| 110 | uint8_t count; | ||
| 111 | // the head of the linked list. | ||
| 112 | pending_key_t *head; | ||
| 113 | }; | ||
| 114 | typedef struct _kring_t kring_t; | ||
| 115 | |||
| 116 | // safe accessor to the i-th item of the linked list (returns pointer or NULL). | ||
| 117 | pending_key_t* kring_get(kring_t *ring, uint8_t i) { | ||
| 118 | if (i >= ring->count) { | ||
| 119 | return NULL; | ||
| 120 | } | ||
| 121 | uint8_t j = (ring->ifirst + i) % RINGSIZE; | ||
| 122 | return &(ring->items[j]); | ||
| 123 | } | ||
| 124 | |||
| 125 | // return the last key in the list of buffered keys. | ||
| 126 | pending_key_t* kring_last(kring_t *ring) { | ||
| 127 | if (ring->count == 0) { | ||
| 128 | return NULL; | ||
| 129 | } | ||
| 130 | return kring_get(ring, ring->count - 1); | ||
| 131 | } | ||
| 132 | |||
| 133 | // remove the oldest item from the ring (the head of the list). | ||
| 134 | void kring_pop(kring_t *ring) { | ||
| 135 | if (ring->count > 0) { | ||
| 136 | ring->ifirst += 1; | ||
| 137 | ring->ifirst %= RINGSIZE; | ||
| 138 | ring->head = ring->head->next; | ||
| 139 | ring->count -= 1; | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | // add an item to the ring (append to the list). | ||
| 144 | void kring_append(kring_t *ring, uint16_t keycode, keyrecord_t *record) { | ||
| 145 | if (ring->count >= RINGSIZE) { | ||
| 146 | // uh oh, we overflowed the capacity of our buffer :( | ||
| 147 | return; | ||
| 148 | } | ||
| 149 | |||
| 150 | // if the ring is empty, insert at index 0. | ||
| 151 | if (ring->count == 0) { | ||
| 152 | ring->count += 1; | ||
| 153 | ring->ifirst = 0; | ||
| 154 | ring->ilast = 0; | ||
| 155 | ring->head = &(ring->items[0]); | ||
| 156 | } | ||
| 157 | // else, append it onto the end. | ||
| 158 | else { | ||
| 159 | ring->count += 1; | ||
| 160 | ring->ilast += 1; | ||
| 161 | ring->ilast %= RINGSIZE; | ||
| 162 | } | ||
| 163 | |||
| 164 | // the index at which we should insert this item. | ||
| 165 | int8_t i = ring->ilast; | ||
| 166 | |||
| 167 | // insert the item. | ||
| 168 | ring->items[i].keycode = keycode; | ||
| 169 | ring->items[i].record.event = record->event; | ||
| 170 | #ifndef NO_ACTION_TAPPING | ||
| 171 | ring->items[i].record.tap = record->tap; | ||
| 172 | #endif | ||
| 173 | ring->items[i].next = NULL; | ||
| 174 | |||
| 175 | // update the previous item to point to this item. | ||
| 176 | if (ring->count > 1) { | ||
| 177 | kring_get(ring, ring->count - 2)->next = &(ring->items[i]); | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | kring_t g_pending; | ||
| 182 | |||
| 183 | void matrix_init_user(void) { | ||
| 184 | g_pending.ifirst = -1; | ||
| 185 | g_pending.ilast = -1; | ||
| 186 | g_pending.count = 0; | ||
| 187 | g_pending.head = NULL; | ||
| 188 | } | ||
| 189 | |||
| 190 | void matrix_scan_user(void) {} | ||
| 191 | |||
| 192 | /* | ||
| 193 | a_ a-: emit a | ||
| 194 | a_ b_ b- a-: emit SHIFT+b | ||
| 195 | a_ b_ a- b-: emit a, b | ||
| 196 | dual1down, dual1up -> norm1down, norm1up | ||
| 197 | dual1down, norm2down, norm2up -> mod1down, norm2down, norm2up | ||
| 198 | dual1down, norm2down, dual1up -> norm1down, norm2down, norm1up | ||
| 199 | dual1down, dual2down, norm3down, norm3up -> mod1down, mod2down, norm3down, norm3up | ||
| 200 | so, a dual key can't be disambiguated until the next keyup of a keydown (not including keyups from keys before it). | ||
| 201 | */ | ||
| 202 | |||
| 203 | bool is_ambiguous_kc(uint16_t kc) { | ||
| 204 | // See the MT() define: https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum_keycodes.h#L642 | ||
| 205 | // See the QK_MOD_TAP case: https://github.com/qmk/qmk_firmware/blob/master/quantum/keymap_common.c#L134 | ||
| 206 | uint8_t mod = mod_config((kc >> 0x8) & 0x1F); | ||
| 207 | return mod != 0; | ||
| 208 | } | ||
| 209 | |||
| 210 | bool is_down(pending_key_t *k) { | ||
| 211 | return k->record.event.pressed; | ||
| 212 | } | ||
| 213 | |||
| 214 | bool is_up(pending_key_t *k) { | ||
| 215 | return !is_down(k); | ||
| 216 | } | ||
| 217 | |||
| 218 | bool keys_match(pending_key_t *a, pending_key_t *b) { | ||
| 219 | return a->record.event.key.col == b->record.event.key.col | ||
| 220 | && a->record.event.key.row == b->record.event.key.row; | ||
| 221 | } | ||
| 222 | |||
| 223 | // both the down and corresponding upstroke of a keypress. | ||
| 224 | struct _pending_pair_t { | ||
| 225 | pending_key_t *down; | ||
| 226 | pending_key_t *up; | ||
| 227 | }; | ||
| 228 | typedef struct _pending_pair_t pending_pair_t; | ||
| 229 | |||
| 230 | // returns true if this keydown event has a corresponding keyup event in the | ||
| 231 | // list of buffered keys. also fills out 'p'. | ||
| 232 | bool is_downup_pair(pending_key_t *k, pending_pair_t *p) { | ||
| 233 | // first, make sure this event is keydown. | ||
| 234 | if (!is_down(k)) { | ||
| 235 | return false; | ||
| 236 | } | ||
| 237 | // now find its matching keyup. | ||
| 238 | pending_key_t *next = k->next; | ||
| 239 | while (next != NULL) { | ||
| 240 | if (keys_match(k, next) && is_up(next)) { | ||
| 241 | // found it. | ||
| 242 | if (p != NULL) { | ||
| 243 | p->down = k; | ||
| 244 | p->up = next; | ||
| 245 | } | ||
| 246 | return true; | ||
| 247 | } | ||
| 248 | next = next->next; | ||
| 249 | } | ||
| 250 | // didn't find it. | ||
| 251 | return false; | ||
| 252 | } | ||
| 253 | |||
| 254 | // given a QK_MOD_TAP keycode, return the KC_* version of the modifier keycode. | ||
| 255 | uint16_t get_mod_kc(uint16_t keycode) { | ||
| 256 | uint8_t mod = mod_config((keycode >> 0x8) & 0x1F); | ||
| 257 | switch (mod) { | ||
| 258 | case MOD_LCTL: | ||
| 259 | return KC_LCTL; | ||
| 260 | case MOD_RCTL: | ||
| 261 | return KC_RCTL; | ||
| 262 | case MOD_LSFT: | ||
| 263 | return KC_LSFT; | ||
| 264 | case MOD_RSFT: | ||
| 265 | return KC_RSFT; | ||
| 266 | case MOD_LALT: | ||
| 267 | return KC_LALT; | ||
| 268 | case MOD_RALT: | ||
| 269 | return KC_RALT; | ||
| 270 | case MOD_LGUI: | ||
| 271 | return KC_LGUI; | ||
| 272 | case MOD_RGUI: | ||
| 273 | return KC_RGUI; | ||
| 274 | default: | ||
| 275 | // shrug? this shouldn't happen. | ||
| 276 | return keycode; | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | bool is_mod_kc(uint16_t keycode) { | ||
| 281 | switch (keycode) { | ||
| 282 | case QK_MODS ... QK_MODS_MAX: | ||
| 283 | return true; | ||
| 284 | default: | ||
| 285 | return false; | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 289 | void interpret_as_mod(pending_pair_t *p) { | ||
| 290 | // see https://github.com/qmk/qmk_firmware/issues/1503 | ||
| 291 | pending_key_t *k; | ||
| 292 | k = p->down; | ||
| 293 | if (k != NULL) { | ||
| 294 | k->keycode = get_mod_kc(k->keycode); | ||
| 295 | } | ||
| 296 | k = p->up; | ||
| 297 | if (k != NULL) { | ||
| 298 | k->keycode = get_mod_kc(k->keycode); | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | void interpret_as_normal(pending_pair_t *p) { | ||
| 303 | pending_key_t *k; | ||
| 304 | k = p->down; | ||
| 305 | if (k != NULL) { | ||
| 306 | k->keycode = k->keycode & 0xFF; | ||
| 307 | } | ||
| 308 | k = p->up; | ||
| 309 | if (k != NULL) { | ||
| 310 | k->keycode = k->keycode & 0xFF; | ||
| 311 | } | ||
| 312 | } | ||
| 313 | |||
| 314 | void execute_head_and_pop(kring_t *ring) { | ||
| 315 | pending_key_t *head = kring_get(ring, 0); | ||
| 316 | uint16_t kc = head->keycode; | ||
| 317 | if (is_mod_kc(kc)) { | ||
| 318 | if (is_down(head)) { | ||
| 319 | dprintf(" %s: mod down 0x%04X\n", __func__, kc); | ||
| 320 | set_mods(get_mods() | MOD_BIT(kc)); | ||
| 321 | } else { | ||
| 322 | dprintf(" %s: mod up 0x%04X\n", __func__, kc); | ||
| 323 | set_mods(get_mods() & ~MOD_BIT(kc)); | ||
| 324 | } | ||
| 325 | } else { | ||
| 326 | if (is_down(head)) { | ||
| 327 | dprintf(" %s: key down 0x%04X\n", __func__, kc); | ||
| 328 | register_code16(kc); | ||
| 329 | } else { | ||
| 330 | dprintf(" %s: key up 0x%04X\n", __func__, kc); | ||
| 331 | unregister_code16(kc); | ||
| 332 | } | ||
| 333 | } | ||
| 334 | kring_pop(ring); | ||
| 335 | } | ||
| 336 | |||
| 337 | // try to figure out what the next pending keypress means. | ||
| 338 | bool parse_next(kring_t *pending) { | ||
| 339 | pending_pair_t p; | ||
| 340 | pending_key_t *first = kring_get(pending, 0); | ||
| 341 | if (!is_ambiguous_kc(first->keycode)) { | ||
| 342 | // this pending key isn't ambiguous, so execute it. | ||
| 343 | dprintf(" %s: found unambiguous key\n", __func__); | ||
| 344 | execute_head_and_pop(pending); | ||
| 345 | return true; | ||
| 346 | } else if (is_ambiguous_kc(first->keycode) && is_up(first)) { | ||
| 347 | dprintf(" %s: interpreting keyup as mod\n", __func__); | ||
| 348 | p.down = NULL; | ||
| 349 | p.up = first; | ||
| 350 | interpret_as_mod(&p); | ||
| 351 | execute_head_and_pop(pending); | ||
| 352 | return true; | ||
| 353 | } else if (is_downup_pair(first, &p)) { | ||
| 354 | // 'first' was released before any other pressed key, so treat this as | ||
| 355 | // a rolling series of normal key taps. | ||
| 356 | dprintf(" %s: found down-up pair, interpreting as normal key\n", __func__); | ||
| 357 | interpret_as_normal(&p); | ||
| 358 | execute_head_and_pop(pending); | ||
| 359 | return true; | ||
| 360 | } else { | ||
| 361 | // if another key was pressed and released while 'first' was held, then we | ||
| 362 | // should treat it like a modifier. | ||
| 363 | pending_key_t *next = first->next; | ||
| 364 | while (next != NULL) { | ||
| 365 | if (is_downup_pair(next, NULL)) { | ||
| 366 | dprintf(" %s: found subsequent downup pair, interpreting head as mod\n", __func__); | ||
| 367 | p.down = first; | ||
| 368 | p.up = NULL; | ||
| 369 | interpret_as_mod(&p); | ||
| 370 | execute_head_and_pop(pending); | ||
| 371 | return true; | ||
| 372 | } | ||
| 373 | next = next->next; | ||
| 374 | } | ||
| 375 | |||
| 376 | // we can't disambiguate 'first' yet. wait for another keypress. | ||
| 377 | dprintf(" %s: can't disambiguate (yet)\n", __func__); | ||
| 378 | return false; | ||
| 379 | } | ||
| 380 | } | ||
| 381 | |||
| 382 | bool process_record_user(uint16_t keycode, keyrecord_t *record) { | ||
| 383 | if (keycode == DEBUG) { | ||
| 384 | return true; | ||
| 385 | } | ||
| 386 | |||
| 387 | if (g_pending.count == 0 && !is_ambiguous_kc(keycode)) { | ||
| 388 | // we have no pending keys and this key isn't ambiguous, so we should | ||
| 389 | // just let QMK take care of it. | ||
| 390 | dprintf("%s: handled by qmk\n", __func__); | ||
| 391 | return true; | ||
| 392 | } else { | ||
| 393 | dprintf("%s: got dual-role key\n", __func__); | ||
| 394 | // append the keypress and then try parsing all pending keypresses. | ||
| 395 | kring_append(&g_pending, keycode, record); | ||
| 396 | while (g_pending.count > 0) { | ||
| 397 | dprintf("%s: looping through %d keys...\n", __func__, g_pending.count); | ||
| 398 | if (!parse_next(&g_pending)) { | ||
| 399 | // one of our keypresses is ambiguous and we can't proceed until | ||
| 400 | // we get further keypresses to disambiguate it. | ||
| 401 | dprintf("%s: %d pending keys are ambiguous\n", __func__, g_pending.count); | ||
| 402 | break; | ||
| 403 | } | ||
| 404 | } | ||
| 405 | return false; | ||
| 406 | } | ||
| 407 | } | ||
diff --git a/keyboards/handwired/hexon38/readme.md b/keyboards/handwired/hexon38/readme.md new file mode 100644 index 000000000..c8ada8e2b --- /dev/null +++ b/keyboards/handwired/hexon38/readme.md | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # hexon38 | ||
| 2 | |||
| 3 | QMK support for the [hexon38](https://github.com/pepaslabs/hexon38). | ||
| 4 | |||
| 5 | ## Building | ||
| 6 | |||
| 7 | ``` | ||
| 8 | $ cd qmk_firmware | ||
| 9 | $ make handwired/hexon38 | ||
| 10 | ``` | ||
| 11 | |||
diff --git a/keyboards/handwired/hexon38/rules.mk b/keyboards/handwired/hexon38/rules.mk new file mode 100644 index 000000000..2b6f17afc --- /dev/null +++ b/keyboards/handwired/hexon38/rules.mk | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | # see https://github.com/pepaslabs/hexon38 | ||
| 2 | |||
| 3 | # MCU name | ||
| 4 | MCU = atmega32u4 | ||
| 5 | |||
| 6 | # Processor frequency. | ||
| 7 | # This will define a symbol, F_CPU, in all source code files equal to the | ||
| 8 | # processor frequency in Hz. You can then use this symbol in your source code to | ||
| 9 | # calculate timings. Do NOT tack on a 'UL' at the end, this will be done | ||
| 10 | # automatically to create a 32-bit value in your source code. | ||
| 11 | # | ||
| 12 | # This will be an integer division of F_USB below, as it is sourced by | ||
| 13 | # F_USB after it has run through any CPU prescalers. Note that this value | ||
| 14 | # does not *change* the processor frequency - it should merely be updated to | ||
| 15 | # reflect the processor speed set externally so that the code can use accurate | ||
| 16 | # software delays. | ||
| 17 | F_CPU = 16000000 | ||
| 18 | |||
| 19 | # | ||
| 20 | # LUFA specific | ||
| 21 | # | ||
| 22 | # Target architecture (see library "Board Types" documentation). | ||
| 23 | ARCH = AVR8 | ||
| 24 | |||
| 25 | # Input clock frequency. | ||
| 26 | # This will define a symbol, F_USB, in all source code files equal to the | ||
| 27 | # input clock frequency (before any prescaling is performed) in Hz. This value may | ||
| 28 | # differ from F_CPU if prescaling is used on the latter, and is required as the | ||
| 29 | # raw input clock is fed directly to the PLL sections of the AVR for high speed | ||
| 30 | # clock generation for the USB and other AVR subsections. Do NOT tack on a 'UL' | ||
| 31 | # at the end, this will be done automatically to create a 32-bit value in your | ||
| 32 | # source code. | ||
| 33 | # | ||
| 34 | # If no clock division is performed on the input clock inside the AVR (via the | ||
| 35 | # CPU clock adjust registers or the clock division fuses), this will be equal to F_CPU. | ||
| 36 | F_USB = $(F_CPU) | ||
| 37 | |||
| 38 | # Interrupt driven control endpoint task(+60) | ||
| 39 | OPT_DEFS += -DINTERRUPT_CONTROL_ENDPOINT | ||
| 40 | |||
| 41 | |||
| 42 | # Bootloader selection | ||
| 43 | # Teensy halfkay | ||
| 44 | # Pro Micro caterina | ||
| 45 | # Atmel DFU atmel-dfu | ||
| 46 | # LUFA DFU lufa-dfu | ||
| 47 | # QMK DFU qmk-dfu | ||
| 48 | # atmega32a bootloadHID | ||
| 49 | BOOTLOADER = halfkay | ||
| 50 | |||
| 51 | |||
| 52 | # Enabled build options: | ||
| 53 | BOOTMAGIC_ENABLE = yes # Virtual DIP switch configuration(+1000) | ||
| 54 | MOUSEKEY_ENABLE = yes # Mouse keys(+4700) | ||
| 55 | EXTRAKEY_ENABLE = yes # Audio control and System control(+450) | ||
| 56 | CONSOLE_ENABLE = yes # Console for debug(+400) | ||
| 57 | COMMAND_ENABLE = yes # Commands for debug and configuration | ||
| 58 | NKRO_ENABLE = yes # USB Nkey Rollover - if this doesn't work, see here: https://github.com/tmk/tmk_keyboard/wiki/FAQ#nkro-doesnt-work | ||
| 59 | |||
| 60 | # Disabled build options: | ||
| 61 | SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend | ||
| 62 | BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality | ||
| 63 | AUDIO_ENABLE = no | ||
| 64 | RGBLIGHT_ENABLE = no | ||
