ergodox-firmware/src/main.c

567 lines
18 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-12 01:51:39 +02:00
#include <stdbool.h>
#include <stdint.h>
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-12 03:54:30 +02:00
typedef void (*void_funptr_t)(void);
2016-06-12 02:31:58 +02:00
typedef enum StickyState {
2016-06-12 05:39:06 +02:00
StickyNone,
StickyOnceDown,
StickyOnceUp,
StickyLock,
2016-06-12 01:51:39 +02:00
} StickyState;
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}
// static const uint8_t PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// static const void_funptr_t PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// static const void_funptr_t PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS];
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
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-12 05:39:06 +02:00
static bool kb_was_transparent[KB_ROWS][KB_COLUMNS];
static uint8_t layers_pressed[KB_ROWS][KB_COLUMNS];
2016-06-12 02:31:58 +02:00
2016-06-12 05:39:06 +02:00
static uint8_t current_layer;
static uint8_t layer_offset;
static uint8_t current_row;
static uint8_t current_col;
static bool current_is_pressed;
static bool non_trans_key_pressed;
static bool trans_key_pressed;
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];
static uint8_t layers_top = 0;
2016-02-04 15:19:06 +01:00
// ----------------------------------------------------------------------------
int main(void) {
2016-02-04 05:38:18 +01:00
kb_init(); // does controller initialization too
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);
// this loop is responsible to
// - "execute" keys when they change state
// - keep track of which layers the keys were on when they were pressed
// (so they can be released using the function from that layer)
//
// note
// - everything else is the key function's responsibility
// - see the keyboard layout file ("keyboard/layout/*.c") for
// which key is assigned which function (per layer)
// - see "lib/key-functions/public/*.c" for the function definitions
for (uint8_t row=0; row<KB_ROWS; row++) {
for (uint8_t col=0; col<KB_COLUMNS; col++) {
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;
trans_key_pressed = false;
} else {
current_layer = layers_pressed[row][col];
trans_key_pressed = kb_was_transparent[row][col];
}
// set remaining vars, and "execute" key
current_row = row;
current_col = col;
layer_offset = 0;
exec_key();
kb_was_transparent[row][col] = trans_key_pressed;
}
}
}
// 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-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-12 02:31:58 +02:00
for (uint8_t layer=0; layer < KB_LAYERS; layer++) {
2016-06-12 05:09:35 +02:00
layers_active[layer] = false;
2016-06-12 05:39:06 +02:00
layers_sticky[layer] = 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
uint8_t _highest_active_layer(uint8_t offset) {
2016-02-04 15:52:43 +01:00
if (offset < layers_top) {
for (uint8_t 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-12 06:20:40 +02:00
StickyState layer_sticky(uint8_t layer) {
2016-02-06 15:31:54 +01:00
if (layer < KB_LAYERS) {
2016-06-12 05:09:35 +02:00
return layers_sticky[layer];
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-12 06:20:40 +02:00
void layer_enable(uint8_t layer, StickyState sticky) {
2016-02-04 15:52:43 +01:00
if (layer >= KB_LAYERS) { return; }
2016-06-12 05:09:35 +02:00
layers_active[layer] = true;
layers_sticky[layer] = sticky;
2016-02-04 10:22:40 +01:00
if (layer > layers_top) {
layers_top = layer;
}
}
2016-02-04 10:22:40 +01:00
// disable a layer
2016-06-12 06:20:40 +02:00
void layer_disable(uint8_t layer) {
// base layer stays always on
if (layer >= KB_LAYERS || layer == 0) { return; }
2016-06-12 05:09:35 +02:00
layers_active[layer] = false;
2016-06-12 05:39:06 +02:00
layers_sticky[layer] = StickyNone;
2016-02-06 15:31:54 +01:00
if (layer == layers_top) {
2016-02-04 10:59:15 +01: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-12 06:20:40 +02:00
uint8_t layer_peek(uint8_t offset) {
2016-02-04 10:59:15 +01:00
return _highest_active_layer(offset);
2016-02-04 10:38:07 +01:00
}
2016-02-04 10:22:40 +01:00
// execute the keypress or keyrelease function (if it exists) of the key at the current possition
2016-06-12 06:20:40 +02:00
void exec_key(void) {
2016-02-04 05:38:18 +01:00
void (*key_function)(void) =
2016-06-12 05:39:06 +02:00
( (current_is_pressed)
? kb_layout_press_get(current_layer, current_row, current_col)
: kb_layout_release_get(current_layer, current_row, current_col) );
2016-02-04 05:38:18 +01:00
if (key_function) {
2016-02-04 05:38:18 +01:00
(*key_function)();
}
2016-02-04 05:38:18 +01:00
// 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-12 06:20:40 +02:00
if (layer_top_sticky() == StickyOnceUp && non_trans_key_pressed) {
layer_disable_top();
}
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-12 03:54:30 +02:00
uint8_t kb_layout_get(uint8_t layer, uint8_t row, uint8_t column) {
return (uint8_t) pgm_read_byte(&(_kb_layout[layer][row][column] ));
}
void_funptr_t kb_layout_press_get(uint8_t layer, uint8_t row, uint8_t column) {
return (void_funptr_t) pgm_read_word(&(_kb_layout_press[layer][row][column] ));
}
void_funptr_t kb_layout_release_get(uint8_t layer, uint8_t row, uint8_t column) {
return (void_funptr_t) pgm_read_word(&(_kb_layout_release[layer][row][column]));
}
2016-06-12 01:51:39 +02:00
/*
* Generate a normal keypress or keyrelease
*
* Arguments
* - press: whether to generate a keypress (true) or keyrelease (false)
* - keycode: the keycode to use
*
* Note
* - Because of the way USB does things, what this actually does is either add
* or remove 'keycode' from the list of currently pressed keys, to be sent at
* the end of the current cycle (see main.c)
*/
void _kbfun_press_release(bool press, uint8_t keycode) {
// no-op
if (keycode == 0) {
return;
}
2016-06-12 06:20:40 +02:00
if (press) {
_kbfun_press(keycode);
} else {
_kbfun_release(keycode);
}
}
void _kbfun_press(uint8_t keycode) {
2016-06-12 01:51:39 +02:00
// modifier keys
switch (keycode) {
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
for (uint8_t i=0; i<6; i++) {
2016-06-12 06:20:40 +02:00
if (keyboard_keys[i] == 0) {
keyboard_keys[i] = keycode;
return;
}
}
}
void _kbfun_release(uint8_t keycode) {
// modifier keys
switch (keycode) {
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;
}
// all others
for (uint8_t i=0; i<6; i++) {
if (keyboard_keys[i] == keycode) {
keyboard_keys[i] = 0;
return;
2016-06-12 01:51:39 +02:00
}
}
}
/*
* 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; }
}
// all others
for (uint8_t i=0; i<6; i++)
if (keyboard_keys[i] == keycode) {
return true;
}
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;
}
}
}
uint8_t _kbfun_get_keycode() {
2016-06-12 05:39:06 +02:00
return kb_layout_get(current_layer, current_row, current_col);
2016-06-12 01:51:39 +02:00
}
// ----------------------------------------------------------------------------
// basic
// ----------------------------------------------------------------------------
void kbfun_press_release() {
2016-06-12 05:39:06 +02:00
if (!trans_key_pressed) {
non_trans_key_pressed = true;
2016-06-12 01:51:39 +02:00
}
kbfun_press_release_preserve_sticky();
}
/*
* 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() {
uint8_t keycode = _kbfun_get_keycode();
2016-06-12 05:39:06 +02:00
_kbfun_press_release(current_is_pressed, keycode);
2016-06-12 01:51:39 +02:00
}
// ----------------------------------------------------------------------------
// layer helper functions
// ----------------------------------------------------------------------------
static bool is_layer_enable(void_funptr_t f) {
if (f == &kbfun_layer_enable || f == &kbfun_layer_sticky) {
return true;
}
return false;
}
static bool is_layer_disable(void_funptr_t f) {
if (f == &kbfun_layer_disable || f == &kbfun_layer_sticky) {
return true;
}
return false;
}
static void layer_enable_upto(uint8_t max_layer) {
// FIXME clean this up
// pressing a key implicitly activates all lower layers as well
for (uint8_t layer=0; layer <= KB_LAYERS; layer++) {
2016-06-12 05:39:06 +02:00
void (*key_function)(void) = kb_layout_press_get(layer, current_row, current_col);
2016-06-12 01:51:39 +02:00
if (is_layer_enable(key_function)) {
2016-06-12 05:39:06 +02:00
uint8_t enable_layer = kb_layout_get(layer, current_row, current_col);
2016-06-12 01:51:39 +02:00
if (enable_layer <= max_layer) {
2016-06-12 06:20:40 +02:00
layer_enable(enable_layer, StickyNone);
2016-06-12 01:51:39 +02:00
}
}
}
}
// ----------------------------------------------------------------------------
// layer functions
// ----------------------------------------------------------------------------
// enable given layer
void kbfun_layer_enable() {
uint8_t layer = _kbfun_get_keycode();
// FIXME useful for anything?
// Only the topmost layer on the stack should be in sticky once state, pop
// the top layer if it is in sticky once state
2016-06-12 06:20:40 +02:00
/* uint8_t topSticky = layer_top_sticky(); */
2016-06-12 05:39:06 +02:00
/* if (topSticky == StickyOnceDown || topSticky == StickyOnceUp) { */
2016-06-12 06:20:40 +02:00
/* layer_disable_top(); */
2016-06-12 01:51:39 +02:00
/* } */
layer_enable_upto(layer);
}
// disable given layer
void kbfun_layer_disable() {
/* uint8_t layer = _kbfun_get_keycode(); */
2016-06-12 02:31:58 +02:00
// FIXME clean this up
// letting go off a key releases *all* layers on that key
for (uint8_t layer=0; layer <= KB_LAYERS; layer++) {
2016-06-12 05:39:06 +02:00
void (*key_function)(void) = kb_layout_release_get(layer, current_row, current_col);
2016-06-12 02:31:58 +02:00
if (is_layer_disable(key_function)) {
2016-06-12 05:39:06 +02:00
uint8_t disable_layer = kb_layout_get(layer, 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
}
/*
* This function gives similar behavior to sticky keys for modifiers available
* on most operating systems.
* 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() {
2016-06-12 02:31:58 +02:00
uint8_t layer = _kbfun_get_keycode();
2016-06-12 06:20:40 +02:00
StickyState topSticky = 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-12 06:26:27 +02:00
if (layer == layers_top) {
2016-06-12 01:51:39 +02:00
// FIXME
2016-06-12 05:39:06 +02:00
/* if (topSticky == StickyOnceUp) { */
2016-06-12 06:20:40 +02:00
/* layer_enable(layer, StickyLock); */
2016-06-12 01:51:39 +02:00
/* } */
} else {
// only the topmost layer on the stack should be in sticky once state
2016-06-12 05:39:06 +02:00
if (topSticky == StickyOnceDown || topSticky == StickyOnceUp) {
2016-06-12 06:20:40 +02:00
layer_disable_top();
2016-06-12 01:51:39 +02:00
}
2016-06-12 06:20:40 +02:00
layer_enable(layer, StickyOnceDown);
2016-06-12 01:51:39 +02:00
// this should be the only place we care about this flag being cleared
2016-06-12 05:39:06 +02:00
non_trans_key_pressed = false;
2016-06-12 01:51:39 +02:00
}
} else {
2016-06-12 06:20:40 +02:00
if (layer_sticky(layer) == StickyOnceDown) {
2016-06-12 01:51:39 +02:00
// When releasing this sticky key, pop the layer always
2016-06-12 06:20:40 +02:00
layer_disable(layer);
2016-06-12 01:51:39 +02:00
2016-06-12 05:39:06 +02:00
if (!non_trans_key_pressed) {
2016-06-12 01:51:39 +02:00
// If no key defined for this layer (a non-transparent key)
// was pressed, push the layer again, but in the
// StickyOnceUp state
2016-06-12 06:20:40 +02:00
layer_enable(layer, StickyOnceUp);
2016-06-12 01:51:39 +02:00
}
}
}
}
// ----------------------------------------------------------------------------
// special
// ----------------------------------------------------------------------------
/*
* Generate a 'shift' press or release before the normal keypress or release
*/
void kbfun_shift_press_release(void) {
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();
}
/*
* Generate a 'control' press or release before the normal keypress or release
*/
void kbfun_control_press_release(void) {
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();
}
/*
* When assigned to two keys (e.g. the physical left and right shift keys)
* (in both the press and release matrices), pressing and holding down one of
* the keys will make the second key toggle capslock
*
* If either of the shifts are pressed when the second key is pressed, they
* wil be released so that capslock will register properly when pressed.
* Capslock will then be pressed and released, and the original state of the
* shifts will be restored
*/
void kbfun_2_keys_capslock_press_release(void) {
static uint8_t keys_pressed;
static bool lshift_pressed;
static bool rshift_pressed;
uint8_t keycode = _kbfun_get_keycode();
2016-06-12 05:39:06 +02:00
if (!current_is_pressed) { keys_pressed--; }
2016-06-12 01:51:39 +02:00
// take care of the key that was actually pressed
2016-06-12 05:39:06 +02:00
_kbfun_press_release(current_is_pressed, keycode);
2016-06-12 01:51:39 +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-12 01:51:39 +02:00
// save the state of left and right shift
lshift_pressed = _kbfun_is_pressed(KEY_LeftShift);
rshift_pressed = _kbfun_is_pressed(KEY_RightShift);
// disable both
_kbfun_press_release(false, KEY_LeftShift);
_kbfun_press_release(false, KEY_RightShift);
// press capslock, then release it
_kbfun_press_release(true, KEY_CapsLock); usb_keyboard_send();
_kbfun_press_release(false, KEY_CapsLock); usb_keyboard_send();
// restore the state of left and right shift
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
}
/*
* Generate a keypress for a media key
*/
void kbfun_mediakey_press_release(void) {
uint8_t keycode = _kbfun_get_keycode();
2016-06-12 05:39:06 +02:00
_kbfun_mediakey_press_release(current_is_pressed, keycode);
2016-06-12 01:51:39 +02:00
}