/* ---------------------------------------------------------------------------- * key functions: code * * These functions may do.. pretty much anything rational that thay like. If * they want keycodes to be sent to the host in an aggrate report, they're * responsible for modifying the appropriate report variables. * ---------------------------------------------------------------------------- * Copyright (c) 2012 Ben Blazak * Released under The MIT License (MIT) (see "license.md") * Project located at * ------------------------------------------------------------------------- */ #include #include "lib-other/pjrc/usb_keyboard/usb_keyboard.h" #include "lib/data-types.h" #include "lib/usb/usage-page/keyboard.h" #include "keyboard.h" #include "key-functions.h" #include "key-functions--private.h" // ---------------------------------------------------------------------------- // public functions (not for keys) // ---------------------------------------------------------------------------- /* * Exec key * - Execute the keypress or keyrelease function (if it exists) of the key at * the current possition. Pass the keycode at the current position, and pass * all other arguments as received */ void _kbfun_exec_key( KBFUN_FUNCTION_ARGS ) { kbfun_funptr_t key_function = ( (pressed_) ? kb_layout_press_get(layer_, *row_, *col_) : kb_layout_release_get(layer_, *row_, *col_) ); if (key_function) (*key_function)( pressed_, kb_layout_get(layer_, *row_, *col_), layer_, row_, col_, current_layer_, current_layers_, pressed_layers_ ); } // ---------------------------------------------------------------------------- // private functions // ---------------------------------------------------------------------------- /* * Generate a normal keypress or keyrelease * * Arguments * - keycode: the keycode to use * - pressed: whether to generate a keypress (true) or keyrelease (false) * * 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 _press_release(bool pressed, uint8_t keycode) { // no-op if (keycode == 0) return; // modifier keys switch (keycode) { case KEY_LeftControl: (pressed) ? (keyboard_modifier_keys |= (1<<0)) : (keyboard_modifier_keys &= ~(1<<0)); return; case KEY_LeftShift: (pressed) ? (keyboard_modifier_keys |= (1<<1)) : (keyboard_modifier_keys &= ~(1<<1)); return; case KEY_LeftAlt: (pressed) ? (keyboard_modifier_keys |= (1<<2)) : (keyboard_modifier_keys &= ~(1<<2)); return; case KEY_LeftGUI: (pressed) ? (keyboard_modifier_keys |= (1<<3)) : (keyboard_modifier_keys &= ~(1<<3)); return; case KEY_RightControl: (pressed) ? (keyboard_modifier_keys |= (1<<4)) : (keyboard_modifier_keys &= ~(1<<4)); return; case KEY_RightShift: (pressed) ? (keyboard_modifier_keys |= (1<<5)) : (keyboard_modifier_keys &= ~(1<<5)); return; case KEY_RightAlt: (pressed) ? (keyboard_modifier_keys |= (1<<6)) : (keyboard_modifier_keys &= ~(1<<6)); return; case KEY_RightGUI: (pressed) ? (keyboard_modifier_keys |= (1<<7)) : (keyboard_modifier_keys &= ~(1<<7)); return; } // all others for (uint8_t i=0; i<6; i++) { if (pressed) { if (keyboard_keys[i] == 0) { keyboard_keys[i] = keycode; return; } } else { if (keyboard_keys[i] == keycode) { keyboard_keys[i] = 0; return; } } } } /* * Set current layer * - Sets any keys currently set to the overall current layer to the new layer, * and then sets the overall current layer * * Arguments * - layer: the new layer value * - current_layer: (a pointer to) the overall current layer (see main.c) * - current_layers: (a pointer to a matrix of) the current layer for each key * (see main.c and lib/key-functions.h) * * Note * - Leaving all non-current layer values alone allows changing layers while * maintaining a possibly enabled layer mask (as might be used to implement * firmware enabled numlock) */ void _layer_set_current( uint8_t layer, uint8_t * current_layer, uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] ) { // don't switch to out-of-bounds layers if ( layer < 0 || layer >= KB_LAYERS ) return; for (uint8_t row=0; row= KB_LAYERS ) return; for (uint8_t row=0; row capslock * - 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( KBFUN_FUNCTION_ARGS ) { static uint8_t keys_pressed; static bool lshift_pressed; static bool rshift_pressed; if (!pressed_) keys_pressed--; // take care of the key that was actually pressed _press_release(pressed_, keycode_); // take care of capslock (only on the press of the 2nd key) if (keys_pressed == 1 && pressed_) { // save the state of left and right shift lshift_pressed = _is_pressed(KEY_LeftShift); rshift_pressed = _is_pressed(KEY_RightShift); // disable both _press_release(false, KEY_LeftShift); _press_release(false, KEY_RightShift); // press capslock, then release it _press_release(true, KEY_CapsLock); usb_keyboard_send(); _press_release(false, KEY_CapsLock); usb_keyboard_send(); // restore the state of left and right shift if (lshift_pressed) _press_release(true, KEY_LeftShift); if (rshift_pressed) _press_release(true, KEY_RightShift); } if (pressed_) keys_pressed++; } // TODO: maybe the numpad functions (and other logical sets of functions?) need // to be in (a) seaparate file(s). /* ---------------------------------------------------------------------------- * Numpad functions * - Functions to implement an embedded numpad * * Notes * - The numpad is toggled by shifting (without changing the overall current * layer) the layer of the keys specified in this function to the value * specified in the keymap * - When the numpad is toggled, the numlock is set to on (for active) or off * (for inactive) as well * - All these functions cooperate, but if more than one layer mask of this * type is used (by a different set of functions) at the same time, the * second will override the first, and any keys covered by both will be reset * to the overall current layer when either is released (even if the other is * still pressed) * ------------------------------------------------------------------------- */ // prefix function (undefined later) // - to keep these names reasonable in this block, and obviously not global // outside it // - 'L' is for 'local' #define L(name) _kbfun_layermask_numpad__##name // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // vars static bool L(numpad_activated) = false; static bool L(layer_mask)[KB_ROWS][KB_COLUMNS] = MATRIX_LAYER( // unused 0, // left hand 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // right hand 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); // functions static inline void L(toggle_numlock)(void) { _press_release(true, KEYPAD_NumLock_Clear); usb_keyboard_send(); _press_release(false, KEYPAD_NumLock_Clear); usb_keyboard_send(); } static void L(toggle_numpad)( uint8_t numpad_layer, uint8_t current_layer, uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] ) { if (L(numpad_activated)) { // deactivate numpad _layer_set_mask(current_layer, L(layer_mask), current_layers); L(numpad_activated) = false; // if: numlock on if (keyboard_leds & (1<<0)) L(toggle_numlock)(); } else { // activate numpad _layer_set_mask(numpad_layer, L(layer_mask), current_layers); L(numpad_activated) = true; // if: numlock off if (!(keyboard_leds & (1<<0))) L(toggle_numlock)(); } } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . /* * Numpad toggle * - Toggles the numpad and sets numlock on (for active) or off (for inactive) * with it, if it's not already in that state */ void kbfun_layermask_numpad_toggle( KBFUN_FUNCTION_ARGS ) { L(toggle_numpad)(keycode_, *current_layer_, current_layers_); } /* * Numpad on * - Set the numpad on (along with numlock, if it's not already) */ void kbfun_layermask_numpad_on( KBFUN_FUNCTION_ARGS ) { if (!L(numpad_activated)) L(toggle_numpad)(keycode_, *current_layer_, current_layers_); } /* * Numpad off * - Set the numpad off (along with numlock, if it's not already) */ void kbfun_layermask_numpad_off( KBFUN_FUNCTION_ARGS ) { if (L(numpad_activated)) L(toggle_numpad)(keycode_, *current_layer_, current_layers_); } // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // prefix function (undefined here) #undef L /* ---------------------------------------------------------------------------- * ------------------------------------------------------------------------- */ // ---------------------------------------------------------------------------- // public functions (device specific) // ---------------------------------------------------------------------------- void kbfun_jump_to_bootloader( KBFUN_FUNCTION_ARGS ) { // from PJRC (slightly modified) // #if MAKEFILE_BOARD == teensy-2-0 // --- for all Teensy boards cli(); // disable watchdog, if enabled // disable all peripherals UDCON = 1; USBCON = (1<