// Persistent encoder modes: the current encoder mode is written into EEPROM memory, and retrieved at the keyboard initialization. This means the current encoder mode is persistent even if the keyboard is reset or turned off
#define PERSISTENT_ENCODER_MODES
#define ENCODER_MODE_CHANGE_DELAY 500
// Defining special keycodes
enumkeyboard_keycodes{
ECLICK=SAFE_RANGE,// Encoder click
ALTTABF,// ALT-TAB forward
ALTTABB,// ALT-TAB backwards
ALTTABC,// For alt-tab-click
ENCMUP,// Encoder mode up
ENCMDN,// Encoder mode down
NEW_SAFE_RANGE
};
// Creates sample keyevents and keyrecords to be used in the processing of the custom keycodes. Their time should be resampled everytime they are used; their cols and rows are set to be "impossible", that is, outside the normal key matrix bounds.
constkeyevent_tsample_pressed_keyevent={
.key=(keypos_t){.row=5,.col=13},
.pressed=true,
.time=0
};
keyrecord_tsample_pressed_keyrecord={
.event=sample_pressed_keyevent
};
constkeyevent_tsample_released_keyevent={
.key=(keypos_t){.row=5,.col=13},
.pressed=false,
.time=0
};
keyrecord_tsample_released_keyrecord={
.event=sample_released_keyevent
};
// tap_process_record_user calls process_record_user with the pressed and released sample keyrecords with a delay of MEDIA_KEY_DELAY. The idea is to allow custom keycodes a simulation of a key press and release, allowing them to be treated in process_record_user. This, in turn, allows the custom keycodes to be used both in the encoder callback and the keyboard keymap.
// process_special_keycode is a function that distinguishes between the native keycodes and the ones custom-defined here. Normal keycodes are tapped, while keycodes in the SAFE_RANGE - NEW_SAFE_RANGE interval are treated with tap_process_record_user.
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
boolautomatic_hold_cycle=false;// This flag registers if the encoder hold was automatically cycled
// 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.
// Checks if the encoder has been pressed; if so, sets the corresponding flag and starts the corresponding timer
if(record->event.pressed){
is_click_held=true;
held_click_timer=timer_read32();
// Checks if the encoder has been released: samples the duration of the encoder push; if this time was less than the encoder_click_delay, processes the clicked key. If it was bigger, processes the hold key. This behavior is adjusted using the ENCODER_MODE_CHANGE_DELAY macro. There is an exception made when automatic_hold_cycle is true; this means that the encoder push has been pressed enough to trigger a hold cycle. This case is taken care of in the housekeeping routine, where the held key is triggered and the timer reset. Hence the automatic_hold_cycle needs to be checked because without this check the function will trigger the clicked key after the hold cycle has been cycled more than once.
returntrue;// Skip all further processing of this key
caseKC_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.
if(record->event.pressed)is_lalt_pressed=true;
elseis_lalt_pressed=false;
returntrue;
caseENCMUP:
caseENCMDN:
if(record->event.pressed)cycle_encoder_mode(keycode==ENCMUP);// If keycode == ENCMUP the expression returns true and the cycle function cycles the modes forward. If not, then cycles backwards.
returnfalse;
caseALTTABF:
caseALTTABB:
if(record->event.pressed){
if(!is_alt_tab_active){
is_alt_tab_active=true;
register_code(KC_LALT);
}
tap_code16(keycode==ALTTABF?KC_TAB:S(KC_TAB));// Due to S(KC_TAB), the 16-bit tap_code16 is needed.
/* This piece of the code checks for the encoder push timer. If the encoder push interval was less than encoder_click_delay then it is automatically processed by process_record_user by triggering the current mode's click key. However, if the encoder push is held for more time than the defined delay, then the encoder hold "cycles", that is, gets activated and the timer needs to be reset. This does three things: