#include "action.h" | #include "action.h" | ||||
/* default layer indicates base layer */ | |||||
uint8_t default_layer = 0; | |||||
/* current layer indicates active layer at this time */ | |||||
uint8_t current_layer = 0; | |||||
static void process_action(keyrecord_t *record); | static void process_action(keyrecord_t *record); | ||||
static bool process_tapping(keyrecord_t *record); | static bool process_tapping(keyrecord_t *record); | ||||
static void waiting_buffer_scan_tap(void); | static void waiting_buffer_scan_tap(void); | ||||
static action_t get_action(key_t key) | static action_t get_action(key_t key) | ||||
{ | { | ||||
action_t action = keymap_get_action(current_layer, key.pos.row, key.pos.col); | |||||
action_t action = action_for_key(current_layer, key); | |||||
/* Transparently use default layer */ | /* Transparently use default layer */ | ||||
if (action.code == ACTION_TRANSPARENT) { | if (action.code == ACTION_TRANSPARENT) { | ||||
// TODO: layer stacking | // TODO: layer stacking | ||||
action = keymap_get_action(default_layer, key.pos.row, key.pos.col); | |||||
action = action_for_key(default_layer, key); | |||||
debug("TRNASPARENT: "); debug_hex16(action.code); debug("\n"); | debug("TRNASPARENT: "); debug_hex16(action.code); debug("\n"); | ||||
} | } | ||||
return action; | return action; | ||||
/* Extentions */ | /* Extentions */ | ||||
case ACT_MACRO: | case ACT_MACRO: | ||||
// TODO | |||||
break; | break; | ||||
case ACT_COMMAND: | case ACT_COMMAND: | ||||
break; | break; | ||||
case ACT_FUNCTION: | case ACT_FUNCTION: | ||||
// TODO | |||||
keymap_call_function(record, action.func.id, action.func.opt); | |||||
action_function(record, action.func.id, action.func.opt); | |||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
*/ | */ | ||||
static void debug_event(keyevent_t event) | static void debug_event(keyevent_t event) | ||||
{ | { | ||||
debug_hex16(event.key.raw); | |||||
debug_hex16((event.key.row<<8) | event.key.col); | |||||
if (event.pressed) debug("d("); else debug("u("); | if (event.pressed) debug("d("); else debug("u("); | ||||
debug_dec(event.time); debug(")"); | debug_dec(event.time); debug(")"); | ||||
} | } |
#include "keycode.h" | #include "keycode.h" | ||||
/* Execute action per keyevent */ | |||||
void action_exec(keyevent_t event); | |||||
/* Struct to record event and tap count */ | /* Struct to record event and tap count */ | ||||
typedef struct { | typedef struct { | ||||
keyevent_t event; | keyevent_t event; | ||||
/* Action struct. | /* Action struct. | ||||
* | * | ||||
* In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). | |||||
* In avr-gcc bit field seems to be assigned from LSB(bit0) to MSB(bit15). | |||||
* AVR looks like a little endian in avr-gcc. | * AVR looks like a little endian in avr-gcc. | ||||
* | * | ||||
* NOTE: not portable across compiler/endianness? | * NOTE: not portable across compiler/endianness? | ||||
} action_t; | } action_t; | ||||
/* layer used currently */ | |||||
extern uint8_t current_layer; | |||||
/* layer to return or start with */ | |||||
extern uint8_t default_layer; | |||||
/* Execute action per keyevent */ | |||||
void action_exec(keyevent_t event); | |||||
/* action for key */ | |||||
action_t action_for_key(uint8_t layer, key_t key); | |||||
/* user defined special function */ | |||||
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt); | |||||
/* | /* | ||||
* Utilities for actions. | * Utilities for actions. | ||||
*/ | */ | ||||
/* | /* | ||||
* Action codes | * Action codes | ||||
* ============ | * ============ | ||||
* 16bit code: action_kind(4bit) + action_parameter(12bit) | * 16bit code: action_kind(4bit) + action_parameter(12bit) | ||||
* | * | ||||
Keyboard Keys | |||||
------------- | |||||
ACT_LMODS(0000): | |||||
0000|0000|000000|00 No action | |||||
0000|0000|000000|01 Transparent | |||||
0000|0000| keycode Key | |||||
0000|mods|000000|00 Left mods | |||||
0000|mods| keycode Key & Left mods | |||||
ACT_RMODS(0001): | |||||
0001|0000|000000|00 No action(not used) | |||||
0001|0000|000000|01 Transparent(not used) | |||||
0001|0000| keycode Key(no used) | |||||
0001|mods|000000|00 Right mods | |||||
0001|mods| keycode Key & Right mods | |||||
ACT_LMODS_TAP(0010): | |||||
0010|mods|000000|00 Left mods OneShot | |||||
0010|mods|000000|01 (reserved) | |||||
0010|mods|000000|10 (reserved) | |||||
0010|mods|000000|11 (reserved) | |||||
0010|mods| keycode Left mods + tap Key | |||||
ACT_RMODS_TAP(0011): | |||||
0011|mods|000000|00 Right mods OneShot | |||||
0011|mods|000000|01 (reserved) | |||||
0011|mods|000000|10 (reserved) | |||||
0011|mods|000000|11 (reserved) | |||||
0011|mods| keycode Right mods + tap Key | |||||
Other HID Usage | |||||
--------------- | |||||
This action handles other usages than keyboard. | |||||
ACT_USAGE(0100): | |||||
0100|00| usage(10) System control(0x80) - General Desktop page(0x01) | |||||
0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C) | |||||
0100|10| usage(10) (reserved) | |||||
0100|11| usage(10) (reserved) | |||||
Mouse Keys | |||||
---------- | |||||
TODO: can be combined with 'Other HID Usage'? to save action kind id. | |||||
ACT_MOUSEKEY(0110): | |||||
0101|XXXX| keycode Mouse key | |||||
Layer Actions | |||||
------------- | |||||
ACT_LAYER(1000): Set layer | |||||
ACT_LAYER_BIT(1001): Bit-op layer | |||||
1000|LLLL|0000 0000 set L to layer on press and set default on release(momentary) | |||||
1000|LLLL|0000 0001 set L to layer on press | |||||
1000|LLLL|0000 0010 set L to layer on release | |||||
1000|----|0000 0011 set default to layer on both(return to default layer) | |||||
1000|LLLL| keycode set L to layer while hold and send key on tap | |||||
1000|LLLL|1111 0000 set L to layer while hold and toggle on several taps | |||||
1000|LLLL|1111 1111 set L to default and layer(on press) | |||||
1001|BBBB|0000 0000 (not used) | |||||
1001|BBBB|0000 0001 bit-xor layer with B on press | |||||
1001|BBBB|0000 0010 bit-xor layer with B on release | |||||
1001|BBBB|0000 0011 bit-xor layer with B on both(momentary) | |||||
1001|BBBB| keycode bit-xor layer with B while hold and send key on tap | |||||
1001|BBBB|1111 0000 bit-xor layer with B while hold and toggle on several taps | |||||
1001|BBBB|1111 1111 bit-xor default with B and set layer(on press) | |||||
Extensions(11XX) | |||||
---------------- | |||||
NOTE: NOT FIXED | |||||
ACT_MACRO(1100): | |||||
1100|opt | id(8) Macro play? | |||||
1100|1111| id(8) Macro record? | |||||
ACT_COMMAND(1110): | |||||
1110|opt | id(8) Built-in Command exec | |||||
ACT_FUNCTION(1111): | |||||
1111| address(12) Function? | |||||
1111|opt | id(8) Function? | |||||
* Keyboard Keys | |||||
* ------------- | |||||
* ACT_LMODS(0000): | |||||
* 0000|0000|000000|00 No action | |||||
* 0000|0000|000000|01 Transparent | |||||
* 0000|0000| keycode Key | |||||
* 0000|mods|000000|00 Left mods | |||||
* 0000|mods| keycode Key & Left mods | |||||
* | |||||
* ACT_RMODS(0001): | |||||
* 0001|0000|000000|00 No action(not used) | |||||
* 0001|0000|000000|01 Transparent(not used) | |||||
* 0001|0000| keycode Key(no used) | |||||
* 0001|mods|000000|00 Right mods | |||||
* 0001|mods| keycode Key & Right mods | |||||
* | |||||
* ACT_LMODS_TAP(0010): | |||||
* 0010|mods|000000|00 Left mods OneShot | |||||
* 0010|mods|000000|01 (reserved) | |||||
* 0010|mods|000000|10 (reserved) | |||||
* 0010|mods|000000|11 (reserved) | |||||
* 0010|mods| keycode Left mods + tap Key | |||||
* | |||||
* ACT_RMODS_TAP(0011): | |||||
* 0011|mods|000000|00 Right mods OneShot | |||||
* 0011|mods|000000|01 (reserved) | |||||
* 0011|mods|000000|10 (reserved) | |||||
* 0011|mods|000000|11 (reserved) | |||||
* 0011|mods| keycode Right mods + tap Key | |||||
* | |||||
* | |||||
* Other HID Usage | |||||
* --------------- | |||||
* This action handles other usages than keyboard. | |||||
* ACT_USAGE(0100): | |||||
* 0100|00| usage(10) System control(0x80) - General Desktop page(0x01) | |||||
* 0100|01| usage(10) Consumer control(0x01) - Consumer page(0x0C) | |||||
* 0100|10| usage(10) (reserved) | |||||
* 0100|11| usage(10) (reserved) | |||||
* | |||||
* | |||||
* Mouse Keys | |||||
* ---------- | |||||
* TODO: can be combined with 'Other HID Usage'? to save action kind id. | |||||
* ACT_MOUSEKEY(0110): | |||||
* 0101|XXXX| keycode Mouse key | |||||
* | |||||
* | |||||
* Layer Actions | |||||
* ------------- | |||||
* ACT_LAYER(1000): Set layer | |||||
* ACT_LAYER_BIT(1001): Bit-op layer | |||||
* | |||||
* 1000|LLLL|0000 0000 set L to layer on press and set default on release(momentary) | |||||
* 1000|LLLL|0000 0001 set L to layer on press | |||||
* 1000|LLLL|0000 0010 set L to layer on release | |||||
* 1000|----|0000 0011 set default to layer on both(return to default layer) | |||||
* 1000|LLLL| keycode set L to layer while hold and send key on tap | |||||
* 1000|LLLL|1111 0000 set L to layer while hold and toggle on several taps | |||||
* 1000|LLLL|1111 1111 set L to default and layer(on press) | |||||
* | |||||
* 1001|BBBB|0000 0000 (not used) | |||||
* 1001|BBBB|0000 0001 bit-xor layer with B on press | |||||
* 1001|BBBB|0000 0010 bit-xor layer with B on release | |||||
* 1001|BBBB|0000 0011 bit-xor layer with B on both(momentary) | |||||
* 1001|BBBB| keycode bit-xor layer with B while hold and send key on tap | |||||
* 1001|BBBB|1111 0000 bit-xor layer with B while hold and toggle on several taps | |||||
* 1001|BBBB|1111 1111 bit-xor default with B and set layer(on press) | |||||
* | |||||
* | |||||
* | |||||
* Extensions(11XX) | |||||
* ---------------- | |||||
* NOTE: NOT FIXED | |||||
* | |||||
* ACT_MACRO(1100): | |||||
* 1100|opt | id(8) Macro play? | |||||
* 1100|1111| id(8) Macro record? | |||||
* | |||||
* ACT_COMMAND(1110): | |||||
* 1110|opt | id(8) Built-in Command exec | |||||
* | |||||
* ACT_FUNCTION(1111): | |||||
* 1111| address(12) Function? | |||||
* 1111|opt | id(8) Function? | |||||
* | |||||
*/ | */ | ||||
enum action_kind_id { | enum action_kind_id { | ||||
ACT_LMODS = 0b0000, | ACT_LMODS = 0b0000, | ||||
#define ACTION_RMOD_ONESHOT(mod) ACTION(ACT_RMODS_TAP, MODS4(MOD_BIT(mod))<<8 | MODS_ONESHOT) | #define ACTION_RMOD_ONESHOT(mod) ACTION(ACT_RMODS_TAP, MODS4(MOD_BIT(mod))<<8 | MODS_ONESHOT) | ||||
/* | |||||
/* | |||||
* Switch layer | * Switch layer | ||||
*/ | */ | ||||
enum layer_codes { | enum layer_codes { | ||||
DEFAULT_ON_BOTH = 3, | DEFAULT_ON_BOTH = 3, | ||||
}; | }; | ||||
/* | |||||
/* | |||||
* return to default layer | * return to default layer | ||||
*/ | */ | ||||
#define ACTION_LAYER_DEFAULT ACTION_LAYER_DEFAULT_R | #define ACTION_LAYER_DEFAULT ACTION_LAYER_DEFAULT_R | ||||
/* set default layer on both press and release */ | /* set default layer on both press and release */ | ||||
#define ACTION_LAYER_SET_DEFAULT(layer) ACTION(ACT_LAYER, (layer)<<8 | LAYER_CHANGE_DEFAULT) | #define ACTION_LAYER_SET_DEFAULT(layer) ACTION(ACT_LAYER, (layer)<<8 | LAYER_CHANGE_DEFAULT) | ||||
/* | |||||
/* | |||||
* Bit-op layer | * Bit-op layer | ||||
*/ | */ | ||||
/* bit-xor on both press and release */ | /* bit-xor on both press and release */ |
for (uint8_t c = 0; c < MATRIX_COLS; c++) { | for (uint8_t c = 0; c < MATRIX_COLS; c++) { | ||||
if (matrix_change & ((matrix_row_t)1<<c)) { | if (matrix_change & ((matrix_row_t)1<<c)) { | ||||
action_exec((keyevent_t){ | action_exec((keyevent_t){ | ||||
.key.pos = (keypos_t){ .row = r, .col = c }, | |||||
.key = (key_t){ .row = r, .col = c }, | |||||
.pressed = (matrix_row & (1<<c)), | .pressed = (matrix_row & (1<<c)), | ||||
.time = (timer_read() | 1) /* time should not be 0 */ | .time = (timer_read() | 1) /* time should not be 0 */ | ||||
}); | }); |
typedef struct { | typedef struct { | ||||
uint8_t col; | uint8_t col; | ||||
uint8_t row; | uint8_t row; | ||||
} keypos_t; | |||||
// TODO: need raw? keypos_t -> key_t? | |||||
typedef union { | |||||
uint16_t raw; | |||||
keypos_t pos; | |||||
} key_t; | } key_t; | ||||
/* key event */ | /* key event */ | ||||
} keyevent_t; | } keyevent_t; | ||||
/* equivalent test of key_t */ | /* equivalent test of key_t */ | ||||
#define KEYEQ(keya, keyb) ((keya).raw == (keyb).raw) | |||||
#define KEYEQ(keya, keyb) ((keya).row == (keyb).row && (keya).col == (keyb).col) | |||||
/* (time == 0) means no event and assumes matrix has no 255 line. */ | /* (time == 0) means no event and assumes matrix has no 255 line. */ | ||||
#define IS_NOEVENT(event) ((event).time == 0 || ((event).key.pos.row == 255 && (event).key.pos.col == 255)) | |||||
#define IS_NOEVENT(event) ((event).time == 0 || ((event).key.row == 255 && (event).key.col == 255)) | |||||
#define NOEVENT (keyevent_t){ \ | #define NOEVENT (keyevent_t){ \ | ||||
.key.pos = (keypos_t){ .row = 255, .col = 255 }, \ | |||||
.key = (key_t){ .row = 255, .col = 255 }, \ | |||||
.pressed = false, \ | .pressed = false, \ | ||||
.time = 0 \ | .time = 0 \ | ||||
} | } | ||||
/* tick event */ | /* tick event */ | ||||
#define TICK (keyevent_t){ \ | #define TICK (keyevent_t){ \ | ||||
.key.pos = (keypos_t){ .row = 255, .col = 255 }, \ | |||||
.key = (key_t){ .row = 255, .col = 255 }, \ | |||||
.pressed = false, \ | .pressed = false, \ | ||||
.time = (timer_read() | 1) \ | .time = (timer_read() | 1) \ | ||||
} | } |
#include "action.h" | #include "action.h" | ||||
/* layer */ | |||||
uint8_t default_layer = 0; | |||||
uint8_t current_layer = 0; | |||||
action_t keymap_keycode_to_action(uint8_t keycode) | action_t keymap_keycode_to_action(uint8_t keycode) | ||||
{ | { | ||||
action_t action; | action_t action; | ||||
#ifndef NO_LEGACY_KEYMAP_SUPPORT | #ifndef NO_LEGACY_KEYMAP_SUPPORT | ||||
/* legacy support with weak reference */ | /* legacy support with weak reference */ | ||||
__attribute__ ((weak)) | __attribute__ ((weak)) | ||||
action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) | |||||
action_t action_for_key(uint8_t layer, key_t key) | |||||
{ | { | ||||
/* convert from legacy keycode to action */ | /* convert from legacy keycode to action */ | ||||
uint8_t keycode = keymap_get_keycode(layer, row, col); | |||||
uint8_t keycode = keymap_get_keycode(layer, key.row, key.col); | |||||
action_t action; | action_t action; | ||||
switch (keycode) { | switch (keycode) { | ||||
case KC_FN0 ... KC_FN31: | case KC_FN0 ... KC_FN31: | ||||
#endif | #endif | ||||
__attribute__ ((weak)) | __attribute__ ((weak)) | ||||
void keymap_call_function(keyrecord_t *event, uint8_t id, uint8_t opt) | |||||
void action_function(keyrecord_t *event, uint8_t id, uint8_t opt) | |||||
{ | { | ||||
} | } |
#include "action.h" | #include "action.h" | ||||
// TODO: move to action.h? | |||||
/* layer used currently */ | |||||
extern uint8_t current_layer; | |||||
/* layer to return or start with */ | |||||
extern uint8_t default_layer; | |||||
/* translates key_t to keycode */ | /* translates key_t to keycode */ | ||||
uint8_t keymap_key_to_keycode(uint8_t layer, key_t key); | uint8_t keymap_key_to_keycode(uint8_t layer, key_t key); | ||||
/* translates keycode to action */ | /* translates keycode to action */ | ||||
action_t keymap_fn_to_action(uint8_t keycode); | action_t keymap_fn_to_action(uint8_t keycode); | ||||
/* action for key */ | |||||
// TODO: should use struct key_t? move to action.h? | |||||
action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col); | |||||
/* user defined special function */ | |||||
void keymap_call_function(keyrecord_t *record, uint8_t id, uint8_t opt); | |||||
#ifndef NO_LEGACY_KEYMAP_SUPPORT | #ifndef NO_LEGACY_KEYMAP_SUPPORT | ||||
/* keycode of key */ | /* keycode of key */ | ||||
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col); | uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col); | ||||
/* layer to move during press Fn key */ | /* layer to move during press Fn key */ | ||||
uint8_t keymap_fn_layer(uint8_t fn_bits); | uint8_t keymap_fn_layer(uint8_t fn_bits); | ||||
/* keycode to send when release Fn key without using */ | /* keycode to send when release Fn key without using */ | ||||
uint8_t keymap_fn_keycode(uint8_t fn_bits); | uint8_t keymap_fn_keycode(uint8_t fn_bits); | ||||
#endif | #endif |
/* translates key to keycode */ | /* translates key to keycode */ | ||||
uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) | uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) | ||||
{ | { | ||||
return pgm_read_byte(&keymaps[(layer)][(key.pos.row)][(key.pos.col)]); | |||||
return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); | |||||
} | } | ||||
/* translates Fn index to action */ | /* translates Fn index to action */ | ||||
} | } | ||||
/* convert key to action */ | /* convert key to action */ | ||||
action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) | |||||
action_t action_for_key(uint8_t layer, key_t key) | |||||
{ | { | ||||
key_t key; | |||||
key.pos.row = row; | |||||
key.pos.col = col; | |||||
uint8_t keycode = keymap_key_to_keycode(layer, key); | uint8_t keycode = keymap_key_to_keycode(layer, key); | ||||
switch (keycode) { | switch (keycode) { | ||||
case KC_FN0 ... KC_FN31: | case KC_FN0 ... KC_FN31: |
/* translates key to keycode */ | /* translates key to keycode */ | ||||
uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) | uint8_t keymap_key_to_keycode(uint8_t layer, key_t key) | ||||
{ | { | ||||
return pgm_read_byte(&keymaps[(layer)][(key.pos.row)][(key.pos.col)]); | |||||
return pgm_read_byte(&keymaps[(layer)][(key.row)][(key.col)]); | |||||
} | } | ||||
/* translates Fn index to action */ | /* translates Fn index to action */ | ||||
} | } | ||||
/* convert key to action */ | /* convert key to action */ | ||||
action_t keymap_get_action(uint8_t layer, uint8_t row, uint8_t col) | |||||
action_t action_for_key(uint8_t layer, key_t key) | |||||
{ | { | ||||
key_t key; | |||||
key.pos.row = row; | |||||
key.pos.col = col; | |||||
uint8_t keycode = keymap_key_to_keycode(layer, key); | uint8_t keycode = keymap_key_to_keycode(layer, key); | ||||
switch (keycode) { | switch (keycode) { | ||||
case KC_FN0 ... KC_FN31: | case KC_FN0 ... KC_FN31: |