ergodox-firmware/src/main.c

624 lines
22 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>
* ------------------------------------------------------------------------- */
2017-02-14 16:25:11 +01:00
#include <stdarg.h>
2016-06-12 01:51:39 +02:00
#include <stdbool.h>
#include <stdint.h>
2016-06-14 00:31:20 +02:00
2016-06-12 02:31:58 +02:00
// --------------------------------------------------------------------
// types and forward declarations
2016-06-12 01:51:39 +02:00
// --------------------------------------------------------------------
2016-08-09 00:23:04 +02:00
typedef int8_t i8;
typedef uint8_t u8;
2016-08-22 17:28:10 +02:00
typedef int16_t i16;
2016-08-09 00:23:04 +02:00
typedef uint16_t u16;
2016-08-22 04:04:00 +02:00
typedef uint32_t u32;
2016-06-12 03:54:30 +02:00
2016-06-14 02:49:01 +02:00
typedef u8 keycode;
typedef u16 media_keycode;
typedef u8 layer;
2016-08-22 04:04:00 +02:00
typedef u32 millis; // wraps every 50 days, but that's fine for our logic
2016-06-14 02:49:01 +02:00
2016-08-09 01:40:48 +02:00
typedef void (*keyfunc)(keycode, bool);
2016-06-14 02:49:01 +02:00
2016-06-12 02:31:58 +02:00
#include "./main.h"
2016-02-04 15:19:06 +01:00
2016-08-22 17:28:10 +02:00
// --------------------------------------------------------------------
// hardware
// --------------------------------------------------------------------
// comment out this define to disable the debug interface completely
// however, just not using the functions gets rid of most of the firmware bloat already
#define KBD_DEBUG
#include "./keyboard/controller.c"
#include "./keyboard/keyboard.h"
2016-06-12 02:31:58 +02:00
// ----------------------------------------------------------------------------
// layout data
2016-06-12 02:31:58 +02:00
// ----------------------------------------------------------------------------
#include "./keyboard/layout.c"
// defines:
2016-08-21 19:25:08 +02:00
// #define KB_LAYERS #{Layers.size}
// static const keycode PROGMEM _kb_layout_code[KB_ROWS][KB_COLUMNS][KB_LAYERS];
// static const keyfunc PROGMEM _kb_layout_func[KB_ROWS][KB_COLUMNS][KB_LAYERS];
/* static u8 layers[KB_LAYERS] = {0, 1, 1+2, 3, 4, 2+3+4}; */
2016-08-21 19:25:08 +02:00
#if KB_LAYERS > 8
2016-08-21 19:39:20 +02:00
#error "can only handle 8 layers for now"
2016-08-21 19:25:08 +02:00
#endif
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
2016-06-14 02:49:01 +02:00
2016-08-22 19:12:27 +02:00
// state of key presses
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-08-22 19:12:27 +02:00
// layer state
2016-08-09 00:23:04 +02:00
static i8 layers_active[KB_LAYERS];
2016-08-09 01:40:48 +02:00
static layer layers_top;
2016-02-04 15:19:06 +01:00
2016-08-22 19:12:27 +02:00
// sticky states
2016-06-14 13:38:17 +02:00
static bool layer_sticky_on;
2016-06-14 11:51:17 +02:00
static bool layer_sticky[KB_LAYERS];
2016-06-14 13:38:17 +02:00
static bool layer_sticky_done;
static u8 mod_sticky;
static bool mod_sticky_done;
2016-06-14 11:51:17 +02:00
2016-08-22 19:12:27 +02:00
// key repeat config
static const millis repeat_delay = 300; // ms before key repeat kicks in
static const millis repeat_rate = 13; // send 1 / RATE key press
// key repeat state
2016-08-22 04:04:00 +02:00
static millis time_pressed[KB_ROWS][KB_COLUMNS];
2016-08-22 19:12:27 +02:00
static bool repeating[KB_ROWS][KB_COLUMNS];
2016-08-22 04:04:00 +02:00
// TODO this only exists as a workaround until we handle our own key repeats
static const keyfunc _kb_layer_funcs[] = {
&kbfun_layer_press_release,
&kbfun_layer_sticky,
&kbfun_shift_layer_press_release,
&kbfun_control_layer_press_release,
&kbfun_alt_layer_press_release,
&kbfun_win_layer_press_release,
};
2016-08-21 19:25:08 +02:00
// ----------------------------------------------------------------------------
// utilities
// ----------------------------------------------------------------------------
#define array_length(x) (sizeof(x) / sizeof((x)[0]))
#define set_bit(x, i) (x) |= (1u << (i))
#define unset_bit(x, i) (x) &= ~(1u << (i))
#define toggle_bit(x, i) (x) ^= (1u << (i))
#define is_set(x, i) (((x) >> (i)) & 1u)
#define is_unset(x, i) !is_set((x), (i))
#define set_layer(x, layer) set_bit((x), (layer) - 1)
#define unset_layer(x, layer) unset_bit((x), (layer) - 1)
#define toggle_layer(x, layer) toggle_bit((x), (layer) - 1)
2016-08-22 04:04:00 +02:00
millis now() { return timer0_ms; }
2016-08-21 19:25:08 +02:00
// ----------------------------------------------------------------------------
// main
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
int main() {
2016-06-14 11:51:17 +02:00
// initialize
2016-06-14 13:38:17 +02:00
init_hw();
2016-06-12 06:20:40 +02:00
init_layers();
2016-06-14 11:51:17 +02:00
init_sticky();
2016-08-22 04:04:00 +02:00
init_timer();
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-08-09 01:40:48 +02:00
bool is_pressed = (*kb_is_pressed)[row][col];
bool was_pressed = (*kb_was_pressed)[row][col];
2016-08-22 19:12:27 +02:00
if (is_pressed) {
if (!was_pressed) { main_key_down_new(row, col); }
else { main_key_down_repeat(row, col); }
} else {
if (!was_pressed) { continue; } // no change
else { main_key_up(row, col); }
2016-06-12 06:26:27 +02:00
}
}
}
// send the USB report (even if nothing's changed)
usb_keyboard_send();
usb_extra_consumer_send();
2016-06-14 12:34:43 +02:00
// unset sticky keys if necessary
2016-06-14 13:38:17 +02:00
if (layer_sticky_on && layer_sticky_done) {
for (layer l=1; l < KB_LAYERS; l++) {
if (layer_sticky[l]) {
layer_disable(l);
layer_sticky[l] = false;
}
}
layer_sticky_on = false;
layer_sticky_done = false;
}
if (mod_sticky && mod_sticky_done) {
keyboard_modifier_keys &= ~mod_sticky;
2016-06-14 12:34:43 +02:00
usb_keyboard_send();
2016-06-14 13:38:17 +02:00
mod_sticky = 0;
mod_sticky_done = false;
2016-06-14 12:34:43 +02:00
}
2016-06-12 06:26:27 +02:00
// debounce in ms; see keyswitch spec for necessary value
_delay_ms(5);
}
}
2016-08-22 19:12:27 +02:00
void main_key_up(u8 row, u8 col) {
layer layer = layers_pressed[row][col];
layers_pressed[row][col] = 0;
// stop key repeat
if (repeating[row][col]) {
repeating[row][col] = false;
2016-10-31 20:29:04 +01:00
/* debug_printf("stop: %lu\n", now() - time_pressed[row][col]); */
2016-08-22 19:12:27 +02:00
}
exec_key(layer, row, col, false);
}
void main_key_down_new(u8 row, u8 col) {
layer layer = layers_top;
layers_pressed[row][col] = layer;
time_pressed[row][col] = now();
2016-10-31 20:29:04 +01:00
/* debug_printf("down: %lu\n", time_pressed[row][col]); */
2016-08-22 19:12:27 +02:00
exec_key(layer, row, col, true);
}
void main_key_down_repeat(u8 row, u8 col) {
millis t = now(); // consistency!
millis diff = t - time_pressed[row][col];
if (!repeating[row][col] && diff >= repeat_delay) { // start repeat
repeating[row][col] = true;
time_pressed[row][col] = t;
2016-10-31 20:29:04 +01:00
/* debug_printf("start: %lu\n", diff); */
2016-08-22 19:12:27 +02:00
} else if (repeating[row][col] && diff >= repeat_rate) { // continue repeat
time_pressed[row][col] = t;
2016-10-31 20:29:04 +01:00
/* debug_printf("cont: %lu\n", diff); */
2016-08-22 19:12:27 +02:00
}
}
2016-02-04 15:19:06 +01:00
// ----------------------------------------------------------------------------
2016-06-14 13:38:17 +02:00
// init functions
2016-02-04 10:59:15 +01:00
// ----------------------------------------------------------------------------
2016-06-14 13:38:17 +02:00
void init_hw() {
kb_init();
usb_init();
while (!usb_configured());
}
void init_sticky() {
for (layer l=1; l < KB_LAYERS; l++) {
layer_sticky[l] = false;
}
layer_sticky_on = false;
mod_sticky = 0;
layer_sticky_done = false;
mod_sticky_done = false;
}
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++) {
2016-08-09 00:23:04 +02:00
layers_active[l] = 0;
2016-06-12 02:31:58 +02:00
}
2016-08-09 01:40:48 +02:00
layers_active[0] = 1;
layers_top = 0;
for (u8 row=0; row<KB_ROWS; row++) {
for (u8 col=0; col<KB_COLUMNS; col++) {
layers_pressed[row][col] = 0;
}
}
2016-06-12 02:31:58 +02:00
}
2016-08-22 04:04:00 +02:00
void init_timer() {
for (u8 row=0; row<KB_ROWS; row++) {
for (u8 col=0; col<KB_COLUMNS; col++) {
time_pressed[row][col] = 0;
2016-08-22 19:12:27 +02:00
repeating[row][col] = false;
2016-08-22 04:04:00 +02:00
}
}
}
2016-06-14 13:38:17 +02:00
// ----------------------------------------------------------------------------
// layer functions
// ----------------------------------------------------------------------------
2016-02-04 15:19:06 +01:00
2016-02-04 10:59:15 +01:00
// find highest active layer
2016-08-09 00:23:04 +02:00
layer highest_active_layer() {
2016-08-09 01:40:48 +02:00
for (layer l = KB_LAYERS - 1; l > 0; l--) {
2016-08-09 00:23:04 +02:00
if (layers_active[l] > 0) { 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;
}
2016-02-04 10:22:40 +01:00
// enable a layer
2016-06-14 11:51:17 +02:00
void layer_enable(layer l) {
2016-08-09 00:23:04 +02:00
if (l >= KB_LAYERS || l == 0) { return; }
2016-02-04 15:52:43 +01:00
2016-08-09 00:23:04 +02:00
layers_active[l] += 1;
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-08-09 00:23:04 +02:00
if (layers_active[l] > 0) {
layers_active[l] -= 1;
}
2016-06-13 06:25:30 +02:00
2016-08-09 01:57:15 +02:00
if (l == layers_top) {
layers_top = highest_active_layer();
}
// re-press affected keys
2016-08-09 00:23:04 +02:00
for (u8 row=0; row<KB_ROWS; row++) {
for (u8 col=0; col<KB_COLUMNS; col++) {
2016-08-09 01:40:48 +02:00
if (layers_pressed[row][col] == l) {
keyfunc func = (kb_keyfunc(l, row, col));
// FIXME don't re-send normal keys until we have key repeats
if (is_layer_keyfunc(func)) {
// FIXME this kinda shouldn't be here and it privileges layer 0 even more
layers_pressed[row][col] = 0;
exec_key(l, row, col, false);
2016-08-28 09:11:55 +02:00
layers_pressed[row][col] = layers_top;
exec_key(layers_top, row, col, true);
2016-08-09 02:49:27 +02:00
}
2016-06-14 05:48:56 +02:00
}
}
}
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
bool is_layer_keyfunc(keyfunc f) {
for (int i=0; i<array_length(_kb_layer_funcs); i++) {
if (f == _kb_layer_funcs[i]) {
return true;
}
}
return false;
}
2016-06-14 05:48:56 +02:00
// ----------------------------------------------------------------------------
// layout info
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
keycode kb_keycode (layer l, u8 row, u8 col) { return (keycode) pgm_read_byte(&(_kb_layout_code[row][col][l])); }
keyfunc kb_keyfunc (layer l, u8 row, u8 col) { return (keyfunc) pgm_read_word(&(_kb_layout_func[row][col][l])); }
2016-06-12 03:54:30 +02:00
2016-06-14 05:48:56 +02:00
// ----------------------------------------------------------------------------
// keyfunc primitives
// ----------------------------------------------------------------------------
// basic keypresses
2016-08-09 01:40:48 +02:00
void _kbfun_normal_press_release(keycode key, bool is_pressed) {
2016-06-14 10:39:45 +02:00
if (key == 0) { return; } // noop
2016-06-12 01:51:39 +02:00
2016-08-22 19:31:11 +02:00
if (is_pressed) { _kbfun_normal_swap(0, key); }
else { _kbfun_normal_swap(key, 0); }
2016-06-12 06:20:40 +02:00
}
2016-08-09 01:40:48 +02:00
void _kbfun_mediakey_press_release(keycode key, bool is_pressed) {
2016-07-08 10:39:40 +02:00
media_keycode media_key = _media_code_lookup(key);
2016-08-09 01:40:48 +02:00
if (is_pressed) {
2016-06-14 10:39:45 +02:00
consumer_key = media_key;
} else {
// only one media key can be pressed at a time, so only clear most recent one
if (media_key == consumer_key) {
consumer_key = 0;
2016-06-12 01:51:39 +02:00
}
}
}
2016-08-09 01:40:48 +02:00
void _kbfun_modifier_press_release(keycode key, bool is_pressed) {
if (is_pressed) {
2016-08-21 19:25:08 +02:00
set_bit(keyboard_modifier_keys, key);
2016-06-14 10:39:45 +02:00
} else {
2016-08-21 19:25:08 +02:00
unset_bit(keyboard_modifier_keys, key);
2016-06-12 01:51:39 +02:00
}
2016-06-14 10:39:45 +02:00
}
2016-06-12 01:51:39 +02:00
2016-08-22 19:31:11 +02:00
void _kbfun_normal_swap(keycode from, keycode to) {
for (u8 i=0; i < sizeof(keyboard_keys); i++) {
if (keyboard_keys[i] == from) {
keyboard_keys[i] = to;
return;
}
}
}
2016-06-14 10:39:45 +02:00
bool _kbfun_normal_is_pressed(keycode key) {
2016-06-14 05:48:56 +02:00
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 10:39:45 +02:00
bool _kbfun_mediakey_is_pressed(keycode key) {
return (consumer_key != 0);
}
bool _kbfun_modifier_is_pressed(keycode key) {
2016-08-21 19:25:08 +02:00
return is_set(keyboard_modifier_keys, key);
2016-06-12 01:51:39 +02:00
}
2016-06-14 13:38:17 +02:00
void _kbfun_normal_sticky_done() {
layer_sticky_done = true;
mod_sticky_done = true;
}
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
2016-06-14 05:48:56 +02:00
// basic keyfuncs
2016-06-12 01:51:39 +02:00
// ----------------------------------------------------------------------------
2016-06-14 08:32:06 +02:00
// execute the keypress or keyrelease function (if it exists) of the key at the current possition
2016-08-09 01:40:48 +02:00
void exec_key(layer layer, u8 row, u8 col, bool is_pressed) {
keycode key = kb_keycode(layer, row, col);
void (*key_function)(keycode, bool) = kb_keyfunc(layer, row, col);
2016-08-09 01:40:48 +02:00
if (key_function) { (*key_function)(key, is_pressed); }
2016-06-14 08:32:06 +02:00
}
2016-06-14 05:48:56 +02:00
// normal key
2016-08-09 01:40:48 +02:00
void kbfun_normal_press_release(keycode key, bool is_pressed) {
2016-06-14 13:38:17 +02:00
_kbfun_normal_sticky_done();
2016-08-09 01:40:48 +02:00
_kbfun_normal_press_release(key, is_pressed);
2016-06-12 01:51:39 +02:00
}
2016-06-14 05:48:56 +02:00
// media key
2016-08-09 01:40:48 +02:00
void kbfun_mediakey_press_release(keycode key, bool is_pressed) {
2016-06-14 13:38:17 +02:00
_kbfun_normal_sticky_done();
2016-08-09 01:40:48 +02:00
_kbfun_mediakey_press_release(key, is_pressed);
2016-06-14 10:39:45 +02:00
}
// modifier
2016-08-09 01:40:48 +02:00
void kbfun_modifier_press_release(keycode key, bool is_pressed) {
2016-06-19 09:48:26 +02:00
layer_sticky_done = true;
2016-08-09 01:40:48 +02:00
_kbfun_modifier_press_release(key, is_pressed);
2016-06-12 01:51:39 +02:00
}
2016-06-14 21:14:44 +02:00
// layer key
2016-08-09 01:40:48 +02:00
void kbfun_layer_press_release(keycode key, bool is_pressed) {
2016-06-14 13:38:17 +02:00
layer_sticky_done = true; // don't disable sticky mods!
2016-06-14 11:51:17 +02:00
2016-08-09 01:40:48 +02:00
layer l = (layer) key;
if (is_pressed) {
2016-08-09 00:23:04 +02:00
layer_enable(l);
2016-06-14 21:14:44 +02:00
} else {
2016-08-09 00:23:04 +02:00
layer_disable(l);
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-08-09 01:40:48 +02:00
void kbfun_layer_sticky(keycode key, bool is_pressed) {
layer l = (layer) key;
2016-06-12 01:51:39 +02:00
2016-08-09 01:40:48 +02:00
if (is_pressed) {
2016-08-09 17:13:13 +02:00
if (! layer_sticky[l]) {
layer_enable(l);
layer_sticky_done = false;
}
2016-06-12 01:51:39 +02:00
} else {
2016-06-14 13:38:17 +02:00
if (layer_sticky_done) {
2016-06-14 02:49:01 +02:00
layer_disable(l);
2016-06-14 11:51:17 +02:00
} else {
2016-06-14 13:38:17 +02:00
layer_sticky[l] = true;
layer_sticky_on = true;
layer_sticky_done = false;
2016-06-12 01:51:39 +02:00
}
}
}
2016-06-14 12:34:43 +02:00
// sticky modifier key
2016-08-09 01:40:48 +02:00
void kbfun_modifier_sticky(keycode key, bool is_pressed) {
2016-06-14 12:34:43 +02:00
// TODO handle: sticky, then same modifier
2016-08-09 01:40:48 +02:00
keycode mod = key;
2016-06-14 12:34:43 +02:00
2016-08-09 01:40:48 +02:00
if (is_pressed) {
kbfun_modifier_press_release(key, true);
2016-06-14 13:38:17 +02:00
mod_sticky_done = false;
2016-06-14 12:34:43 +02:00
} else {
2016-06-14 13:38:17 +02:00
if (mod_sticky_done) {
2016-08-09 01:40:48 +02:00
kbfun_modifier_press_release(key, false);
2016-06-14 12:34:43 +02:00
} else {
2016-08-21 19:25:08 +02:00
set_bit(mod_sticky, mod);
mod_sticky_done = false;
2016-06-14 12:34:43 +02:00
}
2016-10-31 20:29:04 +01:00
2016-06-14 12:34:43 +02:00
}
}
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
// ----------------------------------------------------------------------------
2017-02-14 17:34:00 +01:00
void _kbfun_combo_normal_press_release(keycode combo_key, keycode key, bool is_pressed) {
_kbfun_modifier_press_release(combo_key, is_pressed);
2017-02-14 15:53:06 +01:00
kbfun_normal_press_release(key, is_pressed);
}
void _kbfun_combo_normal_press_release_once(keycode combo_key, keycode key, bool is_pressed) {
// FIXME this should be cleaner when we have actual key repeats
if (is_pressed) {
// avoid messing with independently pressed modifiers
bool mod_already_pressed = _kbfun_modifier_is_pressed(combo_key);
if (!mod_already_pressed) {
_kbfun_modifier_press_release(combo_key, true);
}
kbfun_normal_press_release(key, true);
if (!mod_already_pressed) {
// we force a keyboard send to prevent the modifier from bleeding into the next key press
usb_keyboard_send();
_kbfun_modifier_press_release(combo_key, false);
}
} else {
kbfun_normal_press_release(key, false);
}
}
2016-08-09 01:40:48 +02:00
void _kbfun_combo_layer_press_release(keycode combo_key, keycode key, bool is_pressed) {
kbfun_layer_press_release(key, is_pressed);
_kbfun_modifier_press_release(combo_key, is_pressed);
2016-07-20 22:53:26 +02:00
}
2017-02-14 17:34:00 +01:00
void kbfun_shift_press_release(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release(MOD_KEY_LeftShift, key, is_pressed); } // +shift
void kbfun_control_press_release(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release(MOD_KEY_LeftControl, key, is_pressed); } // +control
void kbfun_alt_press_release(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release(MOD_KEY_LeftAlt, key, is_pressed); } // +alt
void kbfun_win_press_release(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release(MOD_KEY_LeftGUI, key, is_pressed); } // +win
//
void kbfun_shift_press_release_once(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release_once(MOD_KEY_LeftShift, key, is_pressed); } // +shift once
void kbfun_control_press_release_once(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release_once(MOD_KEY_LeftControl, key, is_pressed); } // +control once
void kbfun_alt_press_release_once(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release_once(MOD_KEY_LeftAlt, key, is_pressed); } // +alt once
void kbfun_win_press_release_once(keycode key, bool is_pressed) { _kbfun_combo_normal_press_release_once(MOD_KEY_LeftGUI, key, is_pressed); } // +win once
//
void kbfun_shift_layer_press_release(keycode key, bool is_pressed) { _kbfun_combo_layer_press_release(MOD_KEY_LeftShift, key, is_pressed); } // +shift + layer
void kbfun_control_layer_press_release(keycode key, bool is_pressed) { _kbfun_combo_layer_press_release(MOD_KEY_LeftControl, key, is_pressed); } // +control + layer
void kbfun_alt_layer_press_release(keycode key, bool is_pressed) { _kbfun_combo_layer_press_release(MOD_KEY_LeftAlt, key, is_pressed); } // +alt + layer
void kbfun_win_layer_press_release(keycode key, bool is_pressed) { _kbfun_combo_layer_press_release(MOD_KEY_LeftGUI, key, is_pressed); } // +win + layer
2017-02-14 16:25:11 +01:00
2017-02-14 17:34:00 +01:00
// multi-combos
2017-02-14 16:25:11 +01:00
2017-02-14 17:34:00 +01:00
// TODO lol
2017-02-14 16:25:11 +01:00
2017-02-14 17:34:00 +01:00
void _kbfun_combo_normal_press_release2(keycode combo_key1, keycode combo_key2, keycode key, bool is_pressed) {
_kbfun_modifier_press_release(combo_key1, is_pressed);
_kbfun_modifier_press_release(combo_key2, is_pressed);
kbfun_normal_press_release(key, is_pressed);
}
void _kbfun_combo_normal_press_release3(keycode combo_key1, keycode combo_key2, keycode combo_key3, keycode key, bool is_pressed) {
_kbfun_modifier_press_release(combo_key1, is_pressed);
_kbfun_modifier_press_release(combo_key2, is_pressed);
_kbfun_modifier_press_release(combo_key3, is_pressed);
kbfun_normal_press_release(key, is_pressed);
}
void _kbfun_combo_normal_press_release4(keycode combo_key1, keycode combo_key2, keycode combo_key3, keycode combo_key4, keycode key, bool is_pressed) {
_kbfun_modifier_press_release(combo_key1, is_pressed);
_kbfun_modifier_press_release(combo_key2, is_pressed);
_kbfun_modifier_press_release(combo_key3, is_pressed);
_kbfun_modifier_press_release(combo_key4, is_pressed);
kbfun_normal_press_release(key, is_pressed);
}
2017-02-14 16:25:11 +01:00
2017-02-14 17:34:00 +01:00
#define COMBO2(x1, x2) _kbfun_combo_normal_press_release2(x1, x2, key, is_pressed)
#define COMBO3(x1, x2, x3) _kbfun_combo_normal_press_release3(x1, x2, x3, key, is_pressed)
#define COMBO4(x1, x2, x3, x4) _kbfun_combo_normal_press_release4(x1, x2, x3, x4, key, is_pressed)
void kbfun_shift_control_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftShift, MOD_KEY_LeftControl); }
void kbfun_shift_alt_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftShift, MOD_KEY_LeftAlt); }
void kbfun_shift_win_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftShift, MOD_KEY_LeftGUI); }
void kbfun_control_alt_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftControl, MOD_KEY_LeftAlt); }
void kbfun_control_win_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftControl, MOD_KEY_LeftGUI); }
void kbfun_alt_win_press_release(keycode key, bool is_pressed) { COMBO2(MOD_KEY_LeftAlt, MOD_KEY_LeftGUI); }
void kbfun_shift_control_alt_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftControl, MOD_KEY_LeftAlt); }
void kbfun_shift_control_win_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftControl, MOD_KEY_LeftGUI); }
void kbfun_shift_alt_control_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftAlt, MOD_KEY_LeftControl); }
void kbfun_shift_alt_win_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftAlt, MOD_KEY_LeftGUI); }
void kbfun_shift_win_control_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftGUI, MOD_KEY_LeftControl); }
void kbfun_shift_win_alt_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftShift, MOD_KEY_LeftGUI, MOD_KEY_LeftAlt); }
void kbfun_control_alt_shift_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftControl, MOD_KEY_LeftAlt, MOD_KEY_LeftShift); }
void kbfun_control_alt_win_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftControl, MOD_KEY_LeftAlt, MOD_KEY_LeftGUI); }
void kbfun_control_win_shift_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftControl, MOD_KEY_LeftGUI, MOD_KEY_LeftShift); }
void kbfun_control_win_alt_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftControl, MOD_KEY_LeftGUI, MOD_KEY_LeftAlt); }
void kbfun_alt_win_shift_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftAlt, MOD_KEY_LeftGUI, MOD_KEY_LeftShift); }
void kbfun_alt_win_control_press_release(keycode key, bool is_pressed) { COMBO3(MOD_KEY_LeftAlt, MOD_KEY_LeftGUI, MOD_KEY_LeftControl); }
void kbfun_shift_control_alt_win_press_release(keycode key, bool is_pressed) { COMBO4(MOD_KEY_LeftShift, MOD_KEY_LeftControl, MOD_KEY_LeftAlt, MOD_KEY_LeftGUI); }
2017-02-14 15:53:06 +01:00
2016-06-14 05:48:56 +02:00
// capslock
2016-08-09 01:40:48 +02:00
void kbfun_capslock_press_release(keycode key, bool is_pressed) {
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-08-09 01:40:48 +02:00
if (!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-08-09 01:40:48 +02:00
_kbfun_modifier_press_release(key, is_pressed);
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-08-09 01:40:48 +02:00
if (keys_pressed == 1 && is_pressed) {
2016-06-14 05:48:56 +02:00
// save the state of left and right shift
2016-06-14 10:39:45 +02:00
lshift_pressed = _kbfun_modifier_is_pressed(MOD_KEY_LeftShift);
rshift_pressed = _kbfun_modifier_is_pressed(MOD_KEY_RightShift);
2016-06-14 05:48:56 +02:00
// disable both
2016-08-09 01:40:48 +02:00
_kbfun_modifier_press_release(MOD_KEY_LeftShift, false);
_kbfun_modifier_press_release(MOD_KEY_RightShift, false);
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
// press capslock, then release it
2016-08-09 01:40:48 +02:00
_kbfun_normal_press_release(KEY_CapsLock, true); usb_keyboard_send();
_kbfun_normal_press_release(KEY_CapsLock, false); usb_keyboard_send();
2016-06-12 01:51:39 +02:00
2016-06-14 05:48:56 +02:00
// restore the state of left and right shift
2016-08-09 01:40:48 +02:00
if (lshift_pressed) { _kbfun_modifier_press_release(MOD_KEY_LeftShift, true); }
if (rshift_pressed) { _kbfun_modifier_press_release(MOD_KEY_RightShift, true); }
2016-06-12 01:51:39 +02:00
}
2016-08-09 01:40:48 +02:00
if (is_pressed) { keys_pressed++; }
2016-06-12 01:51:39 +02:00
}