ergodox-firmware/src/main.c

518 lines
15 KiB
C
Raw Normal View History

/* ----------------------------------------------------------------------------
* main()
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
2016-06-14 00:31:20 +02:00
2016-06-12 01:51:39 +02:00
#include <stdbool.h>
#include <stdint.h>
2016-06-14 00:31:20 +02:00
// --------------------------------------------------------------------
// hardware
// --------------------------------------------------------------------
2016-06-14 00:42:34 +02:00
#define KBD_DEBUG // comment out to disable the debug interface completely
2016-06-12 01:58:43 +02:00
#include "./keyboard/controller.c"
2016-06-12 01:51:39 +02:00
#include "./keyboard/keyboard.h"
2016-06-12 02:31:58 +02:00
// --------------------------------------------------------------------
// types and forward declarations
2016-06-12 01:51:39 +02:00
// --------------------------------------------------------------------
2016-06-14 02:49:01 +02:00
typedef uint8_t u8;
typedef uint16_t u16;
2016-06-12 03:54:30 +02:00
2016-06-12 02:31:58 +02:00
typedef enum StickyState {
2016-06-12 05:39:06 +02:00
StickyNone,
StickyOnceDown,
StickyOnceUp,
2016-06-12 01:51:39 +02:00
} StickyState;
2016-06-14 02:49:01 +02:00
typedef u8 keycode;
typedef u16 media_keycode;
typedef u8 layer;
typedef void (*keyfunc)(void);
2016-06-12 02:31:58 +02:00
#include "./main.h"
2016-02-04 15:19:06 +01:00
2016-06-12 02:31:58 +02:00
// ----------------------------------------------------------------------------
// layout data
2016-06-12 02:31:58 +02:00
// ----------------------------------------------------------------------------
#include "./keyboard/layout.c"
// defines:
// #define KB_Layers #{Layers.size}
2016-06-14 02:49:01 +02:00
// static const keycode PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// static const keyfunc PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// static const keyfunc PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
2016-06-14 02:49:01 +02:00
2016-06-12 05:39:06 +02:00
static bool _kb_is_pressed[KB_ROWS][KB_COLUMNS];
static bool (*kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_is_pressed;
2016-06-12 02:31:58 +02:00
2016-06-12 05:39:06 +02:00
static bool _kb_was_pressed[KB_ROWS][KB_COLUMNS];
static bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_was_pressed;
2016-06-12 02:31:58 +02:00
2016-06-14 02:49:01 +02:00
static layer layers_pressed[KB_ROWS][KB_COLUMNS];
2016-06-12 02:31:58 +02:00
2016-06-14 02:49:01 +02:00
static layer current_layer;
static layer layer_offset;
static u8 current_row;
static u8 current_col;
static bool current_is_pressed;
2016-06-14 06:44:11 +02:00
static bool sticky_done;
2016-02-04 15:19:06 +01:00
2016-06-12 05:09:35 +02:00
static bool layers_active[KB_LAYERS];
static StickyState layers_sticky[KB_LAYERS];
2016-06-14 02:49:01 +02:00
static layer layers_top = 0;
2016-02-04 15:19:06 +01:00
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
int main() {
kb_init();
2016-02-04 05:38:18 +01:00
usb_init();
while (!usb_configured());
2016-02-04 15:19:06 +01:00
// initialize layers
2016-06-12 06:20:40 +02:00
init_layers();
2016-02-04 05:38:18 +01:00
2016-06-12 02:31:58 +02:00
// never return
main_key_loop();
2016-02-04 05:38:18 +01:00
return 0;
}
2016-06-12 06:26:27 +02:00
// --------------------------------------------------------------------------------------
void main_key_loop() {
for (;;) {
// swap `kb_is_pressed` and `kb_was_pressed`, then update
bool (*temp)[KB_ROWS][KB_COLUMNS] = kb_was_pressed;
kb_was_pressed = kb_is_pressed;
kb_is_pressed = temp;
kb_update_matrix(*kb_is_pressed);
2016-06-14 05:48:56 +02:00
// - execute key functions when their key changes state
2016-06-12 06:26:27 +02:00
// - keep track of which layers the keys were on when they were pressed
// (so they can be released using the function from that layer)
2016-06-14 02:49:01 +02:00
for (u8 row=0; row<KB_ROWS; row++) {
for (u8 col=0; col<KB_COLUMNS; col++) {
2016-06-12 06:26:27 +02:00
current_is_pressed = (*kb_is_pressed)[row][col];
bool was_pressed = (*kb_was_pressed)[row][col];
if (current_is_pressed != was_pressed) {
if (current_is_pressed) {
current_layer = layers_top;
layers_pressed[row][col] = current_layer;
} else {
2016-06-14 06:44:11 +02:00
current_layer = layers_pressed[row][col];
2016-06-12 06:26:27 +02:00
}
// set remaining vars, and "execute" key
current_row = row;
current_col = col;
layer_offset = 0;
exec_key();
}
}
}
// send the USB report (even if nothing's changed)
usb_keyboard_send();
usb_extra_consumer_send();
// debounce in ms; see keyswitch spec for necessary value
_delay_ms(5);
}
}
2016-06-14 05:48:56 +02:00
// execute the keypress or keyrelease function (if it exists) of the key at the current possition
void exec_key(void) {
void (*key_function)(void) =
( (current_is_pressed)
? kb_keyfunc_press(current_layer, current_row, current_col)
: kb_keyfunc_release(current_layer, current_row, current_col) );
if (key_function) { (*key_function)(); }
// FIXME
// 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
2016-06-14 06:44:11 +02:00
if (layer_top_sticky() == StickyOnceUp && sticky_done) {
2016-06-14 05:48:56 +02:00
layer_disable_top();
}
}
2016-02-04 15:19:06 +01:00
// ----------------------------------------------------------------------------
2016-02-04 10:38:07 +01:00
// layer functions
2016-02-04 10:59:15 +01:00
// ----------------------------------------------------------------------------
2016-06-12 06:20:40 +02:00
void init_layers() {
2016-06-14 02:49:01 +02:00
for (layer l=0; l < KB_LAYERS; l++) {
layers_active[l] = false;
layers_sticky[l] = StickyNone;
2016-06-12 02:31:58 +02:00
}
2016-06-12 05:09:35 +02:00
layers_active[0] = true;
2016-06-12 02:31:58 +02:00
}
2016-02-04 15:19:06 +01:00
2016-02-04 10:59:15 +01:00
// find highest active layer
2016-06-14 05:48:56 +02:00
layer highest_active_layer(layer offset) {
2016-02-04 15:52:43 +01:00
if (offset < layers_top) {
2016-06-14 02:49:01 +02:00
for (layer l = layers_top - offset; l > 0 && l < KB_LAYERS; l--) {
2016-06-12 05:09:35 +02:00
if (layers_active[l]) { return l; }
2016-02-04 10:59:15 +01:00
}
}
2016-02-04 10:59:15 +01:00
// the base layer is always active
return 0;
}
// return if highest active layer is sticky
2016-06-12 06:20:40 +02:00
StickyState layer_top_sticky() {
return layer_sticky(layers_top);
2016-02-06 15:31:54 +01:00
}
// return if layer is sticky
2016-06-14 02:49:01 +02:00
StickyState layer_sticky(layer l) {
if (l < KB_LAYERS) {
return layers_sticky[l];
2016-02-06 15:31:54 +01:00
}
2016-06-12 05:39:06 +02:00
return StickyNone;
2016-02-04 10:22:40 +01:00
}
2016-02-04 10:22:40 +01:00
// enable a layer
2016-06-14 02:49:01 +02:00
void layer_enable(layer l, StickyState sticky) {
2016-06-14 05:48:56 +02:00
// FIXME split off sticky part
2016-06-14 02:49:01 +02:00
if (l >= KB_LAYERS) { return; }
2016-02-04 15:52:43 +01:00
2016-06-14 02:49:01 +02:00
layers_active[l] = true;
layers_sticky[l] = sticky;
2016-06-14 02:49:01 +02:00
if (l > layers_top) {
layers_top = l;
2016-02-04 10:22:40 +01:00
}
}
2016-02-04 10:22:40 +01:00
// disable a layer
2016-06-14 02:49:01 +02:00
void layer_disable(layer l) {
// base layer stays always on
2016-06-14 02:49:01 +02:00
if (l >= KB_LAYERS || l == 0) { return; }
2016-06-14 02:49:01 +02:00
layers_active[l] = false;
2016-06-13 06:25:30 +02:00
2016-06-14 02:49:01 +02:00
if (layers_sticky[l] != StickyNone) {
debug_printf("sticky %d up!\n", l);
2016-06-13 06:25:30 +02:00
}
2016-06-14 02:49:01 +02:00
layers_sticky[l] = StickyNone;
2016-02-06 15:31:54 +01:00
2016-06-14 02:49:01 +02:00
if (l == layers_top) {
2016-06-14 05:48:56 +02:00
layers_top = highest_active_layer(1);
2016-02-04 10:22:40 +01:00
}
}
2016-02-04 10:59:15 +01:00
// disable the highest active layer
2016-06-12 06:20:40 +02:00
void layer_disable_top() {
layer_disable(layers_top);
2016-02-04 10:59:15 +01:00
}
2016-02-04 10:38:07 +01:00
// return layer offset elements below the top
2016-06-14 02:49:01 +02:00
layer layer_peek(layer offset) {
2016-06-14 05:48:56 +02:00
return highest_active_layer(offset);
2016-02-04 10:38:07 +01:00
}
2016-06-14 05:48:56 +02:00
bool is_layer_enable(keyfunc f) {
if (f == &kbfun_layer_enable || f == &kbfun_layer_sticky) {
return true;
}
return false;
}
2016-02-04 05:38:18 +01:00
2016-06-14 05:48:56 +02:00
bool is_layer_disable(keyfunc f) {
if (f == &kbfun_layer_disable || f == &kbfun_layer_sticky) {
return true;
}
2016-06-14 05:48:56 +02:00
return false;
}
2016-02-04 05:38:18 +01:00
2016-06-14 05:48:56 +02:00
void layer_enable_upto(layer max_layer) {
// FIXME clean this up
// pressing a key implicitly activates all lower layers as well
for (layer l=0; l <= KB_LAYERS; l++) {
void (*key_function)(void) = kb_keyfunc_press(l, current_row, current_col);
if (is_layer_enable(key_function)) {
layer enable_layer = (layer) kb_keycode(l, current_row, current_col);
if (enable_layer <= max_layer) {
layer_enable(enable_layer, StickyNone);
}
}
}
adding sticky key functionality 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.
2013-04-08 09:49:35 +02:00
}
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
// ----------------------------------------------------------------------------
// layout info
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
keycode kb_keycode(layer l, u8 row, u8 col) {
return (keycode) pgm_read_byte(&(_kb_layout[l][row][col]));
2016-06-12 03:54:30 +02:00
}
2016-06-14 05:48:56 +02:00
keyfunc kb_keyfunc_press(layer l, u8 row, u8 col) {
return (keyfunc) pgm_read_word(&(_kb_layout_press[l][row][col]));
2016-06-12 03:54:30 +02:00
}
2016-06-14 05:48:56 +02:00
keyfunc kb_keyfunc_release(layer l, u8 row, u8 col) {
2016-06-14 02:49:01 +02:00
return (keyfunc) pgm_read_word(&(_kb_layout_release[l][row][col]));
2016-06-12 03:54:30 +02:00
}
2016-06-14 05:48:56 +02:00
// ----------------------------------------------------------------------------
// keyfunc primitives
// ----------------------------------------------------------------------------
// basic keypresses
2016-06-14 02:49:01 +02:00
void _kbfun_press_release(bool press, keycode key) {
2016-06-14 05:48:56 +02:00
// no-op
if (key == 0) { return; }
2016-06-12 01:51:39 +02:00
2016-06-12 06:20:40 +02:00
if (press) {
2016-06-14 02:49:01 +02:00
_kbfun_press(key);
2016-06-12 06:20:40 +02:00
} else {
2016-06-14 02:49:01 +02:00
_kbfun_release(key);
2016-06-12 06:20:40 +02:00
}
}
2016-06-14 02:49:01 +02:00
void _kbfun_press(keycode key) {
2016-06-14 05:48:56 +02:00
// modifier keys
2016-06-14 02:49:01 +02:00
switch (key) {
2016-06-12 06:20:40 +02:00
case KEY_LeftControl: keyboard_modifier_keys |= (1<<0); return;
case KEY_LeftShift: keyboard_modifier_keys |= (1<<1); return;
case KEY_LeftAlt: keyboard_modifier_keys |= (1<<2); return;
case KEY_LeftGUI: keyboard_modifier_keys |= (1<<3); return;
case KEY_RightControl: keyboard_modifier_keys |= (1<<4); return;
case KEY_RightShift: keyboard_modifier_keys |= (1<<5); return;
case KEY_RightAlt: keyboard_modifier_keys |= (1<<6); return;
case KEY_RightGUI: keyboard_modifier_keys |= (1<<7); return;
2016-06-12 01:51:39 +02:00
}
// all others
2016-06-14 05:48:56 +02:00
for (u8 i=0; i < sizeof(keyboard_keys); i++) {
2016-06-12 06:20:40 +02:00
if (keyboard_keys[i] == 0) {
2016-06-14 02:49:01 +02:00
keyboard_keys[i] = key;
2016-06-12 06:20:40 +02:00
return;
}
}
}
2016-06-14 02:49:01 +02:00
void _kbfun_release(keycode key) {
2016-06-14 05:48:56 +02:00
// modifier keys
2016-06-14 02:49:01 +02:00
switch (key) {
2016-06-12 06:20:40 +02:00
case KEY_LeftControl: keyboard_modifier_keys &= ~(1<<0); return;
case KEY_LeftShift: keyboard_modifier_keys &= ~(1<<1); return;
case KEY_LeftAlt: keyboard_modifier_keys &= ~(1<<2); return;
case KEY_LeftGUI: keyboard_modifier_keys &= ~(1<<3); return;
case KEY_RightControl: keyboard_modifier_keys &= ~(1<<4); return;
case KEY_RightShift: keyboard_modifier_keys &= ~(1<<5); return;
case KEY_RightAlt: keyboard_modifier_keys &= ~(1<<6); return;
case KEY_RightGUI: keyboard_modifier_keys &= ~(1<<7); return;
}
2016-06-14 05:48:56 +02:00
// all others
for (u8 i=0; i < sizeof(keyboard_keys); i++) {
2016-06-14 02:49:01 +02:00
if (keyboard_keys[i] == key) {
2016-06-12 06:20:40 +02:00
keyboard_keys[i] = 0;
return;
2016-06-12 01:51:39 +02:00
}
}
}
2016-06-14 02:49:01 +02:00
bool _kbfun_is_pressed(keycode key) {
2016-06-14 05:48:56 +02:00
// modifier keys
2016-06-14 02:49:01 +02:00
switch (key) {
2016-06-14 05:48:56 +02:00
case KEY_LeftControl: return (keyboard_modifier_keys & (1<<0));
case KEY_LeftShift: return (keyboard_modifier_keys & (1<<1));
case KEY_LeftAlt: return (keyboard_modifier_keys & (1<<2));
case KEY_LeftGUI: return (keyboard_modifier_keys & (1<<3));
case KEY_RightControl: return (keyboard_modifier_keys & (1<<4));
case KEY_RightShift: return (keyboard_modifier_keys & (1<<5));
case KEY_RightAlt: return (keyboard_modifier_keys & (1<<6));
case KEY_RightGUI: return (keyboard_modifier_keys & (1<<7));
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// all others
for (u8 i=0; i < sizeof(keyboard_keys); i++) {
2016-06-14 02:49:01 +02:00
if (keyboard_keys[i] == key) {
2016-06-12 01:51:39 +02:00
return true;
}
2016-06-14 05:48:56 +02:00
}
2016-06-12 01:51:39 +02:00
return false;
}
2016-06-14 02:49:01 +02:00
void _kbfun_mediakey_press_release(bool press, keycode key) {
media_keycode media_key = _media_code_lookup_table[key];
2016-06-12 01:51:39 +02:00
if (press) {
2016-06-14 02:49:01 +02:00
consumer_key = media_key;
2016-06-12 01:51:39 +02:00
} else {
2016-06-14 05:48:56 +02:00
// only one media key can be pressed at a time, so only clear most recent one
2016-06-14 02:49:01 +02:00
if (media_key == consumer_key) {
2016-06-12 01:51:39 +02:00
consumer_key = 0;
}
}
}
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
// basic keyfuncs
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
keycode current_keycode() { return kb_keycode(current_layer, current_row, current_col); }
keyfunc current_keyfunc_press() { return kb_keyfunc_press(current_layer, current_row, current_col); }
keyfunc current_keycode_release() { return kb_keyfunc_release(current_layer, current_row, current_col); }
2016-06-14 06:44:11 +02:00
bool key_is_modifier(keycode key) {
switch (key) {
case KEY_LeftControl: return true;
case KEY_LeftShift: return true;
case KEY_LeftAlt: return true;
case KEY_LeftGUI: return true;
case KEY_RightControl: return true;
case KEY_RightShift: return true;
case KEY_RightAlt: return true;
case KEY_RightGUI: return true;
default: return false;
}
}
2016-06-14 05:48:56 +02:00
// normal key
2016-06-12 01:51:39 +02:00
void kbfun_press_release() {
2016-06-14 06:44:11 +02:00
sticky_done = ! key_is_modifier(current_keycode());
2016-06-14 05:48:56 +02:00
_kbfun_press_release(current_is_pressed, current_keycode());
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// media key
void kbfun_mediakey_press_release() {
2016-06-14 06:44:11 +02:00
sticky_done = true;
2016-06-14 05:48:56 +02:00
keycode key = current_keycode();
_kbfun_mediakey_press_release(current_is_pressed, key);
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// enable layer
2016-06-12 01:51:39 +02:00
void kbfun_layer_enable() {
2016-06-14 05:48:56 +02:00
layer l = (layer) current_keycode();
2016-06-14 02:49:01 +02:00
layer_enable_upto(l);
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// disable layer
2016-06-12 01:51:39 +02:00
void kbfun_layer_disable() {
2016-06-12 02:31:58 +02:00
// letting go off a key releases *all* layers on that key
2016-06-14 02:49:01 +02:00
for (layer l=0; l <= KB_LAYERS; l++) {
2016-06-14 05:48:56 +02:00
void (*key_function)(void) = kb_keyfunc_release(l, current_row, current_col);
2016-06-12 02:31:58 +02:00
if (is_layer_disable(key_function)) {
2016-06-14 05:48:56 +02:00
layer disable_layer = (layer) kb_keycode(l, current_row, current_col);
2016-06-12 06:20:40 +02:00
layer_disable(disable_layer);
2016-06-12 02:31:58 +02:00
}
}
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// sticky layer key
2016-06-12 01:51:39 +02:00
void kbfun_layer_sticky() {
2016-06-14 05:48:56 +02:00
layer l = (layer) current_keycode();
StickyState top_sticky = layer_top_sticky();
2016-06-12 01:51:39 +02:00
2016-06-12 05:39:06 +02:00
if (current_is_pressed) {
2016-06-14 05:48:56 +02:00
if (l != layers_top) {
2016-06-12 01:51:39 +02:00
// only the topmost layer on the stack should be in sticky once state
2016-06-14 05:48:56 +02:00
if (top_sticky == StickyOnceDown || top_sticky == StickyOnceUp) {
2016-06-12 06:20:40 +02:00
layer_disable_top();
2016-06-12 01:51:39 +02:00
}
2016-06-14 02:49:01 +02:00
layer_enable(l, StickyOnceDown);
debug_printf("sticky %d down!\n", l);
2016-06-12 01:51:39 +02:00
// this should be the only place we care about this flag being cleared
2016-06-14 06:44:11 +02:00
sticky_done = false;
2016-06-12 01:51:39 +02:00
}
} else {
2016-06-14 02:49:01 +02:00
if (layer_sticky(l) == StickyOnceDown) {
2016-06-12 01:51:39 +02:00
// When releasing this sticky key, pop the layer always
2016-06-14 02:49:01 +02:00
layer_disable(l);
2016-06-12 01:51:39 +02:00
2016-06-14 06:44:11 +02:00
if (!sticky_done) {
// re-enable the sticky key if we didn't actually use it yet
2016-06-14 02:49:01 +02:00
layer_enable(l, StickyOnceUp);
debug_printf("sticky %d still down!\n", l);
2016-06-12 01:51:39 +02:00
}
}
}
}
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
// combo keyfuncs
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
// +shift
void kbfun_shift_press_release() {
2016-06-12 05:39:06 +02:00
_kbfun_press_release(current_is_pressed, KEY_LeftShift);
2016-06-12 01:51:39 +02:00
kbfun_press_release();
}
2016-06-14 05:48:56 +02:00
// +control
void kbfun_control_press_release() {
2016-06-12 05:39:06 +02:00
_kbfun_press_release(current_is_pressed, KEY_LeftControl);
2016-06-12 01:51:39 +02:00
kbfun_press_release();
}
2016-06-14 05:48:56 +02:00
// +alt
void kbfun_alt_press_release() {
_kbfun_press_release(current_is_pressed, KEY_LeftAlt);
kbfun_press_release();
}
// +win
void kbfun_win_press_release() {
_kbfun_press_release(current_is_pressed, KEY_LeftGUI);
kbfun_press_release();
}
// capslock
void kbfun_2_keys_capslock_press_release() {
2016-06-14 02:49:01 +02:00
static u8 keys_pressed;
static bool lshift_pressed;
static bool rshift_pressed;
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
keycode key = current_keycode();
2016-06-12 01:51:39 +02:00
2016-06-12 05:39:06 +02:00
if (!current_is_pressed) { keys_pressed--; }
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
// take care of the key that was actually pressed
2016-06-14 02:49:01 +02:00
_kbfun_press_release(current_is_pressed, key);
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
// take care of capslock (only on the press of the 2nd key)
2016-06-12 05:39:06 +02:00
if (keys_pressed == 1 && current_is_pressed) {
2016-06-14 05:48:56 +02:00
// save the state of left and right shift
2016-06-12 01:51:39 +02:00
lshift_pressed = _kbfun_is_pressed(KEY_LeftShift);
rshift_pressed = _kbfun_is_pressed(KEY_RightShift);
2016-06-14 05:48:56 +02:00
// disable both
2016-06-12 01:51:39 +02:00
_kbfun_press_release(false, KEY_LeftShift);
_kbfun_press_release(false, KEY_RightShift);
2016-06-14 05:48:56 +02:00
// press capslock, then release it
2016-06-12 01:51:39 +02:00
_kbfun_press_release(true, KEY_CapsLock); usb_keyboard_send();
_kbfun_press_release(false, KEY_CapsLock); usb_keyboard_send();
2016-06-14 05:48:56 +02:00
// restore the state of left and right shift
2016-06-12 01:51:39 +02:00
if (lshift_pressed) { _kbfun_press_release(true, KEY_LeftShift); }
if (rshift_pressed) { _kbfun_press_release(true, KEY_RightShift); }
}
2016-06-12 05:39:06 +02:00
if (current_is_pressed) { keys_pressed++; }
2016-06-12 01:51:39 +02:00
}