ergodox-firmware/src/lib/key-functions/public/special.c

167 lines
4.9 KiB
C
Raw Normal View History

/* ----------------------------------------------------------------------------
* key functions : special : code
* ----------------------------------------------------------------------------
* 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>
* ------------------------------------------------------------------------- */
#include <stdbool.h>
#include <stdint.h>
#include "../../../lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "../../../lib/usb/usage-page/keyboard.h"
#include "../../../keyboard/layout.h"
#include "../../../main.h"
#include "../public.h"
#include "../private.h"
// ----------------------------------------------------------------------------
// convenience macros
#define LAYER main_arg_layer
#define LAYER_OFFSET main_arg_layer_offset
#define ROW main_arg_row
#define COL main_arg_col
#define IS_PRESSED main_arg_is_pressed
#define WAS_PRESSED main_arg_was_pressed
// ----------------------------------------------------------------------------
/*
* [name]
* Shift + press|release
*
* [description]
* Generate a 'shift' press or release before the normal keypress or
* keyrelease
*/
void kbfun_shift_press_release(void) {
_kbfun_press_release(IS_PRESSED, KEY_LeftShift);
kbfun_press_release();
}
/*
* [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++;
}
/* ----------------------------------------------------------------------------
* numpad functions
* ------------------------------------------------------------------------- */
static uint8_t numpad_layer_id;
static inline void numpad_toggle_numlock(void) {
_kbfun_press_release(true, KEY_LockingNumLock);
usb_keyboard_send();
_kbfun_press_release(false, KEY_LockingNumLock);
usb_keyboard_send();
}
/*
* [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);
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
numpad_layer_id = main_layers_push(keycode, eStickyNone);
numpad_toggle_numlock();
}
/*
* [name]
* Numpad off
*
* [description]
* Set the numpad to off (pop the layer element created by "numpad on" out of
* the stack) and toggle numlock (regardless of whether or not numlock is
* currently on)
*
* [note]
* Meant to be assigned (along with "numpad on") instead of a normal numlock
* key
*/
void kbfun_layer_pop_numpad(void) {
main_layers_pop_id(numpad_layer_id);
numpad_layer_id = 0;
numpad_toggle_numlock();
}
/*
* [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);
}
/* ----------------------------------------------------------------------------
* ------------------------------------------------------------------------- */