]> git.donarmstrong.com Git - qmk_firmware.git/blob - users/twschum/twschum.c
Merge pull request #7666 from fauxpark/docs-edit-page
[qmk_firmware.git] / users / twschum / twschum.c
1 #include "twschum.h"
2
3 #ifdef TWSCHUM_TAPPING_CTRL_PREFIX
4 // state for the great state machine of custom actions!
5 #define TIMEOUT_DELAY 200 // ms
6 static uint16_t idle_timer;
7 static bool timeout_is_active = false;
8
9 static bool ctrl_shortcuts_enabled_g = false;
10 //static bool B_down = 0; // TODO just use top bit from count
11 //static int8_t B_count = 0;
12
13 #define N_TAPPING_CTRL_KEYS 2
14 static struct Tapping_ctrl_key_t special_keys_g[N_TAPPING_CTRL_KEYS] = {
15     {false, 0, KC_B}, {false, 0, KC_A}
16 };
17
18 static inline void start_idle_timer(void) {
19     idle_timer = timer_read();
20     timeout_is_active = true;
21 }
22 static inline void clear_state_after_idle_timeout(void) {
23     idle_timer = 0;
24     timeout_is_active = false;
25
26     // send timed out plain keys from tapping ctrl mod
27     for (int i = 0; i < N_TAPPING_CTRL_KEYS; ++i) {
28         struct Tapping_ctrl_key_t* key = special_keys_g + i;
29         repeat_send_keys(key->count, key->keycode);
30         key->count = 0;
31     }
32 }
33
34 inline void matrix_scan_user(void) {
35     if (timeout_is_active && timer_elapsed(idle_timer) > TIMEOUT_DELAY) {
36         clear_state_after_idle_timeout();
37     }
38 }
39
40 static inline bool tap_ctrl_event(struct Tapping_ctrl_key_t* key, keyrecord_t* record) {
41     if (!ctrl_shortcuts_enabled_g) {
42         // normal operation, just send the plain keycode
43         if (record->event.pressed) {
44             register_code(key->keycode);
45         }
46         else {
47             unregister_code(key->keycode);
48         }
49         return false;
50     }
51     key->down = record->event.pressed;
52     // increment count and reset timer when key pressed
53     // start the timeout when released
54     if (key->down) {
55         ++(key->count);
56         timeout_is_active = false;
57         idle_timer = 0;
58     }
59     else {
60         if (key->count) {
61             start_idle_timer();
62         }
63     }
64     return false;
65 }
66
67 static inline bool tap_ctrl_other_pressed(void) {
68     for (int i = 0; i < N_TAPPING_CTRL_KEYS; ++i) {
69         struct Tapping_ctrl_key_t* key = special_keys_g + i;
70         if (key->count) {
71             if (key->down) {
72                 // another key has been pressed while the leader key is down,
73                 // so send number of ctrl-KEY combos before the other key
74                 repeat_send_keys(key->count, KC_LCTL, key->keycode);
75                 key->count = 0;
76             }
77             else {
78                 // another key pressed after leader key released,
79                 // need to send the plain keycode plus potential mods
80                 if (get_mods() & MOD_MASK_CTRL) {
81                     // make sure to send a shift if prssed
82                     repeat_send_keys(key->count, KC_RSHIFT, key->keycode);
83                 }
84                 else {
85                     repeat_send_keys(key->count, key->keycode);
86                 }
87                 key->count = 0;
88             }
89             return true; // will send the other keycode
90         }
91     }
92     return true; // safe default
93 }
94 #endif /* TWSCHUM_TAPPING_CTRL_PREFIX */
95
96
97 /* Use RGB underglow to indicate layer
98  * https://docs.qmk.fm/reference/customizing-functionality
99  */
100 // add to quantum/rgblight_list.h
101 #ifdef RGBLIGHT_ENABLE
102 static bool rgb_layers_enabled = true;
103 static bool rgb_L0_enabled = false;
104
105 layer_state_t layer_state_set_user(layer_state_t state) {
106     if (!rgb_layers_enabled) {
107         return state;
108     }
109     switch (get_highest_layer(state)) {
110     case _Base:
111         if (rgb_L0_enabled) {
112             rgblight_sethsv_noeeprom(_Base_HSV_ON);
113         }
114         else {
115             rgblight_sethsv_noeeprom(_Base_HSV_OFF);
116         }
117         break;
118     case _Vim:
119         rgblight_sethsv_noeeprom(_Vim_HSV);
120         break;
121     case _Fn:
122         rgblight_sethsv_noeeprom(_Fn_HSV);
123         break;
124     case _Nav:
125         rgblight_sethsv_noeeprom(_Nav_HSV);
126         break;
127     case _Num:
128         rgblight_sethsv_noeeprom(_Num_HSV);
129         break;
130     case _Cfg:
131         rgblight_sethsv_noeeprom(_Cfg_HSV);
132         break;
133     case _None:
134         rgblight_sethsv_noeeprom(_None_HSV);
135         break;
136     }
137     return state;
138 }
139 #endif /* RGBLIGHT_ENABLE */
140
141 /* process_record_vimlayer: handles the VIM_ keycodes from xtonhasvim's vim
142  * emulation layer
143  * add process_record_keymap to allow specific keymap to still add keys
144  * Makes the callstack look like:
145  * process_record_
146  *  _quantum
147  *    _kb
148  *      _user
149  *        _keymap
150  *        _vimlayer
151  */
152 __attribute__ ((weak))
153 bool process_record_keymap(uint16_t keycode, keyrecord_t *record) {
154   return true;
155 }
156
157 /* Return True to continue processing keycode, false to stop further processing
158  * process_record_keymap to be call by process_record_user in the vim addon */
159 bool process_record_user(uint16_t keycode, keyrecord_t *record) {
160
161   /* keymap gets first whack, then vimlayer */
162   if(!process_record_keymap(keycode, record)) return false;
163   if(!process_record_vimlayer(keycode, record)) return false;
164
165     switch (keycode) {
166         /* KC_MAKE is a keycode to be used with any keymap
167          * Outputs `make <keyboard>:<keymap>`
168          * Holding shift will add the appropriate flashing command (:dfu,
169          *   :teensy, :avrdude, :dfu-util) for a majority of keyboards.
170          * Holding control will add some commands that will speed up compiling
171          *   time by processing multiple files at once
172          * For the boards that lack a shift key, or that you want to always
173          *   attempt the flashing part, you can add FLASH_BOOTLOADER = yes to the
174          *   rules.mk of that keymap.
175          */
176         case KC_MAKE:  // Compiles the firmware, and adds the flash command based on keyboard bootloader
177             if (!record->event.pressed) {
178             uint8_t temp_mod = get_mods();
179             uint8_t temp_osm = get_oneshot_mods();
180             clear_mods(); clear_oneshot_mods();
181             SEND_STRING("make " QMK_KEYBOARD ":" QMK_KEYMAP);
182         #ifndef FLASH_BOOTLOADER
183             if ( (temp_mod | temp_osm) & MOD_MASK_SHIFT ) {
184                 SEND_STRING(":flash");
185             }
186         #endif
187             if ( (temp_mod | temp_osm) & MOD_MASK_CTRL) {
188                 SEND_STRING(" -j8 --output-sync");
189             }
190             SEND_STRING(SS_TAP(X_ENTER));
191             set_mods(temp_mod);
192         }
193         break;
194
195         #ifdef RGBLIGHT_ENABLE
196         case TG_LAYER_RGB:
197             if (record->event.pressed) {
198                 rgb_layers_enabled = !rgb_layers_enabled;
199             }
200             return false;
201         case TG_L0_RGB:
202             if (record->event.pressed) {
203                 rgb_L0_enabled = !rgb_L0_enabled;
204             }
205             return false;
206         #endif
207
208         case SALT_CMD:
209             if (!record->event.pressed) {
210                 SEND_STRING(SALT_CMD_MACRO);
211             }
212             return false;
213         case LESS_PD:
214             if (!record->event.pressed) {
215                 SEND_STRING(LESS_PD_MACRO);
216             }
217             return false;
218         case CODE_PASTE:
219             if (!record->event.pressed) {
220                 SEND_STRING(CODE_PASTE_MACRO);
221             }
222             return false;
223
224         #ifdef TWSCHUM_TAPPING_CTRL_PREFIX
225         case EN_CTRL_SHORTCUTS:
226             if (record->event.pressed) {
227                 ctrl_shortcuts_enabled_g = !ctrl_shortcuts_enabled_g;
228                 start_idle_timer(); // need to clear out state in some cases
229             }
230             return false;
231         case CTRL_A:
232             return tap_ctrl_event(&special_keys_g[1], record);
233         case CTRL_B:
234             return tap_ctrl_event(&special_keys_g[0], record);
235         default:
236             if (record->event.pressed) {
237                 return tap_ctrl_other_pressed();
238             }
239         #endif
240     }
241     return true;
242 }
243
244 #ifdef RGBLIGHT_ENABLE
245 void matrix_init_user(void) {
246     // called once on board init
247     rgblight_enable();
248 }
249 #endif
250
251 void suspend_power_down_user(void) {
252     // TODO shut off backlighting
253 }
254
255 void suspend_wakeup_init_user(void) {
256     // TODO turn on backlighting
257 }