forked from qmk/qmk_firmware
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Callum style layout improvements and my layout changes (qmk#16174)
- Loading branch information
1 parent
863e5c3
commit b424451
Showing
8 changed files
with
762 additions
and
386 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,336 @@ | ||
/* Copyright 2022 @daliusd | ||
* | ||
* This program is free software: you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation, either version 2 of the License, or | ||
* (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
* GNU General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public License | ||
* along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
#include "flow.h" | ||
|
||
extern const uint16_t flow_config[FLOW_COUNT][2]; | ||
extern const uint16_t flow_layers_config[FLOW_LAYERS_COUNT][2]; | ||
|
||
// Represents the states a flow key can be in | ||
typedef enum { | ||
flow_up_unqueued, | ||
flow_up_queued, | ||
flow_up_queued_used, | ||
flow_down_unused, | ||
flow_down_used, | ||
} flow_state_t; | ||
|
||
#ifdef FLOW_ONESHOT_TERM | ||
const int g_flow_oneshot_term = FLOW_ONESHOT_TERM; | ||
#else | ||
const int g_flow_oneshot_term = 500; | ||
#endif | ||
|
||
#ifdef FLOW_ONESHOT_WAIT_TERM | ||
const int g_flow_oneshot_wait_term = FLOW_ONESHOT_WAIT_TERM; | ||
#else | ||
const int g_flow_oneshot_wait_term = 500; | ||
#endif | ||
|
||
flow_state_t flow_state[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = flow_up_unqueued }; | ||
bool flow_pressed[FLOW_COUNT][2] = { [0 ... FLOW_COUNT - 1] = {false, false} }; | ||
uint16_t flow_timers[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = 0 }; | ||
bool flow_timeout_timers_active[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = false }; | ||
uint16_t flow_timeout_timers_value[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = 0 }; | ||
uint16_t flow_timeout_wait_timers_value[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = 0 }; | ||
|
||
flow_state_t flow_layers_state[FLOW_LAYERS_COUNT] = { | ||
[0 ... FLOW_LAYERS_COUNT - 1] = flow_up_unqueued | ||
}; | ||
bool flow_layer_timeout_timers_active[FLOW_LAYERS_COUNT] = { [0 ... FLOW_LAYERS_COUNT - 1] = false }; | ||
uint16_t flow_layer_timeout_timers_value[FLOW_LAYERS_COUNT] = { [0 ... FLOW_LAYERS_COUNT - 1] = 0 }; | ||
uint16_t flow_layer_timeout_wait_timers_value[FLOW_LAYERS_COUNT] = { [0 ... FLOW_LAYERS_COUNT - 1] = 0 }; | ||
|
||
bool is_flow_ignored_key(uint16_t keycode) { | ||
for (int i = 0; i < FLOW_COUNT; i++) { | ||
if (flow_config[i][0] == keycode) { | ||
return true; | ||
} | ||
} | ||
|
||
for (int i = 0; i < FLOW_LAYERS_COUNT; i++) { | ||
if (flow_layers_config[i][0] == keycode) { | ||
return true; | ||
} | ||
} | ||
|
||
if (keycode == KC_LSFT || keycode == KC_RSFT | ||
|| keycode == KC_LCTL || keycode == KC_RCTL | ||
|| keycode == KC_LALT || keycode == KC_RALT | ||
|| keycode == KC_LGUI || keycode == KC_RGUI) { | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
bool update_flow_mods( | ||
uint16_t keycode, | ||
bool pressed | ||
) { | ||
bool pass = true; | ||
bool flow_key_list_triggered[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = false }; | ||
bool flow_key_list_pressed[FLOW_COUNT] = { [0 ... FLOW_COUNT - 1] = false }; | ||
|
||
bool flow_triggered = false; | ||
|
||
for (uint8_t i = 0; i < FLOW_COUNT; i++) { | ||
// Layer key | ||
if (keycode == flow_config[i][0]) { | ||
if (pressed) { | ||
flow_pressed[i][0] = true; | ||
} else { | ||
flow_pressed[i][0] = false; | ||
} | ||
// KC mod key | ||
} else if (keycode == flow_config[i][1]) { | ||
if (pressed) { | ||
if (flow_pressed[i][0]) { | ||
flow_pressed[i][1] = true; | ||
flow_key_list_triggered[i] = true; | ||
flow_triggered = true; | ||
flow_key_list_pressed[i] = true; | ||
pass = false; | ||
} | ||
} else if (flow_pressed[i][1]) { | ||
flow_pressed[i][1] = false; | ||
if (flow_pressed[i][0]) { | ||
flow_key_list_triggered[i] = true; | ||
flow_triggered = true; | ||
pass = false; | ||
} else if ((flow_state[i] == flow_down_unused) | ||
|| (flow_state[i] == flow_down_used)) { | ||
flow_key_list_triggered[i] = true; | ||
flow_triggered = true; | ||
pass = false; | ||
} | ||
} | ||
} | ||
} | ||
|
||
for (uint8_t i = 0; i < FLOW_COUNT; i++) { | ||
if (flow_key_list_triggered[i]) { | ||
if (flow_key_list_pressed[i]) { | ||
if (flow_state[i] == flow_up_unqueued) { | ||
register_code(flow_config[i][1]); | ||
} | ||
flow_timeout_wait_timers_value[i] = timer_read(); | ||
flow_state[i] = flow_down_unused; | ||
} else { | ||
// Trigger keyup | ||
switch (flow_state[i]) { | ||
case flow_down_unused: | ||
if (!flow_pressed[i][1]) { | ||
if (timer_elapsed(flow_timeout_wait_timers_value[i]) > g_flow_oneshot_wait_term) { | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
} else { | ||
// If we didn't use the mod while trigger was held, queue it. | ||
flow_state[i] = flow_up_queued; | ||
flow_timeout_timers_active[i] = true; | ||
flow_timeout_timers_value[i] = timer_read(); | ||
} | ||
} | ||
break; | ||
case flow_down_used: | ||
// If we did use the mod while trigger was held, unregister it. | ||
if (!flow_pressed[i][1]) { | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
} | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} else if (!flow_triggered) { | ||
if (pressed) { | ||
if (!is_flow_ignored_key(keycode)) { | ||
switch (flow_state[i]) { | ||
case flow_up_queued: | ||
flow_state[i] = flow_up_queued_used; | ||
flow_timeout_timers_active[i] = false; | ||
break; | ||
case flow_up_queued_used: | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} else { | ||
if (!is_flow_ignored_key(keycode)) { | ||
// On non-ignored keyup, consider the oneshot used. | ||
switch (flow_state[i]) { | ||
case flow_down_unused: | ||
flow_state[i] = flow_down_used; | ||
break; | ||
case flow_up_queued: | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
break; | ||
case flow_up_queued_used: | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return pass; | ||
} | ||
|
||
void change_pressed_status(uint16_t keycode, bool pressed) { | ||
for (int i = 0; i < FLOW_COUNT; i++) { | ||
if (flow_config[i][0] == keycode) { | ||
flow_pressed[i][0] = pressed; | ||
} | ||
} | ||
} | ||
|
||
bool update_flow_layers( | ||
uint16_t keycode, | ||
bool pressed, | ||
keypos_t key_position | ||
) { | ||
uint8_t key_layer = read_source_layers_cache(key_position); | ||
bool pass = true; | ||
|
||
for (int i = 0; i < FLOW_LAYERS_COUNT; i++) { | ||
uint16_t trigger = flow_layers_config[i][0]; | ||
uint16_t layer = flow_layers_config[i][1]; | ||
|
||
if (keycode == trigger) { | ||
if (pressed) { | ||
// Trigger keydown | ||
if (flow_layers_state[i] == flow_up_unqueued) { | ||
layer_on(layer); | ||
change_pressed_status(trigger, true); | ||
} | ||
flow_layer_timeout_wait_timers_value[i] = timer_read(); | ||
flow_layers_state[i] = flow_down_unused; | ||
pass = false; | ||
} else { | ||
// Trigger keyup | ||
switch (flow_layers_state[i]) { | ||
case flow_down_unused: | ||
if (timer_elapsed(flow_layer_timeout_wait_timers_value[i]) > g_flow_oneshot_wait_term) { | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(layer); | ||
change_pressed_status(trigger, false); | ||
pass = false; | ||
} else { | ||
// If we didn't use the layer while trigger was held, queue it. | ||
flow_layers_state[i] = flow_up_queued; | ||
flow_layer_timeout_timers_active[i] = true; | ||
flow_layer_timeout_timers_value[i] = timer_read(); | ||
pass = false; | ||
change_pressed_status(trigger, true); | ||
} | ||
break; | ||
case flow_down_used: | ||
// If we did use the layer while trigger was held, turn off it. | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(layer); | ||
change_pressed_status(trigger, false); | ||
pass = false; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} else { | ||
if (pressed) { | ||
if (key_layer == layer) { | ||
// On non-ignored keyup, consider the oneshot used. | ||
switch (flow_layers_state[i]) { | ||
case flow_down_unused: | ||
flow_layers_state[i] = flow_down_used; | ||
break; | ||
case flow_up_queued: | ||
flow_layers_state[i] = flow_up_queued_used; | ||
flow_layer_timeout_timers_active[i] = false; | ||
break; | ||
case flow_up_queued_used: | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(layer); | ||
change_pressed_status(trigger, false); | ||
pass = false; | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} else { | ||
// Ignore key ups from other layers | ||
if (key_layer == layer) { | ||
// On non-ignored keyup, consider the oneshot used. | ||
switch (flow_layers_state[i]) { | ||
case flow_up_queued: | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(layer); | ||
change_pressed_status(trigger, false); | ||
break; | ||
case flow_up_queued_used: | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(layer); | ||
change_pressed_status(trigger, false); | ||
break; | ||
default: | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return pass; | ||
} | ||
|
||
bool update_flow( | ||
uint16_t keycode, | ||
bool pressed, | ||
keypos_t key_position | ||
) { | ||
bool pass = update_flow_mods(keycode, pressed); | ||
pass = update_flow_layers(keycode, pressed, key_position) & pass; | ||
return pass; | ||
} | ||
|
||
void flow_matrix_scan(void) { | ||
for (int i = 0; i < FLOW_COUNT; i++) { | ||
if (flow_timeout_timers_active[i] | ||
&& timer_elapsed(flow_timeout_timers_value[i]) > g_flow_oneshot_term) { | ||
flow_timeout_timers_active[i] = false; | ||
flow_state[i] = flow_up_unqueued; | ||
unregister_code(flow_config[i][1]); | ||
} | ||
} | ||
|
||
for (int i = 0; i < FLOW_LAYERS_COUNT; i++) { | ||
if (flow_layer_timeout_timers_active[i] | ||
&& timer_elapsed(flow_layer_timeout_timers_value[i]) > g_flow_oneshot_term) { | ||
flow_layer_timeout_timers_active[i] = false; | ||
flow_layers_state[i] = flow_up_unqueued; | ||
layer_off(flow_layers_config[i][1]); | ||
change_pressed_status(flow_layers_config[i][0], false); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
/* | ||
Copyright 2022 Dalius Dobravolskas <[email protected]> | ||
This program is free software: you can redistribute it and/or modify | ||
it under the terms of the GNU General Public License as published by | ||
the Free Software Foundation, either version 2 of the License, or | ||
(at your option) any later version. | ||
This program is distributed in the hope that it will be useful, | ||
but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
GNU General Public License for more details. | ||
You should have received a copy of the GNU General Public License | ||
along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
*/ | ||
#pragma once | ||
|
||
#include QMK_KEYBOARD_H | ||
|
||
bool update_flow( | ||
uint16_t keycode, | ||
bool pressed, | ||
keypos_t key_position | ||
); | ||
|
||
void flow_matrix_scan(void); |
Oops, something went wrong.