#include "twschum.h" #ifdef TWSCHUM_TAPPING_CTRL_PREFIX // state for the great state machine of custom actions! #define TIMEOUT_DELAY 200 // ms static uint16_t idle_timer; static bool timeout_is_active = false; static bool ctrl_shortcuts_enabled_g = false; //static bool B_down = 0; // TODO just use top bit from count //static int8_t B_count = 0; #define N_TAPPING_CTRL_KEYS 2 static struct Tapping_ctrl_key_t special_keys_g[N_TAPPING_CTRL_KEYS] = { {false, 0, KC_B}, {false, 0, KC_A} }; static inline void start_idle_timer(void) { idle_timer = timer_read(); timeout_is_active = true; } static inline void clear_state_after_idle_timeout(void) { idle_timer = 0; timeout_is_active = false; // send timed out plain keys from tapping ctrl mod for (int i = 0; i < N_TAPPING_CTRL_KEYS; ++i) { struct Tapping_ctrl_key_t* key = special_keys_g + i; repeat_send_keys(key->count, key->keycode); key->count = 0; } } inline void matrix_scan_user(void) { if (timeout_is_active && timer_elapsed(idle_timer) > TIMEOUT_DELAY) { clear_state_after_idle_timeout(); } } static inline bool tap_ctrl_event(struct Tapping_ctrl_key_t* key, keyrecord_t* record) { if (!ctrl_shortcuts_enabled_g) { // normal operation, just send the plain keycode if (record->event.pressed) { register_code(key->keycode); } else { unregister_code(key->keycode); } return false; } key->down = record->event.pressed; // increment count and reset timer when key pressed // start the timeout when released if (key->down) { ++(key->count); timeout_is_active = false; idle_timer = 0; } else { if (key->count) { start_idle_timer(); } } return false; } static inline bool tap_ctrl_other_pressed(void) { for (int i = 0; i < N_TAPPING_CTRL_KEYS; ++i) { struct Tapping_ctrl_key_t* key = special_keys_g + i; if (key->count) { if (key->down) { // another key has been pressed while the leader key is down, // so send number of ctrl-KEY combos before the other key repeat_send_keys(key->count, KC_LCTL, key->keycode); key->count = 0; } else { // another key pressed after leader key released, // need to send the plain keycode plus potential mods if (get_mods() & MOD_MASK_CTRL) { // make sure to send a shift if prssed repeat_send_keys(key->count, KC_RSHIFT, key->keycode); } else { repeat_send_keys(key->count, key->keycode); } key->count = 0; } return true; // will send the other keycode } } return true; // safe default } #endif /* TWSCHUM_TAPPING_CTRL_PREFIX */ /* Use RGB underglow to indicate layer * https://docs.qmk.fm/reference/customizing-functionality */ // add to quantum/rgblight_list.h #ifdef RGBLIGHT_ENABLE static bool rgb_layers_enabled = true; static bool rgb_L0_enabled = false; layer_state_t layer_state_set_user(layer_state_t state) { if (!rgb_layers_enabled) { return state; } switch (get_highest_layer(state)) { case _Base: if (rgb_L0_enabled) { rgblight_sethsv_noeeprom(_Base_HSV_ON); } else { rgblight_sethsv_noeeprom(_Base_HSV_OFF); } break; case _Vim: rgblight_sethsv_noeeprom(_Vim_HSV); break; case _Fn: rgblight_sethsv_noeeprom(_Fn_HSV); break; case _Nav: rgblight_sethsv_noeeprom(_Nav_HSV); break; case _Num: rgblight_sethsv_noeeprom(_Num_HSV); break; case _Cfg: rgblight_sethsv_noeeprom(_Cfg_HSV); break; case _None: rgblight_sethsv_noeeprom(_None_HSV); break; } return state; } #endif /* RGBLIGHT_ENABLE */ /* process_record_vimlayer: handles the VIM_ keycodes from xtonhasvim's vim * emulation layer * add process_record_keymap to allow specific keymap to still add keys * Makes the callstack look like: * process_record_ * _quantum * _kb * _user * _keymap * _vimlayer */ __attribute__ ((weak)) bool process_record_keymap(uint16_t keycode, keyrecord_t *record) { return true; } /* Return True to continue processing keycode, false to stop further processing * process_record_keymap to be call by process_record_user in the vim addon */ bool process_record_user(uint16_t keycode, keyrecord_t *record) { /* keymap gets first whack, then vimlayer */ if(!process_record_keymap(keycode, record)) return false; if(!process_record_vimlayer(keycode, record)) return false; switch (keycode) { /* KC_MAKE is a keycode to be used with any keymap * Outputs `make :` * Holding shift will add the appropriate flashing command (:dfu, * :teensy, :avrdude, :dfu-util) for a majority of keyboards. * Holding control will add some commands that will speed up compiling * time by processing multiple files at once * For the boards that lack a shift key, or that you want to always * attempt the flashing part, you can add FLASH_BOOTLOADER = yes to the * rules.mk of that keymap. */ case KC_MAKE: // Compiles the firmware, and adds the flash command based on keyboard bootloader if (!record->event.pressed) { uint8_t temp_mod = get_mods(); uint8_t temp_osm = get_oneshot_mods(); clear_mods(); clear_oneshot_mods(); SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP); #ifndef FLASH_BOOTLOADER if ( (temp_mod | temp_osm) & MOD_MASK_SHIFT ) { SEND_STRING(":flash"); } #endif if ( (temp_mod | temp_osm) & MOD_MASK_CTRL) { SEND_STRING(" -j8 --output-sync"); } SEND_STRING(SS_TAP(X_ENTER)); set_mods(temp_mod); } break; #ifdef RGBLIGHT_ENABLE case TG_LAYER_RGB: if (record->event.pressed) { rgb_layers_enabled = !rgb_layers_enabled; } return false; case TG_L0_RGB: if (record->event.pressed) { rgb_L0_enabled = !rgb_L0_enabled; } return false; #endif case SALT_CMD: if (!record->event.pressed) { SEND_STRING(SALT_CMD_MACRO); } return false; case LESS_PD: if (!record->event.pressed) { SEND_STRING(LESS_PD_MACRO); } return false; case CODE_PASTE: if (!record->event.pressed) { SEND_STRING(CODE_PASTE_MACRO); } return false; #ifdef TWSCHUM_TAPPING_CTRL_PREFIX case EN_CTRL_SHORTCUTS: if (record->event.pressed) { ctrl_shortcuts_enabled_g = !ctrl_shortcuts_enabled_g; start_idle_timer(); // need to clear out state in some cases } return false; case CTRL_A: return tap_ctrl_event(&special_keys_g[1], record); case CTRL_B: return tap_ctrl_event(&special_keys_g[0], record); default: if (record->event.pressed) { return tap_ctrl_other_pressed(); } #endif } return true; } #ifdef RGBLIGHT_ENABLE void matrix_init_user(void) { // called once on board init rgblight_enable(); } #endif void suspend_power_down_user(void) { // TODO shut off backlighting } void suspend_wakeup_init_user(void) { // TODO turn on backlighting }