begin major refactor to replace the layer stack
parent
ccd324d972
commit
447f1fb2cb
|
@ -6,7 +6,6 @@
|
|||
* Project located at <https://github.com/benblazak/ergodox-firmware>
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../../lib-other/pjrc/usb_keyboard/usb_keyboard.h"
|
||||
|
@ -59,103 +58,73 @@ static const uint16_t _media_code_lookup_table[] = {
|
|||
* the end of the current cycle (see main.c)
|
||||
*/
|
||||
void _kbfun_press_release(bool press, uint8_t keycode) {
|
||||
// no-op
|
||||
if (keycode == 0)
|
||||
return;
|
||||
// no-op
|
||||
if (keycode == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// modifier keys
|
||||
switch (keycode) {
|
||||
case KEY_LeftControl: (press)
|
||||
? (keyboard_modifier_keys |= (1<<0))
|
||||
: (keyboard_modifier_keys &= ~(1<<0));
|
||||
return;
|
||||
case KEY_LeftShift: (press)
|
||||
? (keyboard_modifier_keys |= (1<<1))
|
||||
: (keyboard_modifier_keys &= ~(1<<1));
|
||||
return;
|
||||
case KEY_LeftAlt: (press)
|
||||
? (keyboard_modifier_keys |= (1<<2))
|
||||
: (keyboard_modifier_keys &= ~(1<<2));
|
||||
return;
|
||||
case KEY_LeftGUI: (press)
|
||||
? (keyboard_modifier_keys |= (1<<3))
|
||||
: (keyboard_modifier_keys &= ~(1<<3));
|
||||
return;
|
||||
case KEY_RightControl: (press)
|
||||
? (keyboard_modifier_keys |= (1<<4))
|
||||
: (keyboard_modifier_keys &= ~(1<<4));
|
||||
return;
|
||||
case KEY_RightShift: (press)
|
||||
? (keyboard_modifier_keys |= (1<<5))
|
||||
: (keyboard_modifier_keys &= ~(1<<5));
|
||||
return;
|
||||
case KEY_RightAlt: (press)
|
||||
? (keyboard_modifier_keys |= (1<<6))
|
||||
: (keyboard_modifier_keys &= ~(1<<6));
|
||||
return;
|
||||
case KEY_RightGUI: (press)
|
||||
? (keyboard_modifier_keys |= (1<<7))
|
||||
: (keyboard_modifier_keys &= ~(1<<7));
|
||||
return;
|
||||
}
|
||||
// modifier keys
|
||||
switch (keycode) {
|
||||
case KEY_LeftControl: (press) ? (keyboard_modifier_keys |= (1<<0)) : (keyboard_modifier_keys &= ~(1<<0)); return;
|
||||
case KEY_LeftShift: (press) ? (keyboard_modifier_keys |= (1<<1)) : (keyboard_modifier_keys &= ~(1<<1)); return;
|
||||
case KEY_LeftAlt: (press) ? (keyboard_modifier_keys |= (1<<2)) : (keyboard_modifier_keys &= ~(1<<2)); return;
|
||||
case KEY_LeftGUI: (press) ? (keyboard_modifier_keys |= (1<<3)) : (keyboard_modifier_keys &= ~(1<<3)); return;
|
||||
case KEY_RightControl: (press) ? (keyboard_modifier_keys |= (1<<4)) : (keyboard_modifier_keys &= ~(1<<4)); return;
|
||||
case KEY_RightShift: (press) ? (keyboard_modifier_keys |= (1<<5)) : (keyboard_modifier_keys &= ~(1<<5)); return;
|
||||
case KEY_RightAlt: (press) ? (keyboard_modifier_keys |= (1<<6)) : (keyboard_modifier_keys &= ~(1<<6)); return;
|
||||
case KEY_RightGUI: (press) ? (keyboard_modifier_keys |= (1<<7)) : (keyboard_modifier_keys &= ~(1<<7)); return;
|
||||
}
|
||||
|
||||
// all others
|
||||
for (uint8_t i=0; i<6; i++) {
|
||||
if (press) {
|
||||
if (keyboard_keys[i] == 0) {
|
||||
keyboard_keys[i] = keycode;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (keyboard_keys[i] == keycode) {
|
||||
keyboard_keys[i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// all others
|
||||
for (uint8_t i=0; i<6; i++) {
|
||||
if (press) {
|
||||
if (keyboard_keys[i] == 0) {
|
||||
keyboard_keys[i] = keycode;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (keyboard_keys[i] == keycode) {
|
||||
keyboard_keys[i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the given keycode pressed?
|
||||
*/
|
||||
bool _kbfun_is_pressed(uint8_t keycode) {
|
||||
// modifier keys
|
||||
switch (keycode) {
|
||||
case KEY_LeftControl: if (keyboard_modifier_keys & (1<<0))
|
||||
return true;
|
||||
case KEY_LeftShift: if (keyboard_modifier_keys & (1<<1))
|
||||
return true;
|
||||
case KEY_LeftAlt: if (keyboard_modifier_keys & (1<<2))
|
||||
return true;
|
||||
case KEY_LeftGUI: if (keyboard_modifier_keys & (1<<3))
|
||||
return true;
|
||||
case KEY_RightControl: if (keyboard_modifier_keys & (1<<4))
|
||||
return true;
|
||||
case KEY_RightShift: if (keyboard_modifier_keys & (1<<5))
|
||||
return true;
|
||||
case KEY_RightAlt: if (keyboard_modifier_keys & (1<<6))
|
||||
return true;
|
||||
case KEY_RightGUI: if (keyboard_modifier_keys & (1<<7))
|
||||
return true;
|
||||
}
|
||||
// modifier keys
|
||||
switch (keycode) {
|
||||
case KEY_LeftControl: if (keyboard_modifier_keys & (1<<0)) { return true; }
|
||||
case KEY_LeftShift: if (keyboard_modifier_keys & (1<<1)) { return true; }
|
||||
case KEY_LeftAlt: if (keyboard_modifier_keys & (1<<2)) { return true; }
|
||||
case KEY_LeftGUI: if (keyboard_modifier_keys & (1<<3)) { return true; }
|
||||
case KEY_RightControl: if (keyboard_modifier_keys & (1<<4)) { return true; }
|
||||
case KEY_RightShift: if (keyboard_modifier_keys & (1<<5)) { return true; }
|
||||
case KEY_RightAlt: if (keyboard_modifier_keys & (1<<6)) { return true; }
|
||||
case KEY_RightGUI: if (keyboard_modifier_keys & (1<<7)) { return true; }
|
||||
}
|
||||
|
||||
// all others
|
||||
for (uint8_t i=0; i<6; i++)
|
||||
if (keyboard_keys[i] == keycode)
|
||||
return true;
|
||||
// all others
|
||||
for (uint8_t i=0; i<6; i++)
|
||||
if (keyboard_keys[i] == keycode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
void _kbfun_mediakey_press_release(bool press, uint8_t keycode) {
|
||||
uint16_t mediakey_code = _media_code_lookup_table[keycode];
|
||||
if (press) {
|
||||
consumer_key = mediakey_code;
|
||||
} else {
|
||||
// Only one key can be pressed at a time so only clear the keypress for
|
||||
// active key (most recently pressed)
|
||||
if (mediakey_code == consumer_key) {
|
||||
consumer_key = 0;
|
||||
}
|
||||
}
|
||||
uint16_t mediakey_code = _media_code_lookup_table[keycode];
|
||||
if (press) {
|
||||
consumer_key = mediakey_code;
|
||||
} else {
|
||||
// Only one key can be pressed at a time so only clear the keypress for
|
||||
// active key (most recently pressed)
|
||||
if (mediakey_code == consumer_key) {
|
||||
consumer_key = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,17 +11,16 @@
|
|||
|
||||
|
||||
#ifndef LIB__KEY_FUNCTIONS__INTERNAL_h
|
||||
#define LIB__KEY_FUNCTIONS__INTERNAL_h
|
||||
#define LIB__KEY_FUNCTIONS__INTERNAL_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../../keyboard/matrix.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "../../keyboard/matrix.h"
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
void _kbfun_press_release (bool press, uint8_t keycode);
|
||||
bool _kbfun_is_pressed (uint8_t keycode);
|
||||
void _kbfun_mediakey_press_release (bool press, uint8_t keycode);
|
||||
void _kbfun_press_release (bool press, uint8_t keycode);
|
||||
bool _kbfun_is_pressed (uint8_t keycode);
|
||||
void _kbfun_mediakey_press_release (bool press, uint8_t keycode);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -8,58 +8,43 @@
|
|||
|
||||
|
||||
#ifndef LIB__KEY_FUNCTIONS__COMMON_h
|
||||
#define LIB__KEY_FUNCTIONS__COMMON_h
|
||||
#define LIB__KEY_FUNCTIONS__COMMON_h
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// basic
|
||||
void kbfun_press_release (void);
|
||||
void kbfun_press_release_preserve_sticky (void);
|
||||
void kbfun_toggle (void);
|
||||
void kbfun_transparent (void);
|
||||
// --- layer push/pop functions
|
||||
void kbfun_layer_push_1 (void);
|
||||
void kbfun_layer_push_2 (void);
|
||||
void kbfun_layer_push_3 (void);
|
||||
void kbfun_layer_push_4 (void);
|
||||
void kbfun_layer_push_5 (void);
|
||||
void kbfun_layer_push_6 (void);
|
||||
void kbfun_layer_push_7 (void);
|
||||
void kbfun_layer_push_8 (void);
|
||||
void kbfun_layer_push_9 (void);
|
||||
void kbfun_layer_push_10 (void);
|
||||
void kbfun_layer_sticky_1 (void);
|
||||
void kbfun_layer_sticky_2 (void);
|
||||
void kbfun_layer_sticky_3 (void);
|
||||
void kbfun_layer_sticky_4 (void);
|
||||
void kbfun_layer_sticky_5 (void);
|
||||
void kbfun_layer_sticky_6 (void);
|
||||
void kbfun_layer_sticky_7 (void);
|
||||
void kbfun_layer_sticky_8 (void);
|
||||
void kbfun_layer_sticky_9 (void);
|
||||
void kbfun_layer_sticky_10 (void);
|
||||
void kbfun_layer_pop_1 (void);
|
||||
void kbfun_layer_pop_2 (void);
|
||||
void kbfun_layer_pop_3 (void);
|
||||
void kbfun_layer_pop_4 (void);
|
||||
void kbfun_layer_pop_5 (void);
|
||||
void kbfun_layer_pop_6 (void);
|
||||
void kbfun_layer_pop_7 (void);
|
||||
void kbfun_layer_pop_8 (void);
|
||||
void kbfun_layer_pop_9 (void);
|
||||
void kbfun_layer_pop_10 (void);
|
||||
// ---
|
||||
// basic
|
||||
void kbfun_press_release (void);
|
||||
void kbfun_press_release_preserve_sticky (void);
|
||||
void kbfun_toggle (void);
|
||||
void kbfun_transparent (void);
|
||||
|
||||
// device
|
||||
void kbfun_jump_to_bootloader (void);
|
||||
// layer push/pop functions
|
||||
#define simple_layer(n) \
|
||||
void kbfun_layer_push_##n (void); \
|
||||
void kbfun_layer_sticky_##n (void); \
|
||||
void kbfun_layer_pop_##n (void);
|
||||
|
||||
// special
|
||||
void kbfun_shift_press_release (void);
|
||||
void kbfun_control_press_release (void);
|
||||
void kbfun_2_keys_capslock_press_release (void);
|
||||
void kbfun_mediakey_press_release (void);
|
||||
simple_layer(1);
|
||||
simple_layer(2);
|
||||
simple_layer(3);
|
||||
simple_layer(4);
|
||||
simple_layer(5);
|
||||
simple_layer(6);
|
||||
simple_layer(7);
|
||||
simple_layer(8);
|
||||
simple_layer(9);
|
||||
simple_layer(10);
|
||||
|
||||
// device
|
||||
void kbfun_jump_to_bootloader (void);
|
||||
|
||||
// special
|
||||
void kbfun_shift_press_release (void);
|
||||
void kbfun_control_press_release (void);
|
||||
void kbfun_2_keys_capslock_press_release (void);
|
||||
void kbfun_mediakey_press_release (void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -12,12 +12,8 @@
|
|||
#include "../public.h"
|
||||
#include "../private.h"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#define MAX_LAYER_PUSH_POP_FUNCTIONS 10
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// convenience macros
|
||||
#define LAYER main_arg_layer
|
||||
#define LAYER_OFFSET main_arg_layer_offset
|
||||
|
@ -26,71 +22,55 @@
|
|||
#define IS_PRESSED main_arg_is_pressed
|
||||
#define WAS_PRESSED main_arg_was_pressed
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Press|Release
|
||||
*
|
||||
* [description]
|
||||
* Generate a normal keypress or keyrelease
|
||||
* Generate a normal keypress or keyrelease
|
||||
*/
|
||||
void kbfun_press_release(void) {
|
||||
if (!main_arg_trans_key_pressed)
|
||||
main_arg_any_non_trans_key_pressed = true;
|
||||
kbfun_press_release_preserve_sticky();
|
||||
if (!main_arg_trans_key_pressed) {
|
||||
main_arg_any_non_trans_key_pressed = true;
|
||||
}
|
||||
kbfun_press_release_preserve_sticky();
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Press|Release and preserve top layer sticky key state
|
||||
*
|
||||
* [description]
|
||||
* Generate a normal keypress or keyrelease
|
||||
* While basing the sticky key state transition on whether
|
||||
* kbfun_press_release() was called after kbfun_transparent() generally
|
||||
* works in practice, it is not always the desired behavior. One of the
|
||||
* benefits of sticky keys is avoiding key chording, so we want to make sure
|
||||
* that standard modifiers do not interrupt the sticky key cycle. Use
|
||||
* kbfun_press_release_preserve_sticky() if you want to define a standard
|
||||
* modifier key (shift, control, alt, gui) on the sticky layer instead of
|
||||
* defining the key to be transparent for the layer.
|
||||
* Generate a normal keypress or keyrelease
|
||||
* While basing the sticky key state transition on whether
|
||||
* kbfun_press_release() was called after kbfun_transparent() generally
|
||||
* works in practice, it is not always the desired behavior. One of the
|
||||
* benefits of sticky keys is avoiding key chording, so we want to make sure
|
||||
* that standard modifiers do not interrupt the sticky key cycle. Use
|
||||
* kbfun_press_release_preserve_sticky() if you want to define a standard
|
||||
* modifier key (shift, control, alt, gui) on the sticky layer instead of
|
||||
* defining the key to be transparent for the layer.
|
||||
*/
|
||||
void kbfun_press_release_preserve_sticky(void) {
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
_kbfun_press_release(IS_PRESSED, keycode);
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
_kbfun_press_release(IS_PRESSED, keycode);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Toggle
|
||||
*
|
||||
* [description]
|
||||
* Toggle the key pressed or unpressed
|
||||
* Toggle the key pressed or unpressed
|
||||
*/
|
||||
void kbfun_toggle(void) {
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
|
||||
if (_kbfun_is_pressed(keycode))
|
||||
_kbfun_press_release(false, keycode);
|
||||
else
|
||||
_kbfun_press_release(true, keycode);
|
||||
if (_kbfun_is_pressed(keycode)) {
|
||||
_kbfun_press_release(false, keycode);
|
||||
} else {
|
||||
_kbfun_press_release(true, keycode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Transparent
|
||||
*
|
||||
* [description]
|
||||
* Execute the key that would have been executed if the current layer was not
|
||||
* active
|
||||
* Execute the key that would have been executed if the current layer was not
|
||||
* active
|
||||
*/
|
||||
void kbfun_transparent(void) {
|
||||
main_arg_trans_key_pressed = true;
|
||||
LAYER_OFFSET++;
|
||||
LAYER = main_layers_peek(LAYER_OFFSET);
|
||||
main_layers_pressed[ROW][COL] = LAYER;
|
||||
main_exec_key();
|
||||
main_arg_trans_key_pressed = true;
|
||||
LAYER_OFFSET++;
|
||||
LAYER = main_layers_peek(LAYER_OFFSET);
|
||||
main_layers_pressed[ROW][COL] = LAYER;
|
||||
main_exec_key();
|
||||
}
|
||||
|
||||
|
||||
|
@ -98,457 +78,121 @@ void kbfun_transparent(void) {
|
|||
* layer push/pop functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
// While there are only MAX_LAYER_PUSH_POP_FUNCTIONS number of layer functions,
|
||||
// there are 1 + MAX_LAYER_PUSH_POP_FUNCTIONS layer ids because we still have
|
||||
// layer 0 even if we will never have a push or pop function for it
|
||||
/*
|
||||
* While there are only MAX_LAYER_PUSH_POP_FUNCTIONS number of layer functions,
|
||||
* there are 1 + MAX_LAYER_PUSH_POP_FUNCTIONS layer ids because we still have
|
||||
* layer 0 even if we will never have a push or pop function for it
|
||||
*/
|
||||
static uint8_t layer_ids[1 + MAX_LAYER_PUSH_POP_FUNCTIONS];
|
||||
|
||||
/*
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
static void layer_push(uint8_t local_id) {
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
// Only the topmost layer on the stack should be in sticky once state, pop
|
||||
// the top layer if it is in sticky once state
|
||||
uint8_t topSticky = main_layers_peek_sticky(0);
|
||||
if (topSticky == eStickyOnceDown || topSticky == eStickyOnceUp) {
|
||||
main_layers_pop_id(main_layers_peek(0));
|
||||
}
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyNone);
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
// Only the topmost layer on the stack should be in sticky once state, pop
|
||||
// the top layer if it is in sticky once state
|
||||
uint8_t topSticky = main_layers_top_sticky();
|
||||
if (topSticky == eStickyOnceDown || topSticky == eStickyOnceUp) {
|
||||
main_layers_pop_id(main_layers_top_layer());
|
||||
}
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyNone);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function gives similar behavior to sticky keys for modifiers available
|
||||
* on most operating systems. It is considered an accessibility feature
|
||||
* because it alleviates the user from having to hold down modifiers while
|
||||
* pressing a key to produce the modified key function. It is useful for fast
|
||||
* touch typing because you can avoid chording motions which both strain your
|
||||
* hands and take your hands out of home-row position while pressing normal
|
||||
* alpha keys.
|
||||
* This function emulates the 3-state behavior which is default on OS X and
|
||||
* optional in Windows where the modifier cycles between Off->Once->Locked
|
||||
* states. This is particularly handy for symbol layers where you typically
|
||||
* only type one symbol before you want to return to unmodified typing (layer
|
||||
* 0), e.g. 'if (condition) { a = "b" + "c"; }'. If you assign a symbol layer
|
||||
* to a thumb key as a layer sticky cycle, you can type the entire line of
|
||||
* code without taking your hands out of home row position and you do not need
|
||||
* to toggle off the layer after each symbol is pressed, only immediately
|
||||
* before keying the symbol.
|
||||
* The exact behavior of the layer sticky cycle function is defined as follows
|
||||
* for each state:
|
||||
* 1) One time down (set on key press) - The layer was not active and the key
|
||||
* has been pressed but not yet released. The layer is pushed in the one
|
||||
* time down state.
|
||||
* 2) One time up (set on key release) - The layer was active when the layer
|
||||
* sticky key was released. If a key on this layer (not set to
|
||||
* transparent) was pressed before the key was released, the layer will be
|
||||
* popped. If a non-transparent key was not pressed, the layer is popped
|
||||
* and pushed again in the one time up state.
|
||||
* 3) Locked (set on key press) - The layer was active and in the one time up
|
||||
* state when the layer sticky key was pressed again. The layer will be
|
||||
* popped if the function is invoked on a subsequent keypress.
|
||||
*/
|
||||
static void layer_sticky(uint8_t local_id) {
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
if (IS_PRESSED) {
|
||||
uint8_t topLayer = main_layers_peek(0);
|
||||
uint8_t topSticky = main_layers_peek_sticky(0);
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
if (topLayer == local_id) {
|
||||
if (topSticky == eStickyOnceUp)
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
// only the topmost layer on the stack should be in sticky once state
|
||||
if (topSticky == eStickyOnceDown || topSticky == eStickyOnceUp) {
|
||||
main_layers_pop_id(layer_ids[topLayer]);
|
||||
}
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyOnceDown);
|
||||
// this should be the only place we care about this flag being cleared
|
||||
main_arg_any_non_trans_key_pressed = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t topLayer = main_layers_peek(0);
|
||||
uint8_t topSticky = main_layers_peek_sticky(0);
|
||||
if (topLayer == local_id) {
|
||||
if (topSticky == eStickyOnceDown) {
|
||||
// When releasing this sticky key, pop the layer always
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
if (!main_arg_any_non_trans_key_pressed) {
|
||||
// If no key defined for this layer (a non-transparent key)
|
||||
// was pressed, push the layer again, but in the
|
||||
// StickyOnceUp state
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyOnceUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
|
||||
if (IS_PRESSED) {
|
||||
uint8_t topLayer = main_layers_top_layer();
|
||||
uint8_t topSticky = main_layers_top_sticky();
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
if (topLayer == local_id) {
|
||||
if (topSticky == eStickyOnceUp) {
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyLock);
|
||||
}
|
||||
} else {
|
||||
// only the topmost layer on the stack should be in sticky once state
|
||||
if (topSticky == eStickyOnceDown || topSticky == eStickyOnceUp) {
|
||||
main_layers_pop_id(layer_ids[topLayer]);
|
||||
}
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyOnceDown);
|
||||
// this should be the only place we care about this flag being cleared
|
||||
main_arg_any_non_trans_key_pressed = false;
|
||||
}
|
||||
} else {
|
||||
uint8_t topLayer = main_layers_top_layer();
|
||||
uint8_t topSticky = main_layers_top_sticky();
|
||||
if (topLayer == local_id) {
|
||||
if (topSticky == eStickyOnceDown) {
|
||||
// When releasing this sticky key, pop the layer always
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
if (!main_arg_any_non_trans_key_pressed) {
|
||||
// If no key defined for this layer (a non-transparent key)
|
||||
// was pressed, push the layer again, but in the
|
||||
// StickyOnceUp state
|
||||
layer_ids[local_id] = main_layers_push(keycode, eStickyOnceUp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
static void layer_pop(uint8_t local_id) {
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
layer_ids[local_id] = 0;
|
||||
main_layers_pop_id(layer_ids[local_id]);
|
||||
layer_ids[local_id] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #1
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_1(void) {
|
||||
layer_push(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #1
|
||||
*
|
||||
* [description]
|
||||
* This function gives similar behavior to sticky keys for modifiers available
|
||||
* on most operating systems. It is considered an accessibility feature
|
||||
* because it alleviates the user from having to hold down modifiers while
|
||||
* pressing a key to produce the modified key function. It is useful for fast
|
||||
* touch typing because you can avoid chording motions which both strain your
|
||||
* hands and take your hands out of home-row position while pressing normal
|
||||
* alpha keys.
|
||||
* This function emulates the 3-state behavior which is default on OS X and
|
||||
* optional in Windows where the modifier cycles between Off->Once->Locked
|
||||
* states. This is particularly handy for symbol layers where you typically
|
||||
* only type one symbol before you want to return to unmodified typing (layer
|
||||
* 0), e.g. 'if (condition) { a = "b" + "c"; }'. If you assign a symbol layer
|
||||
* to a thumb key as a layer sticky cycle, you can type the entire line of
|
||||
* code without taking your hands out of home row position and you do not need
|
||||
* to toggle off the layer after each symbol is pressed, only immediately
|
||||
* before keying the symbol.
|
||||
* The exact behavior of the layer sticky cycle function is defined as follows
|
||||
* for each state:
|
||||
* 1) One time down (set on key press) - The layer was not active and the key
|
||||
* has been pressed but not yet released. The layer is pushed in the one
|
||||
* time down state.
|
||||
* 2) One time up (set on key release) - The layer was active when the layer
|
||||
* sticky key was released. If a key on this layer (not set to
|
||||
* transparent) was pressed before the key was released, the layer will be
|
||||
* popped. If a non-transparent key was not pressed, the layer is popped
|
||||
* and pushed again in the one time up state.
|
||||
* 3) Locked (set on key press) - The layer was active and in the one time up
|
||||
* state when the layer sticky key was pressed again. The layer will be
|
||||
* popped if the function is invoked on a subsequent keypress.
|
||||
*/
|
||||
void kbfun_layer_sticky_1 (void) {
|
||||
layer_sticky(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #1
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_1(void) {
|
||||
layer_pop(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #2
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_2(void) {
|
||||
layer_push(2);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #2
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_2 (void) {
|
||||
layer_sticky(2);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #2
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_2(void) {
|
||||
layer_pop(2);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #3
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_3(void) {
|
||||
layer_push(3);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #3
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_3 (void) {
|
||||
layer_sticky(3);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #3
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_3(void) {
|
||||
layer_pop(3);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #4
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_4(void) {
|
||||
layer_push(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #4
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_4 (void) {
|
||||
layer_sticky(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #4
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_4(void) {
|
||||
layer_pop(4);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #5
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_5(void) {
|
||||
layer_push(5);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #5
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_5 (void) {
|
||||
layer_sticky(5);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #5
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_5(void) {
|
||||
layer_pop(5);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #6
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_6(void) {
|
||||
layer_push(6);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #6
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_6 (void) {
|
||||
layer_sticky(6);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #6
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_6(void) {
|
||||
layer_pop(6);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #7
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_7(void) {
|
||||
layer_push(7);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #7
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_7 (void) {
|
||||
layer_sticky(7);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #7
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_7(void) {
|
||||
layer_pop(7);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #8
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_8(void) {
|
||||
layer_push(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #8
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_8 (void) {
|
||||
layer_sticky(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #8
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_8(void) {
|
||||
layer_pop(8);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #9
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_9(void) {
|
||||
layer_push(9);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #9
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_9 (void) {
|
||||
layer_sticky(9);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #9
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_9(void) {
|
||||
layer_pop(9);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer push #10
|
||||
*
|
||||
* [description]
|
||||
* Push a layer element containing the layer value specified in the keymap to
|
||||
* the top of the stack, and record the id of that layer element
|
||||
*/
|
||||
void kbfun_layer_push_10(void) {
|
||||
layer_push(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer sticky cycle #10
|
||||
*
|
||||
* [description]
|
||||
* See the description of kbfun_layer_sticky_1()
|
||||
*/
|
||||
void kbfun_layer_sticky_10 (void) {
|
||||
layer_sticky(10);
|
||||
}
|
||||
|
||||
/*
|
||||
* [name]
|
||||
* Layer pop #10
|
||||
*
|
||||
* [description]
|
||||
* Pop the layer element created by the corresponding "layer push" function
|
||||
* out of the layer stack (no matter where it is in the stack, without
|
||||
* touching any other elements)
|
||||
*/
|
||||
void kbfun_layer_pop_10(void) {
|
||||
layer_pop(10);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ------------------------------------------------------------------------- */
|
||||
// push/pop functions for all layers
|
||||
|
||||
#define simple_layer(n) \
|
||||
void kbfun_layer_push_##n (void) { layer_push(n); } \
|
||||
void kbfun_layer_sticky_##n (void) { layer_sticky(n); } \
|
||||
void kbfun_layer_pop_##n (void) { layer_pop(n); }
|
||||
|
||||
simple_layer(1);
|
||||
simple_layer(2);
|
||||
simple_layer(3);
|
||||
simple_layer(4);
|
||||
simple_layer(5);
|
||||
simple_layer(6);
|
||||
simple_layer(7);
|
||||
simple_layer(8);
|
||||
simple_layer(9);
|
||||
simple_layer(10);
|
||||
|
|
119
src/main.c
119
src/main.c
|
@ -84,7 +84,7 @@ int main(void) {
|
|||
|
||||
if (main_arg_is_pressed != main_arg_was_pressed) {
|
||||
if (main_arg_is_pressed) {
|
||||
main_arg_layer = main_layers_peek(0);
|
||||
main_arg_layer = main_layers_top_layer();
|
||||
main_layers_pressed[row][col] = main_arg_layer;
|
||||
main_arg_trans_key_pressed = false;
|
||||
} else {
|
||||
|
@ -130,19 +130,56 @@ int main(void) {
|
|||
* Implemented as a fixed size stack.
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// new array version
|
||||
|
||||
struct layers {
|
||||
uint8_t layer;
|
||||
uint8_t id;
|
||||
uint8_t sticky;
|
||||
struct layer {
|
||||
bool active;
|
||||
uint8_t sticky;
|
||||
};
|
||||
|
||||
struct layer layers[KB_LAYERS];
|
||||
uint8_t layers_top = 0;
|
||||
|
||||
// old stack version
|
||||
|
||||
struct layer_stack {
|
||||
uint8_t layer;
|
||||
uint8_t id;
|
||||
uint8_t sticky;
|
||||
};
|
||||
|
||||
struct layer_stack layers_stack[MAX_ACTIVE_LAYERS];
|
||||
uint8_t layers_head = 0;
|
||||
uint8_t layers_ids_in_use[MAX_ACTIVE_LAYERS] = {true};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct layers layers[MAX_ACTIVE_LAYERS];
|
||||
uint8_t layers_head = 0;
|
||||
uint8_t layers_ids_in_use[MAX_ACTIVE_LAYERS] = {true};
|
||||
// return the highest active layer
|
||||
uint8_t main_layers_top_layer() {
|
||||
return layers_stack[layers_head].layer;
|
||||
}
|
||||
|
||||
// return if highest active layer is sticky
|
||||
uint8_t main_layers_top_sticky() {
|
||||
return layers_stack[layers_head].sticky;
|
||||
}
|
||||
|
||||
// disable the highest active layer
|
||||
void main_layers_disable_top() {
|
||||
main_layers_pop_id(layers_head);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* Exec key
|
||||
|
@ -155,13 +192,15 @@ void main_exec_key(void) {
|
|||
? kb_layout_press_get(main_arg_layer, main_arg_row, main_arg_col)
|
||||
: kb_layout_release_get(main_arg_layer, main_arg_row, main_arg_col) );
|
||||
|
||||
if (key_function)
|
||||
if (key_function) {
|
||||
(*key_function)();
|
||||
}
|
||||
|
||||
// If the current layer is in the sticky once up state and a key defined
|
||||
// for this layer (a non-transparent key) was pressed, pop the layer
|
||||
if (layers[layers_head].sticky == eStickyOnceUp && main_arg_any_non_trans_key_pressed)
|
||||
main_layers_pop_id(layers_head);
|
||||
if (main_layers_top_sticky() == eStickyOnceUp && main_arg_any_non_trans_key_pressed) {
|
||||
main_layers_disable_top();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -176,15 +215,7 @@ void main_exec_key(void) {
|
|||
*/
|
||||
uint8_t main_layers_peek(uint8_t offset) {
|
||||
if (offset <= layers_head) {
|
||||
return layers[layers_head - offset].layer;
|
||||
}
|
||||
|
||||
return 0; // default, or error
|
||||
}
|
||||
|
||||
uint8_t main_layers_peek_sticky(uint8_t offset) {
|
||||
if (offset <= layers_head) {
|
||||
return layers[layers_head - offset].sticky;
|
||||
return layers_stack[layers_head - offset].layer;
|
||||
}
|
||||
|
||||
return 0; // default, or error
|
||||
|
@ -205,11 +236,11 @@ uint8_t main_layers_push(uint8_t layer, uint8_t sticky) {
|
|||
for (uint8_t id=1; id<MAX_ACTIVE_LAYERS; id++) {
|
||||
// if one is found
|
||||
if (layers_ids_in_use[id] == false) {
|
||||
layers_ids_in_use[id] = true;
|
||||
layers_head++;
|
||||
layers[layers_head].layer = layer;
|
||||
layers[layers_head].id = id;
|
||||
layers[layers_head].sticky = sticky;
|
||||
layers_ids_in_use[id] = true;
|
||||
layers_head++;
|
||||
layers_stack[layers_head].layer = layer;
|
||||
layers_stack[layers_head].id = id;
|
||||
layers_stack[layers_head].sticky = sticky;
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
@ -227,44 +258,18 @@ void main_layers_pop_id(uint8_t id) {
|
|||
// look for the element with the id we want to pop
|
||||
for (uint8_t element=1; element<=layers_head; element++) {
|
||||
// if we find it
|
||||
if (layers[element].id == id) {
|
||||
if (layers_stack[element].id == id) {
|
||||
// move all layers above it down one
|
||||
for (; element<layers_head; element++) {
|
||||
layers[element].layer = layers[element+1].layer;
|
||||
layers[element].id = layers[element+1].id;
|
||||
layers_stack[element].layer = layers_stack[element+1].layer;
|
||||
layers_stack[element].id = layers_stack[element+1].id;
|
||||
}
|
||||
// reinitialize the topmost (now unused) slot
|
||||
layers[layers_head].layer = 0;
|
||||
layers[layers_head].id = 0;
|
||||
layers_stack[layers_head].layer = 0;
|
||||
layers_stack[layers_head].id = 0;
|
||||
// record keeping
|
||||
layers_ids_in_use[id] = false;
|
||||
layers_head--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* get_offset_id()
|
||||
*
|
||||
* Arguments
|
||||
* - 'id': the id of the element you want the offset of
|
||||
*
|
||||
* Returns
|
||||
* - success: the offset (down the stack from the head element) of the element
|
||||
* with the given id
|
||||
* - failure: 0 (default) (id unassigned)
|
||||
*/
|
||||
uint8_t main_layers_get_offset_id(uint8_t id) {
|
||||
// look for the element with the id we want to get the offset of
|
||||
for (uint8_t element=1; element<=layers_head; element++) {
|
||||
// if we find it
|
||||
if (layers[element].id == id) {
|
||||
return (layers_head - element);
|
||||
}
|
||||
}
|
||||
|
||||
return 0; // default, or error
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
|
12
src/main.h
12
src/main.h
|
@ -45,12 +45,12 @@
|
|||
|
||||
void main_exec_key (void);
|
||||
|
||||
uint8_t main_layers_peek (uint8_t offset);
|
||||
uint8_t main_layers_peek_sticky (uint8_t offset);
|
||||
uint8_t main_layers_push (uint8_t layer, uint8_t sticky);
|
||||
void main_layers_pop_id (uint8_t id);
|
||||
uint8_t main_layers_get_offset_id (uint8_t id);
|
||||
uint8_t main_layers_top_layer (void);
|
||||
uint8_t main_layers_top_sticky (void);
|
||||
|
||||
uint8_t main_layers_peek (uint8_t offset);
|
||||
uint8_t main_layers_push (uint8_t layer, uint8_t sticky);
|
||||
void main_layers_pop_id (uint8_t id);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue