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); layer_pop(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) { layer_pop(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 layer_pop(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); } } } } }
/* * [name] * Toggle * * [description] * Toggle the key pressed or unpressed */ void kbfun_toggle(void) { 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); }
static void layer_push(uint8_t local_id) { uint8_t keycode = kb_layout_get(LAYER, ROW, COL); layer_pop(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); }
static void layer_disable_all() { // FIXME clean this up // letting go off a key releases *all* layers on that key for (uint8_t layer=0; layer <= KB_LAYERS; layer++) { void (*key_function)(void) = kb_layout_release_get(layer, main_arg_row, main_arg_col); if (is_layer_disable(key_function)) { uint8_t disable_layer = kb_layout_get(layer, main_arg_row, main_arg_col); main_layers_disable(disable_layer); } } }
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++) { void (*key_function)(void) = kb_layout_press_get(layer, main_arg_row, main_arg_col); if (is_layer_enable(key_function)) { uint8_t enable_layer = kb_layout_get(layer, main_arg_row, main_arg_col); if (enable_layer <= max_layer) { main_layers_enable(enable_layer, eStickyNone); } } } }
/* * [name] * Two keys => capslock * * [description] * 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 * * [note] * 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 = kb_layout_get(LAYER, ROW, COL); if (!IS_PRESSED) keys_pressed--; // take care of the key that was actually pressed _kbfun_press_release(IS_PRESSED, keycode); // take care of capslock (only on the press of the 2nd key) if (keys_pressed == 1 && IS_PRESSED) { // 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); } if (IS_PRESSED) keys_pressed++; }
/* * [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. */ void kbfun_press_release_preserve_sticky(void) { uint8_t keycode = kb_layout_get(LAYER, ROW, COL); _kbfun_press_release(IS_PRESSED, keycode); }
int main(void) { kb_init(); // does controller initialization too kb_led_state_power_on(); usb_init(); while (!usb_configured()); kb_led_delay_usb_init(); // give the OS time to load drivers, etc. kb_led_state_ready(); for (;;) { static uint8_t current_layer = 0; // 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); // call the appropriate function for each key, then send the usb report // if necessary // - everything else is the key function's responsibility; see the // keyboard layout file ("keyboard/ergodox/layout/*.c") for which key // is assigned which function (per layer), and "lib/key-functions.c" // for their definitions for (uint8_t row=0; row<KB_ROWS; row++) { for (uint8_t col=0; col<KB_COLUMNS; col++) { bool is_pressed = (*kb_is_pressed)[row][col]; bool was_pressed = (*kb_was_pressed)[row][col]; if (is_pressed != was_pressed) { if (is_pressed) { kbfun_funptr_t press_function = kb_layout_press_get(current_layer, row, col); if (press_function) { (*press_function)( kb_layout_get(current_layer, row, col), ¤t_layer, &row, &col ); } } else { kbfun_funptr_t release_function = kb_layout_release_get(current_layer, row, col); if (release_function) { (*release_function)( kb_layout_get(current_layer, row, col), ¤t_layer, &row, &col ); } } usb_keyboard_send(); _delay_ms(KB_DEBOUNCE_TIME); } } } // update LEDs if (keyboard_leds & (1<<0)) { kb_led_num_on(); } else { kb_led_num_off(); } if (keyboard_leds & (1<<1)) { kb_led_caps_on(); } else { kb_led_caps_off(); } if (keyboard_leds & (1<<2)) { kb_led_scroll_on(); } else { kb_led_scroll_off(); } if (keyboard_leds & (1<<3)) { kb_led_compose_on(); } else { kb_led_compose_off(); } if (keyboard_leds & (1<<4)) { kb_led_kana_on(); } else { kb_led_kana_off(); } } return 0; }
/* * [name] * Media Key Press Release * * [description] * Generate a keypress for a media key, such as play/pause, next track, or * previous track * */ void kbfun_mediakey_press_release(void) { uint8_t keycode = kb_layout_get(LAYER, ROW, COL); _kbfun_mediakey_press_release(IS_PRESSED, keycode); }
/* * [name] * Numpad on * * [description] * Set the numpad to on (put the numpad layer, specified in the keymap, in an * element at the top of the layer stack, and record that element's id) and * toggle numlock (regardless of whether or not numlock is currently on) * * [note] * Meant to be assigned (along with "numpad off") instead of a normal numlock * key */ void kbfun_layer_push_numpad(void) { uint8_t keycode = kb_layout_get(LAYER, ROW, COL); main_layers_pop_id(numpad_layer_id); numpad_layer_id = main_layers_push(keycode, eStickyNone); numpad_toggle_numlock(); }