/*
Copyright 2022 @Yowkees
Copyright 2022 MURAOKA Taro (aka KoRoN, @kaoriya)
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/>.
*/
#include QMK_KEYBOARD_H
#include "quantum.h"
// Home row mods
#define HR_A KC_A
#define HR_S MT(MOD_LALT, KC_S)
#define HR_D MT(MOD_LSFT, KC_D)
#define HR_F MT(MOD_LCTL, KC_F)
#define HR_J MT(MOD_RCTL, KC_J)
#define HR_K MT(MOD_RSFT, KC_K)
#define HR_L MT(MOD_RALT, KC_L)
#define HR_SCLN KC_SCLN
// Custom shortcuts
#define KC_EUNDO LCTL(LSFT(KC_MINUS))
#define KC_AENTER LCTL(LALT(KC_ENT))
#define WAYFULL LGUI(LSFT(KC_F))
#define WAYHALF LGUI(LSFT(KC_D))
#define KC_CAD LCTL(LALT(KC_DEL))
enum {
TD_UNDO,
};
// Combo for caps word
const uint16_t PROGMEM capsword_combo[] = {HR_D, HR_K, COMBO_END};
combo_t key_combos[] = {
COMBO(capsword_combo, QK_CAPS_WORD_TOGGLE),
};
tap_dance_action_t tap_dance_actions[] = {
[TD_UNDO] = ACTION_TAP_DANCE_DOUBLE(KC_U, KC_EUNDO),
};
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
// Base layer
[0] = LAYOUT_universal(
KC_Q , KC_W , KC_E , KC_R , KC_T , KC_Y , TD(TD_UNDO), KC_I , KC_O , KC_P ,
HR_A , HR_S , HR_D , HR_F , KC_G , KC_H , HR_J , HR_K , HR_L , HR_SCLN ,
KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMM , KC_DOT , KC_SLSH ,
KC_ESC , KC_TAB , MO(5) , LT(3,KC_TAB), LT(4,KC_BSPC), KC_LGUI, MT(MOD_RGUI, KC_ENT), LT(4,KC_SPC), _______, _______, _______, KC_QUOT
),
// Transparent layer for HR_L GUI+N behavior
[1] = LAYOUT_universal(
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
),
// Gaming layer (removes home row mods via layer toggle)
[2] = LAYOUT_universal(
_______ , _______ , KC_E , _______ , _______ , _______ , KC_U , _______ , _______ , _______ ,
KC_A , KC_S , KC_D , KC_F , _______ , _______ , KC_J , KC_K , KC_L , KC_SCLN ,
_______ , _______ , _______ , _______ , KC_B , _______ , _______ , _______ , _______ , _______ ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
),
// Mouse + Numpad layer (via left thumb)
[3] = LAYOUT_universal(
_______ , _______ , _______ , _______ , _______ , KC_SLSH , KC_7 , KC_8 , KC_9 , KC_ASTR ,
_______ , _______ , _______ , _______ , _______ , KC_MINS , KC_4 , KC_5 , KC_6 , KC_PLUS ,
SCRL_TO , SCRL_MO , KC_BTN2 , KC_BTN1 , _______ , KC_0 , KC_1 , KC_2 , KC_3 , KC_DOT ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
),
// Symbols layer (via thumb keys)
[4] = LAYOUT_universal(
KC_GRV , KC_TILDE , KC_HASH , KC_AMPR , KC_PIPE, KC_CIRC , KC_LCBR , KC_RCBR , KC_LBRC , KC_RBRC ,
KC_EXLM , KC_UNDS , KC_COLN , KC_EQL , KC_DLR , KC_AT , KC_LPRN , KC_RPRN , KC_UNDS , KC_SCLN ,
KC_PERC , KC_QUES , KC_ASTR , KC_PLUS , KC_BSLS , KC_SLSH , KC_MINUS , KC_LT , KC_GT , KC_DQT ,
_______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______ , _______
),
// Nav/Settings layer
[5] = LAYOUT_universal(
RGB_TOG , AML_TO , AML_I50 , AML_D50 , TG(1) , _______ , SSNP_VRT , SSNP_HOR , SSNP_FRE , QK_BOOT ,
WAYHALF , WAYFULL , KC_CAD , KC_AENTER, SCRL_DVI, CPI_I100, KC_HOME , KC_UP , KC_END , _______ ,
RGB_MOD , RGB_RMOD , RGB_VAI , RGB_VAD , SCRL_DVD, CPI_D100, KC_LEFT , KC_DOWN , KC_RGHT , _______ ,
QK_BOOT , KBC_RST , _______ , _______ , _______ , _______ , _______ , C(S(KC_TAB)), C(KC_TAB), KC_PGUP , KC_PGDN , KBC_SAVE
),
};
// clang-format on
layer_state_t layer_state_set_user(layer_state_t state) {
// Auto enable scroll mode on layer 5 (nav layer)
// Only force scroll ON for layer 5; let SCRL_TO handle toggling otherwise
if (get_highest_layer(state) == 5) {
keyball_set_scroll_mode(true);
}
return state;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case HR_L:
if (record->event.pressed && record->tap.count && layer_state_is(1)) {
uint8_t mods = get_mods();
uint8_t weak = get_weak_mods();
uint8_t oneshot = get_oneshot_mods();
if ((mods | weak | oneshot) & MOD_MASK_GUI) {
// GUI is already held; just tap N so the host sees GUI+N.
tap_code(KC_N);
return false;
}
}
break;
}
return true;
}
bool caps_word_press_user(uint16_t keycode) {
switch (keycode) {
// Keycodes that continue Caps Word, with shift applied.
case KC_A ... KC_Z:
case TD(TD_UNDO): // Treat tap dance U like a letter
add_weak_mods(MOD_BIT(KC_LSFT));
return true;
// Keycodes that continue Caps Word, without shifting.
case KC_1 ... KC_0:
case KC_BSPC:
case KC_DEL:
case KC_UNDS:
case KC_MINS:
return true;
default:
return false; // Deactivate Caps Word.
}
}
// Override scroll direction (invert vertical scroll) with accumulator
// Adjust SCROLL_DIVISOR to control speed (higher = slower)
#define SCROLL_DIVISOR 4
void keyball_on_apply_motion_to_mouse_scroll(report_mouse_t *report, report_mouse_t *output, bool is_left) {
static int16_t acc_h = 0;
static int16_t acc_v = 0;
// Accumulate movement
acc_h += report->x;
acc_v += report->y;
// Consume input
report->x = 0;
report->y = 0;
// Calculate scroll output
int8_t h = acc_h / SCROLL_DIVISOR;
int8_t v = acc_v / SCROLL_DIVISOR;
// Keep remainder for next time
acc_h -= h * SCROLL_DIVISOR;
acc_v -= v * SCROLL_DIVISOR;
// Apply to output (inverted)
output->h = is_left ? h : -h;
output->v = is_left ? v : -v;
// scroll snapping
switch (keyball_get_scrollsnap_mode()) {
case KEYBALL_SCROLLSNAP_MODE_VERTICAL:
output->h = 0;
break;
case KEYBALL_SCROLLSNAP_MODE_HORIZONTAL:
output->v = 0;
break;
default:
// pass by without doing anything
break;
}
}
uint16_t get_quick_tap_term(uint16_t keycode, keyrecord_t *record) {
switch (keycode) {
case LT(4, KC_BSPC):
return TAPPING_TERM; // Enable quick-tap for backspace
case HR_F:
return TAPPING_TERM; // Enable quick-tap for Ctrl+F repeating
default:
return 0; // Disabled for everything else (home row mods)
}
}
#ifdef OLED_ENABLE
# include "lib/oledkit/oledkit.h"
void oledkit_render_info_user(void) {
keyball_oled_render_keyinfo();
keyball_oled_render_ballinfo();
keyball_oled_render_layerinfo();
}
#endif