Created
March 29, 2026 20:50
-
-
Save jasonwbarnett/68b63ed3ad6675d945e17a6e26107a5a to your computer and use it in GitHub Desktop.
Keychron Q2 ANSI Encoder (Q2N3Z) custom QMK keymap - Nav layer with vim HJKL, RGB layer indicators, 125ms tapping term
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #pragma once | |
| /* Enable per-key tapping term overrides via get_tapping_term() */ | |
| #define TAPPING_TERM_PER_KEY |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Copyright 2021 @ Keychron (https://www.keychron.com) | |
| * | |
| * 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 2 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/>. | |
| */ | |
| /* | |
| * Custom keymap for the Keychron Q2 ANSI Encoder (Q2N3Z) | |
| * | |
| * Changes from the default keymap: | |
| * | |
| * BASE LAYERS (MAC_BASE & WIN_BASE): | |
| * - Top-left key changed from Escape to Grave/Tilde (`/~) | |
| * - Caps Lock replaced with Nav/Esc dual-role key: | |
| * Hold = activate _NAV layer, Tap = Escape | |
| * - Right Slash (/) replaced with Shift/Slash dual-role key: | |
| * Hold = Right Shift, Tap = Slash (/) | |
| * Uses a very short 35ms tapping term for fast typing | |
| * - MO(_FN3) on bottom row replaced with Right Ctrl | |
| * | |
| * _NAV LAYER (hold Caps Lock to activate): | |
| * Vim-style navigation on the right hand: | |
| * | |
| * Y(Home) U(PgDn) I(PgUp) O(End) Del->PgUp | |
| * H(Left) J(Down) K(Up) L(Right) Home->PgDn | |
| * | |
| * Del and Home keys on the right column also become PgUp/PgDn | |
| * for easy one-finger access. | |
| * | |
| * OTHER: | |
| * - RGB backlighting disabled on keyboard startup | |
| * | |
| * ENCODER (volume knob): | |
| * - Base layers: Volume down/up on turn, Mute on press | |
| * - FN1/FN2: RGB brightness down/up on turn, RGB toggle on press | |
| */ | |
| #include QMK_KEYBOARD_H | |
| enum layers { | |
| MAC_BASE, | |
| WIN_BASE, | |
| _NAV, | |
| _FN1, | |
| _FN2, | |
| _FN3 | |
| }; | |
| #define KC_TASK LGUI(KC_TAB) | |
| #define KC_FLXP LGUI(KC_E) | |
| /* Hold = Right Shift, Tap = Slash (/) */ | |
| #define SFT_SLSH MT(MOD_RSFT, KC_SLSH) | |
| const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |
| /* | |
| * MAC_BASE: Default layer for macOS | |
| * | |
| * ,---------------------------------------------------------------. ,----. | |
| * | ` | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 0 | - | = | Bksp | |Mute| | |
| * |---------------------------------------------------------------| `----' | |
| * | Tab | Q | W | E | R | T | Y | U | I | O | P | [ | ] | \ | |Del | | |
| * |---------------------------------------------------------------| `----' | |
| * |Nav/Esc| A | S | D | F | G | H | J | K | L | ; | ' | Enter | |Home| | |
| * |---------------------------------------------------------------| `----' | |
| * | Shift | Z | X | C | V | B | N | M | , | . |Sft//|Shft| Up | | |
| * |---------------------------------------------------------------| | |
| * |Ctrl |Opt |Cmd | Space |Cmd |FN1 |Ctrl|Lt|Dn|Rt| | |
| * `---------------------------------------------------------------' | |
| */ | |
| [MAC_BASE] = LAYOUT_ansi_67( | |
| KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_MUTE, | |
| KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, | |
| LT(_NAV, KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, | |
| KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, SFT_SLSH, KC_RSFT, KC_UP, | |
| KC_LCTL, KC_LOPT, KC_LCMD, KC_SPC, KC_RCMD, MO(_FN1), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), | |
| /* WIN_BASE: Same customizations as MAC_BASE but with Windows modifiers */ | |
| [WIN_BASE] = LAYOUT_ansi_67( | |
| KC_GRV, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC, KC_MUTE, | |
| KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS, KC_DEL, | |
| LT(_NAV, KC_ESC), KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_HOME, | |
| KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, SFT_SLSH, KC_RSFT, KC_UP, | |
| KC_LCTL, KC_LWIN, KC_LALT, KC_SPC, KC_RALT, MO(_FN2), KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT), | |
| /* | |
| * _NAV: Navigation layer (hold Caps Lock to activate) | |
| * | |
| * Vim-style navigation on the right hand: | |
| * | |
| * ,---------------------------------------------------------------. ,----. | |
| * | | | | | | | | | | | | | | | | | | |
| * |---------------------------------------------------------------| `----' | |
| * | | | | | | |Hom |PgDn|PgUp|End | | | | | |PgUp| | |
| * |---------------------------------------------------------------| `----' | |
| * | [NAV] | | | | | | <- | Dn | Up | -> | | | | |PgDn| | |
| * |---------------------------------------------------------------| `----' | |
| * | | | | | | | | | | | | | | | |
| * |---------------------------------------------------------------| | |
| * | | | | | | | | | | | | |
| * `---------------------------------------------------------------' | |
| */ | |
| [_NAV] = LAYOUT_ansi_67( | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, KC_HOME, KC_PGDN, KC_PGUP, KC_END, _______, _______, _______, _______, KC_PGUP, | |
| _______, _______, _______, _______, _______, _______, KC_LEFT, KC_DOWN, KC_UP, KC_RGHT, _______, _______, _______, KC_PGDN, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______), | |
| /* _FN1: Mac function layer (hold FN1 to access) | |
| * - Number row: Grave, Brightness, media controls, volume | |
| * - Letters: RGB controls, NK toggle | |
| * - Encoder press: RGB toggle | |
| */ | |
| [_FN1] = LAYOUT_ansi_67( | |
| KC_GRV, KC_BRID, KC_BRIU, _______, _______, RM_VALD, RM_VALU, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, RM_TOGG, | |
| RM_TOGG, RM_NEXT, RM_VALU, RM_HUEU, RM_SATU, RM_SPDU, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, RM_PREV, RM_VALD, RM_HUED, RM_SATD, RM_SPDD, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______), | |
| /* _FN2: Windows function layer (same as FN1 but adds Task View and File Explorer shortcuts) */ | |
| [_FN2] = LAYOUT_ansi_67( | |
| KC_GRV, KC_BRID, KC_BRIU, KC_TASK, KC_FLXP, RM_VALD, RM_VALU, KC_MPRV, KC_MPLY, KC_MNXT, KC_MUTE, KC_VOLD, KC_VOLU, _______, RM_TOGG, | |
| RM_TOGG, RM_NEXT, RM_VALU, RM_HUEU, RM_SATU, RM_SPDU, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, RM_PREV, RM_VALD, RM_HUED, RM_SATD, RM_SPDD, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______), | |
| /* _FN3: F-key layer (F1-F12 on number row) */ | |
| [_FN3] = LAYOUT_ansi_67( | |
| KC_TILD, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, _______, _______, | |
| RM_TOGG, RM_NEXT, RM_VALU, RM_HUEU, RM_SATU, RM_SPDU, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, RM_PREV, RM_VALD, RM_HUED, RM_SATD, RM_SPDD, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, | |
| _______, _______, _______, _______, _______, _______, _______, _______, _______, _______) | |
| }; | |
| /* Encoder (volume knob) mappings per layer */ | |
| #if defined(ENCODER_MAP_ENABLE) | |
| const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = { | |
| [MAC_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) }, /* Volume down / up */ | |
| [WIN_BASE] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) }, /* Volume down / up */ | |
| [_NAV] = { ENCODER_CCW_CW(_______, _______) }, /* No action */ | |
| [_FN1] = { ENCODER_CCW_CW(RM_VALD, RM_VALU) }, /* RGB brightness down / up */ | |
| [_FN2] = { ENCODER_CCW_CW(RM_VALD, RM_VALU) }, /* RGB brightness down / up */ | |
| [_FN3] = { ENCODER_CCW_CW(_______, _______) }, /* No action */ | |
| }; | |
| #endif | |
| /* Disable RGB backlighting on startup */ | |
| void keyboard_post_init_user(void) { | |
| rgb_matrix_disable(); | |
| } | |
| /* Light up all keys when _NAV or _FN1 layers are active, turn off when released */ | |
| layer_state_t layer_state_set_user(layer_state_t state) { | |
| if (IS_LAYER_ON_STATE(state, _NAV)) { | |
| rgb_matrix_enable_noeeprom(); | |
| rgb_matrix_mode_noeeprom(RGB_MATRIX_SOLID_COLOR); | |
| rgb_matrix_sethsv_noeeprom(128, 255, 100); /* Teal */ | |
| } else if (IS_LAYER_ON_STATE(state, _FN1)) { | |
| rgb_matrix_enable_noeeprom(); | |
| rgb_matrix_mode_noeeprom(RGB_MATRIX_SOLID_COLOR); | |
| rgb_matrix_sethsv_noeeprom(180, 255, 100); /* Purple */ | |
| } else { | |
| rgb_matrix_disable_noeeprom(); | |
| } | |
| return state; | |
| } | |
| /* Per-key tapping term overrides */ | |
| uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) { | |
| switch (keycode) { | |
| case SFT_SLSH: | |
| /* Hold longer than 105ms = Right Shift, tap = Slash (/) */ | |
| return 125; | |
| case LT(_NAV, KC_ESC): | |
| /* Hold longer than 105ms = _NAV layer, tap = Escape */ | |
| return 125; | |
| default: | |
| return TAPPING_TERM; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ENCODER_MAP_ENABLE = yes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment