aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xkeyboards/evolv/keymaps/gondolindrim/keymap.c410
-rw-r--r--keyboards/evolv/rules.mk6
2 files changed, 413 insertions, 3 deletions
diff --git a/keyboards/evolv/keymaps/gondolindrim/keymap.c b/keyboards/evolv/keymaps/gondolindrim/keymap.c
new file mode 100755
index 000000000..3ab66bd05
--- /dev/null
+++ b/keyboards/evolv/keymaps/gondolindrim/keymap.c
@@ -0,0 +1,410 @@
1/*
2Copyright 2021 Álvaro "Gondolindrim" Volpato <alvaro.volpato@usp.br>
3
4This program is free software: you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation, either version 2 of the License, or
7(at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18/* ---------------------------------------------- EVOLV75 GONDOLINDRIM LAYOUT
19This is the firmware for the Evolv75 CE (pre-Alpha) PCBs as designed by Gondolindrim.
20
21The final objective is to achieve a joystic encoder feature where the encoder can exhibit multiple behaviours, hereby called "encoder modes", which can be switched seamlessly by the user. In order to make the user know what encoder mode is active at a given instant, the keyboard has RGB underglow LEDs that shine a particular color; each mode has its own color.
22
23Modes, their behaviours and their colors are user-customizable.
24*/
25
26/* ---------------------------------------------- BASIC DEFINITIONS
27DON"T CHANGE ANY OF THESE.
28*/
29
30#include QMK_KEYBOARD_H
31typedef uint8_t color[3];
32#define COLOR(h,s,v) ((color){h,s,v})
33
34// Defining custom keycodes
35enum keyboard_keycodes {
36 ENCCLK = 0x5F80, // For "encoder click"
37 ENCNTH, // "Encoder north"
38 ENCSTH, // "Encoder south"
39 ENCEST, // "Encoder east"
40 ENCWST, // "Encoder west"
41 ALTTABN, // For alt-tab-switch, next
42 ALTTABP, // For alt-tab-switch, previous
43 ALTTABC, // For alt-tab-click
44 ENCMUP, // Encoder mode up
45 ENCMDN // Encoder mode down
46};
47
48// Defining the encoder mode data structure
49typedef struct _encoder_mode_t {
50 color indicator_color;
51 uint16_t clockwise_key[4];
52 uint16_t counterclockwise_key[4];
53 uint16_t clicked_key[4];
54 uint16_t north_key[4];
55 uint16_t south_key[4];
56 uint16_t east_key[4];
57 uint16_t west_key[4];
58} encoder_mode_t;
59
60/* ---------------------------------------------- COLORS
61Colors are defined as HSV values where the values range from 0 to 255. Template:
62
63#define <COLOR NAME> COLOR( <HSV CODE> )
64
65Use these to define the colors for encoder modes.
66*/
67
68#define CYAN COLOR(128,255,255)
69#define PINK COLOR(191,255,255)
70#define YELLOW COLOR(36,255,255)
71#define WHITE COLOR(0,0,255)
72#define STARTUP_COLOR WHITE
73
74/* ---------------------------------------------- DELAYS
75These delays define some important behaviours on the firmware.
76
77MEDIA_KEY_DELAY is used throughout the code to hold certain keycodes for a time before holding them; this allows the use of media keys like volume up and down everywhere.
78
79ALT_TAB_DELAY is the time delay the firmware holds the LALT key before letting it go; in practical use this means once you rotate the encoder in alt-tabbing mode, it will keep the alt-tab window held for this amount of time.
80
81ENCODER_CLICK_DELAY defines a delayed behavior for the encoder click. Once you click it, a timer is triggered and monitored. If the click is held for more than this macro (defaults to 1000 or 1 second), encoder modes start cycling, each per second, and stops when you release. If you hold the click for shorter than the time defined in this macro, then the firmware registers the key contained in the .clicked_key list of that mode.
82*/
83
84#define MEDIA_KEY_DELAY 20
85#define ALT_TAB_DELAY 2000
86#define ENCODER_CLICK_DELAY 1000
87
88// -------------------------------------------- ENCODER MODES
89/* Encoder mode list
90WARNING: DO NOT, ABSOLUTELY DO NOT use ENCNTH, ENCSTH, ENCWST or ENCEST in any of the encoder mode keys. The reason is because these keycodes are used in process_record_user and they point to these very same encoder mode keys; this could generate a loop in process_record_user and freeze the keyboard.
91
92You can add and remove modes at will as long as you have at least one.
93*/
94const encoder_mode_t encoder_modes[] = {
95 // PINK MODE: "media mode". Encoder controls volume (and mode change on layer 1); click does media pause (mute on layer 1), directionals do arrows.
96 { .indicator_color = PINK,
97 .clockwise_key = {KC_VOLU, ENCMUP, KC_VOLU, KC_VOLU},
98 .counterclockwise_key = {KC_VOLD, ENCMDN, KC_VOLD, KC_VOLD},
99 .clicked_key = {KC_MUTE, KC_MUTE, KC_MPLY, KC_MUTE},
100 .north_key = {KC_UP, KC_UP, KC_UP, KC_UP},
101 .south_key = {KC_DOWN, KC_DOWN, KC_DOWN, KC_DOWN},
102 .east_key = {KC_RGHT, KC_RGHT, KC_RGHT, KC_RGHT},
103 .west_key = {KC_LEFT, KC_LEFT, KC_LEFT, KC_LEFT}
104 },
105 /* CYAN MODE: "application mode". Switches back and forth between applications ("alt-tabbing"); click stops the alt-tabbing at the selected application. When on layer 1, encoder changes modes. East-west switches tabs ("ctrl-tabbing") and north-sourh maximizes/minimizes windows (GUI plus up and down). Note: these are modifier keys defined natively in QMK
106 - C(kc) means hold left control and press kc
107 - MEH(kc) means hold left control, left shift and press kc
108 - G(kc) means hold LGUI and press kc
109*/
110 { .indicator_color = CYAN,
111 .clockwise_key = {ALTTABN, ENCMUP, ALTTABN, ALTTABN},
112 .counterclockwise_key = {ALTTABP, ENCMDN, ALTTABP, ALTTABP},
113 .clicked_key = {ALTTABC, ALTTABC, ALTTABC, ALTTABC},
114 .north_key = {G(KC_UP),G(KC_UP), G(KC_UP), G(KC_UP)},
115 .south_key = {G(KC_DOWN), G(KC_DOWN), G(KC_DOWN), G(KC_DOWN)},
116 .east_key = {C(KC_TAB), C(KC_TAB), C(KC_TAB), C(KC_TAB)},
117 .west_key = {S(C(KC_TAB)), S(C(KC_TAB)), S(C(KC_TAB)), S(C(KC_TAB))}
118 },
119 // YELLOW MODE: "navigation mode". Encoder mimicks mousehwheel, click does mouseclick. North-wouth does page up/down, east-west do home and end.
120 { .indicator_color = YELLOW,
121 .clockwise_key = {KC_WH_U, ENCMUP, KC_WH_U, KC_WH_U},
122 .counterclockwise_key = {KC_WH_D, ENCMDN, KC_WH_D, KC_WH_D},
123 .clicked_key = {KC_BTN1, KC_BTN2, KC_BTN1, KC_BTN1},
124 .north_key = {KC_PGUP, KC_PGUP, KC_PGUP, KC_PGUP},
125 .south_key = {KC_PGDN, KC_PGDN, KC_PGDN, KC_PGDN},
126 .east_key = {KC_END, KC_END, KC_END, KC_END},
127 .west_key = {KC_HOME, KC_HOME, KC_HOME, KC_HOME}
128 }
129 // Insert your custom encoder mode here
130};
131
132#define NUM_ENCODER_MODES (sizeof(encoder_modes)/sizeof(encoder_modes[0])) // DO NOT CHANGE THIS. NUM_ENCODER_MODES calculates how many modes there are.
133
134// This counter is used to track what encoder mode is being used at a certain time
135int encoder_mode_count = 0;
136
137/* ---------------------------------------------- RGB STARTING COLOR
138Due to the way rgblight.c stores to and re-stores RGB configurations from EEPROM, the first time the MCU boots up, the EEPROM will not have stored the default value for the RGB animation which in QMK is the static red light; however, during the first bootup, this EEPROM will be set so that, in all subsequent bootups, the RGBs will glow red instead of whatever color the first encoder mode is. What these lines do is re-define the default RGB color so that the default RGB color is defined the same as encoder mode [0] so that the RGB will glow this color once the keyboard boots. DONT CHANGE THIS.
139*/
140#define RGBLIGHT_DEFAULT_HUE encoder_modes[0].indicator_color[0]
141#define RGBLIGHT_DEFAULT_SAT encoder_modes[0].indicator_color[1]
142#define RGBLIGHT_DEFAULT_VAL encoder_modes[0].indicator_color[2]
143
144/* ---------------------------------------------- DEFINING DEFAULT KEYMAP
145Adapt this at will with the caveat that you should not have more nor less than four layers. And let's be honest, if you find yourself needing more than four layers on a 75% keyboard you are probably doing something wrong.
146*/
147const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
148 [0] = LAYOUT_evolv_iso(
149 KC_ESC , KC_F1 , KC_F2 , KC_F3 , KC_F4 , KC_F5 , KC_F6 , KC_F7 , KC_F8 , KC_F9 , KC_F10 , KC_F11 , KC_F12 , KC_INS ,
150 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_BSPC, KC_DEL , ENCNTH,
151 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_ENT , KC_PGUP, ENCWST , ENCCLK, ENCEST,
152 KC_CAPS, KC_A , KC_S , KC_D , KC_F , KC_G , KC_H , KC_J , KC_K , KC_L , KC_SCLN, KC_QUOT, KC_NUHS, KC_PGDN, ENCSTH,
153 KC_LSFT, KC_BSLS, KC_Z , KC_X , KC_C , KC_V , KC_B , KC_N , KC_M , KC_COMM, KC_DOT , KC_SLSH, KC_RSFT, KC_UP , MO(1) ,
154 KC_LCTL, KC_LGUI, KC_LALT, KC_SPC , KC_RALT, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT),
155 [1] = LAYOUT_evolv_iso(
156 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
157 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCNTH,
158 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCWST , ENCCLK, ENCEST,
159 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCSTH,
160 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_TRNS,
161 _______, _______, _______, _______, _______, _______, _______, _______, _______),
162 [2] = LAYOUT_evolv_iso(
163 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
164 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCNTH,
165 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCWST , ENCCLK, ENCEST,
166 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCSTH,
167 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
168 _______, _______, _______, _______, _______, _______, _______, _______, _______),
169 [3] = LAYOUT_evolv_iso(
170 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
171 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCNTH,
172 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCWST , ENCCLK, ENCEST,
173 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, ENCSTH,
174 _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
175 _______, _______, _______, _______, _______, _______, _______, _______, _______)
176};
177
178/* ---------------------------------------------- END OF USER CUSTOMIZABLE CODE
179Everything past here are functions that operate the firmware. There is nothing to be customized by the user for encoder modes or keyboard keymap.
180*/
181
182/* ---------------------------------------------- SET INDICATOR COLOR FUNCTION
183This is the function used when the RGB colors need to change.
184*/
185void set_indicator_colors(const color target_color){
186 rgblight_sethsv(target_color[0],target_color[1],target_color[2]);
187};
188
189// Board init: RGB indicator is set to the first encoder mode color, also encoder mode is set to first mode.
190void keyboard_pre_init_user(void){
191 set_indicator_colors(STARTUP_COLOR);
192 encoder_mode_count = 0;
193};
194
195void keyboard_post_init_user(void){
196 set_indicator_colors(encoder_modes[0].indicator_color);
197};
198
199/* ---------------------------------------------- SPECIAL KEYCODE PROCESSING
200 The heart of this firmware is the process_custom_keycode function; this allows all the customized keycodes ENCMUP, ENCMDN, ALTTABN, ALLTABP and so on to be used in any place including the encoder callback. Its main mechanic is calling the process_record_user function, where there is a function for each one of the customized keycodes.
201 What process_custom_keycode does is, if a "normal" keycode is passed on, then it is registered and held for a small period of time (MEDIA_KEY_DELAY to be more specific). This "holding" allows it to correctly register media keys. However, if a custom keycode is used, then the function executes process_record_user again, but now with a new argument keycode that will be whatever is mapped inside the special key requested.
202 Admittedly, this implementation looks redundant: process_record_user calls process_custom_keycode which calls process_record_user again. However, the ingenuity of this recursion is this allows any of the custom keycodes to be mappable both to encoder action as well as keys by having their behavior mapped to a single function in a switch-case structure. For instance, by having the encoder update function encoder_update_user use process_custom_keycode, the code for each custom keycode can be present in a single place in the code, that is, in process_record_user. On another hand, if the user wants to map a certain special keycode to a particular key, they can do so; for instance, if the user wants to map the encoder mode switch keys ENCMUP/ENCMDN to, say, left and right keys of layer 1, they can also do so.
203 The glaring problem with this approach is the same as with all recursions: a recursion mapped to itself is a loop, meaning that it is very easy to put the program in a loop within process_record_user by nesting the custom keycodes, for instance, using the keycode ENCNTH in a north key in any of the modes. This then requires a certain care from whoever is adapting or customizing their encoder modes to not use ENCNTH, ENCSTH, ENCWST, ENCEST in the keymap or the encoder modes. The way the firmware deals with this is by only processing keycodes inside the 0x5F85 and 0x5F89 range which exclude these keys; if the given keycode is in the 0x5F80 to 0x5F84 range, which pertains to these forbidden keycodes, nothing is done; to the user it will seem like nothing happens.
204 In the case of the encoder rotating action, in order to call process_record_user a placeholder record is used, the idea being to use values not obtainable phisically on the keyboard like col 20, row 20, with a timer right at the begginig of the code initialization.
205keyrecord_t record {
206 keyevent_t event {
207 keypos_t key {
208 uint8_t col
209 uint8_t row
210 }
211 bool pressed
212 uint16_t time
213 }
214}
215
216Despite this long description, process_custom_kc is fairly simple. It tests the passed keycode and, if it is one of the custom-defined keys in the forbidden range, nothing is done; if it's one of the good ones, process_record_user is called and the function for that particular keycode will be executed. In other cases, if the event was a press the keycode is registered and held for MEDIA_KEY_DELAY ms. In the case the event was a release, the keycode is unregistered.
217*/
218
219keyrecord_t placeholder_record ;
220//placeholder_record->event.key.col = 20;
221//placeholder_record.event.key.row = 20;
222//placeholder_record.event.time = timer_read32();
223
224uint16_t mapped_code = 0;
225uint32_t held_keycode_timer = 0;
226void process_custom_keycode(uint16_t keycode, keyrecord_t *record){
227 if (keycode >= 0x05F80 && keycode < 0x5F85) ;
228 else if (keycode >= 0x5F85 && keycode <= 0x5F89) process_record_user(keycode, record);
229 else {
230 // Note: (un)register_keycode16 need to be the 16 bit versions in case modifier keys like C(), G() and so on are used. This is specially true for the "application control" encoder mode.
231 if (record->event.pressed){
232 register_code16(keycode);
233 held_keycode_timer = timer_read32();
234 while (timer_elapsed32(held_keycode_timer) < MEDIA_KEY_DELAY);
235 } else unregister_code16(keycode);
236 }
237}
238
239// Basically calls process_custom_keycode in a press event and then in a release event. This is basically done to tap custom keycodes.
240void tap_custom_keycode(uint16_t keycode){
241 placeholder_record.event.pressed = true;
242 process_custom_keycode(keycode, &placeholder_record);
243 placeholder_record.event.pressed = false;
244 process_custom_keycode(keycode, &placeholder_record);
245}
246
247/* ---------------------------------------------- LAYER UPDATING
248Keeps track of the highest active layer.
249*/
250int current_layer = 0 ; // Updated in layer_state_set_user each time a layer change is made
251layer_state_t layer_state_set_user(layer_state_t state) {
252 current_layer = get_highest_layer(state);
253 return state;
254}
255
256/* ---------------------------------------------- ENCODER MDOE CYCLING
257Pretty straightforward: cycles encoder mode forwards if passed a true value and backwards otherwise.
258
259Some care is taken for two edge cases:
260 - The user is at mode 0 and the encoder mode is changed backwards
261 - The user is at the last mode and changes it forward.
262
263The program deals with this last case by taking the division remainder, which will take encoder_mode_count to 0. For the first case, encoder_mode_count is just made equal to the last (highest) mode.
264*/
265void cycle_encoder_mode(bool forward){
266 forward ? encoder_mode_count++ : encoder_mode_count-- ;
267 if (encoder_mode_count == -1) encoder_mode_count = NUM_ENCODER_MODES - 1;
268 encoder_mode_count = encoder_mode_count%NUM_ENCODER_MODES ; // This makes sure encoder_mode_count keeps cycling between 0,1,...,NUM_ENCODER_MODES and doesnt eventually overflow
269 set_indicator_colors( encoder_modes[ encoder_mode_count ].indicator_color ); // Set indicator color to the corresponding defined color
270}
271
272/* ---------------------------------------------- PROCESSING ALT-TABBING
273This function process the alt-tabbing keycode ALTTABS. The process works in a few steps:
274- At first, the flag is_alt_tab_active is false. When the user first uses this keycode (rotating the encoder, for instance) then the function turns the flag and "presses" left alt (KC_LALT), also triggering a timer alt_tab_timer.
275- The alt_tab_timer is supposed to keep track of how many miliseconds the alt-tab window should be kept, that is, how much time the LALT keycode should be held. The objective being, once the user cycles through the applications to the desired one, they select it either by not rotating the applications anymore or clicking the encoder.
276- Finally, the function shoots out the KC_TAB keycode if the encoder was rotated clockwise or the S(KC_TAB) (shift + tab) if the encoder was rotated counterclockwise.
277- If the user cycles the encoder still while alt-tab is active, then the function refreshes the timer and shoots out tab or shift+tab.
278- The function that keeps track of the timer expiration is housekeeping_task_user, where if the alt_tab_timer surpasses the defined ALT_TAB_DELAY macro (defaults to 2 seconds or 2000 ms) then the release_alt_tab function is called: the LALT keycode is released and the is_alt_tab_active flag is set to false again
279- The release_alt_tab function is also called when the ALTTABC keycode is hit, thus selecting the desired application.
280*/
281
282// This bool records if LALT is pressed or not. Due to the automatic disabling of the ALT-TAB of the ALTTABS custom keystroke, the automatic disabling can un-register KC_LALT even when the LALT key is phisically pressed. Hence there needs to be two bools: one that keebs track of the ALT-TAB activity and one that keeps track of LALT so that the automatic disabling will not disable LALT if it is phisically pressed.
283bool is_lalt_pressed = false;
284bool is_alt_tab_active = false; // Flag to check if alt tab is active
285uint32_t alt_tab_timer = 0; // Time trigger for alt tab
286void process_alt_tabbing(bool next){
287 if(!is_alt_tab_active) {
288 is_alt_tab_active = true;
289 register_code(KC_LALT);
290 }
291 alt_tab_timer = timer_read32();
292 tap_code16(next ? KC_TAB : S(KC_TAB));
293}
294
295void release_alt_tab(void){
296 is_alt_tab_active = false;
297 unregister_code(KC_LALT);
298}
299
300/* ---------------------------------------------- ENCODER UPDATE CALLBACK
301This taps the keycode stored in the encoder mode struct, at the current encoder mode, at the current layer. Because the user can use non-QMK-native keycodes in the encoder, like the alt-tabbing keycodes like ALTTABP and ATLTTABN, the tap function is the custom tap one.
302*/
303
304bool encoder_update_user(uint8_t index, bool clockwise) {
305 mapped_code = clockwise ? encoder_modes[ encoder_mode_count ].clockwise_key[ current_layer ] : encoder_modes[ encoder_mode_count ].counterclockwise_key[ current_layer ] ; // mapped code is the clockwise key if a clockwise motion is sensed, otherwise it registers the counterclockwise key
306 tap_custom_keycode(mapped_code);
307 return false; // This function needs to return false in order to inhibit the action of encoder_update_user as defined in evolv.c
308}
309
310/* ---------------------------------------------- DEALING WITH THE ENCODER CLICK
311The encoder used in the Evolv has a construction particularity in that not only it has rotation and clicking but also directional joystic capabilities in the four cardinal directions, as in, it can also register four directions. The way that this works is, there are A,B and a common pin for the encoder rotation , with a PUSH and a COM pin. The encoder pins work pretty much like common encoders, as does the switch click: once you click it, PUSH and COM short-circuit, so the pushing mechanic can be easily integrated into a switch matrix and treated like a switch would.
312
313The problem, however, lies in the directionals. For each directional, say N,S,W,E, there is a corresponding pin on the encoder; once one directional is hit its pin is shorted with PUSH and COM. This means that the directionals can be treated as four short-circuit keys and integrated into the matrix, but with the added hassle that every time one of them is registered, the encoder push is also registered.
314
315The way this firmware deals with this problem is threefold.
316
317- First, there is a is_click_blocked flag that is set true whenever one of the directionals is sensed by the matrix; the name suggests that in this case the click keycode processing should be "blocked". This allows the firmware to differentiate between an event where a directional was hit (the encoder push is recognized but is_click_blocked is true) and an event where only the push was used (is_click_blocked is false albeit the push being sensed).
318- Second, in order to prevent the encoder push key from registering before the flag is set, a 20ms delay takes place when the encoder click was sensed; this means that when a directional is hit, the encoder action is guaranteed to be processed only after the is_click_blocked flag is true.
319- Finally, held_click_timer and is_click_held are used to differentiate between a click short push and a long push; when a directional key is hit, is_click_held is immediately reset, further preventing any action corresponding to the encoder push click being held down.
320
321automatic_encoder_mode_cycle is a flag used by the housekeeping function to communicate an encoder mode change was made during an encoder push, meaning that the user has held the encoder enough to trigger an encoder mode change. What the housekeeping function does is constantly monitor the timer so that, when it extrapolates the designated ENCODER_CLICK_DELAY, a mode change takes place; the held_click_timer timer is refreshed. The problem is that, once the user reaches their desired mode and releases the encoder, the timer had been refreshed and is lower than the designated delay, which would cause the "fast click" keycode to be triggered, which is of course unwanted. Hence the algorithm filters out these situations by knowing when the automatic mode change has taken place and not registering the click key, only resetting the automatic_encoder_mode_cycle flag.
322
323Finally, the process_encoder_click function has two parts. In a click press event, it sets the flag is_click_held and triggers a timer. When the encoder push is released, the timer is sampled and the pertinent action is taken depending on how much time the encoder was held for.
324*/
325
326uint32_t held_click_timer = 0;
327bool is_click_held = false;
328bool is_shift_held = false;
329bool automatic_encoder_mode_cycle = false; // This flag registers if the encoder mode was automatically cycled
330bool is_click_blocked = false;
331void process_encoder_click(bool clickpress){
332 // What to do when the encoder is pressed: turn the flag to true, start (or refresh) timer
333 if (clickpress) {
334 is_click_held = true;
335 held_click_timer = timer_read32();
336 } else { // What to do when encoder is released
337 is_click_held = false;
338 // Checking if the time the encoder click was held was smaller than the delay defined and if an automatic mode change was not already performed. If it was, just register whatever it is the click does.
339 if (timer_elapsed32(held_click_timer) < ENCODER_CLICK_DELAY && !automatic_encoder_mode_cycle ) tap_custom_keycode(encoder_modes[ encoder_mode_count ].clicked_key[ current_layer ]);
340 automatic_encoder_mode_cycle = false;
341 }
342}
343
344bool process_directional(uint16_t keycode, keyrecord_t *record){
345 is_click_held = false;
346 is_click_blocked = record->event.pressed ;
347 process_custom_keycode( keycode , record );
348 return false;
349}
350
351bool process_record_user(uint16_t keycode, keyrecord_t *record) {
352 switch (keycode) {
353 case KC_LSFT:
354 case KC_RSFT:
355 is_shift_held = record->event.pressed;
356 break;
357 case KC_LALT: // If this is not defined, if the encoder is activated in the alt-tab mode while the LALT key is pressed, the menu goes away.
358 is_lalt_pressed = record->event.pressed;
359 break;
360// ---------------------------------------------- CUSTOM KEYCODES: they do their thing and retun false right away to prevent any further action
361// --------------------- Encoder directionals (note: process_directional always returns false)
362 case ENCNTH: return process_directional( encoder_modes[ encoder_mode_count ].north_key[ current_layer ] , record);
363 case ENCSTH: return process_directional( encoder_modes[ encoder_mode_count ].south_key[ current_layer ] , record);
364 case ENCEST: return process_directional( encoder_modes[ encoder_mode_count ].east_key[ current_layer ] , record);
365 case ENCWST: return process_directional( encoder_modes[ encoder_mode_count ].west_key[ current_layer ] , record);
366// --------------------- Encoder click
367 case ENCCLK:
368 held_keycode_timer = timer_read32();
369 while (timer_elapsed32(held_keycode_timer) < 20);
370 if(!is_click_blocked) process_encoder_click(record->event.pressed);
371 return false; // Skip all further processing of this key
372// --------------------- Alt-tabbing
373 case ALTTABN:
374 case ALTTABP:
375 if(record->event.pressed) process_alt_tabbing(keycode == ALTTABN); // alt-tabs forward if the keycode is ALTTABN, else alt-tabs backwards if it's ALTTABP
376 return false;
377 case ALTTABC:
378 if(record->event.pressed) release_alt_tab();
379 return false;
380// --------------------- Encoder mode up/down
381 case ENCMUP:
382 case ENCMDN:
383 if(record->event.pressed) cycle_encoder_mode(keycode == ENCMUP); // Cycles encoder mode up if keycode is ENCMUP, else cycles backwards if the keycode is ENCMDN
384 return false;
385// ---------------------------------------------- DEFAULT
386 default:
387 return true;
388 }
389 return true;
390}
391
392/* ---------------------------------------------- HOUSEKEEPING
393Housekeeping keeps track of three events:
394- Keeps track of the alt-tabbing timer. If it surpasses ALT_TAB_DELAY the release_alt_tab function is called;
395- Keeps track of the encoder click hold timer; if the encoder click is held for more than a certain delay, cycles encoder mode and sets the automatic_mode_change flag.
396- The is_click_blocked flag marks if the encoder click has been registered with a directional key (recall that in this encoder, when a directional key is hit, both the directional key and the encoder push key are triggered in the keymap). In this case, only the directional should be registered. Hence, this housekeeping function resets the held_click_timer timer because, if this is not done, if the directional key is held for more than ENCODER_CLICK_DELAY then this will trigger an automatic mode change.
397*/
398void housekeeping_task_user(void) {
399 if (is_alt_tab_active){
400 if (is_lalt_pressed) alt_tab_timer = timer_read32(); // If the user is holding the LALT key, refresh the timer
401 else if (timer_elapsed32(alt_tab_timer) > ALT_TAB_DELAY) release_alt_tab(); // If the timer surpasses the delay, release alt tab
402 }
403 if (is_click_blocked) held_click_timer = timer_read32(); // To prevent mode changing when directionals are held
404 if (is_click_held && timer_elapsed32(held_click_timer) > ENCODER_CLICK_DELAY ){
405 automatic_encoder_mode_cycle = true;
406 held_click_timer = timer_read32();
407 if (is_shift_held) cycle_encoder_mode(false);
408 else cycle_encoder_mode(true);
409 }
410}
diff --git a/keyboards/evolv/rules.mk b/keyboards/evolv/rules.mk
index 5f5b97241..5b705106b 100644
--- a/keyboards/evolv/rules.mk
+++ b/keyboards/evolv/rules.mk
@@ -10,11 +10,11 @@ BOOTLOADER = stm32-dfu
10BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite 10BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
11MOUSEKEY_ENABLE = yes # Mouse keys 11MOUSEKEY_ENABLE = yes # Mouse keys
12EXTRAKEY_ENABLE = yes # Audio control and System control 12EXTRAKEY_ENABLE = yes # Audio control and System control
13CONSOLE_ENABLE = no # Console for debug 13CONSOLE_ENABLE = no # Console for debug
14COMMAND_ENABLE = no # Commands for debug and configuration 14COMMAND_ENABLE = no # Commands for debug and configuration
15NKRO_ENABLE = yes # Enable N-Key Rollover 15NKRO_ENABLE = yes # Enable N-Key Rollover
16BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality 16BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
17RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow 17RGBLIGHT_ENABLE = yes # Enable keyboard RGB underglow
18AUDIO_ENABLE = no # Audio output 18AUDIO_ENABLE = no # Audio output
19ENCODER_ENABLE = yes 19ENCODER_ENABLE = yes
20 20