aboutsummaryrefslogtreecommitdiff
path: root/users/twschum/twschum.c
diff options
context:
space:
mode:
Diffstat (limited to 'users/twschum/twschum.c')
-rw-r--r--users/twschum/twschum.c257
1 files changed, 257 insertions, 0 deletions
diff --git a/users/twschum/twschum.c b/users/twschum/twschum.c
new file mode 100644
index 000000000..2d34f9571
--- /dev/null
+++ b/users/twschum/twschum.c
@@ -0,0 +1,257 @@
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
6static uint16_t idle_timer;
7static bool timeout_is_active = false;
8
9static 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
14static struct Tapping_ctrl_key_t special_keys_g[N_TAPPING_CTRL_KEYS] = {
15 {false, 0, KC_B}, {false, 0, KC_A}
16};
17
18static inline void start_idle_timer(void) {
19 idle_timer = timer_read();
20 timeout_is_active = true;
21}
22static 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
34inline 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
40static 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
67static 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
102static bool rgb_layers_enabled = true;
103static bool rgb_L0_enabled = false;
104
105layer_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))
153bool 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 */
159bool 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
245void matrix_init_user(void) {
246 // called once on board init
247 rgblight_enable();
248}
249#endif
250
251void suspend_power_down_user(void) {
252 // TODO shut off backlighting
253}
254
255void suspend_wakeup_init_user(void) {
256 // TODO turn on backlighting
257}