2012-04-10 10:44:27 +02:00
/* ----------------------------------------------------------------------------
* 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
// ----------------------------------------------------------------------------
2016-06-12 06:04:40 +02:00
// layout data
2016-06-12 02:31:58 +02:00
// ----------------------------------------------------------------------------
2016-06-12 06:04:40 +02:00
# include "./keyboard/layout.c"
// defines:
2016-08-21 19:25:08 +02:00
// #define KB_LAYERS #{Layers.size}
2016-08-22 00:50:03 +02:00
// 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];
2016-08-21 20:32:32 +02:00
/* static u8 layers[KB_LAYERS] = {0, 1, 1+2, 3, 4, 2+3+4}; */
2016-06-12 06:04:40 +02:00
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
2016-06-12 06:04:40 +02:00
// ----------------------------------------------------------------------------
// 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
2016-08-09 03:51:24 +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
2012-07-31 23:48:31 +02:00
// ----------------------------------------------------------------------------
2012-04-10 10:44:27 +02:00
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 ;
2012-04-10 10:44:27 +02:00
}
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
// ----------------------------------------------------------------------------
2012-11-30 21:06:41 +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 07:35:27 +01:00
2016-02-04 10:59:15 +01:00
// the base layer is always active
return 0 ;
}
2012-12-04 01:19:12 +01:00
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-02-04 07:35:27 +01:00
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 07:35:27 +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 ) {
2016-02-04 16:28:11 +01:00
// base layer stays always on
2016-06-14 02:49:01 +02:00
if ( l > = KB_LAYERS | | l = = 0 ) { return ; }
2016-02-13 23:08:05 +01:00
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 ) {
2016-08-21 20:32:32 +02:00
keyfunc func = ( kb_keyfunc ( l , row , col ) ) ;
2016-08-09 03:51:24 +02:00
// 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
}
}
2016-02-04 07:35:27 +01:00
}
2013-04-08 09:49:35 +02:00
}
2016-06-12 01:51:39 +02:00
2016-08-09 03:51:24 +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
// ----------------------------------------------------------------------------
2016-08-22 00:50:03 +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 ) {
2016-08-21 20:32:32 +02:00
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 ) ;
}
2016-08-22 18:26:44 +02:00
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
}