fixing up the ...exec_key...() functions

just need to implement eeprom_macro's in a layout now, to test them!
partial-rewrite
Ben Blazak 2014-05-27 21:42:01 -07:00
parent c5afdb9659
commit 74c685a8b4
8 changed files with 135 additions and 54 deletions

View File

@ -145,7 +145,11 @@
* [Why do we need C Unions?]
(http://stackoverflow.com/questions/252552/why-do-we-need-c-unions)
Some good examples of what Unions are good for.
Some examples of what unions are good for.
* [Using and Abusing Unions]
(http://critical.eschertech.com/2010/03/12/using-and-abusing-unions/)
A good discussion on when to use unions and when not to.
* [C preprocessor, recursive macros]
(http://stackoverflow.com/questions/5641836/c-preprocessor-recursive-macros)
@ -728,7 +732,7 @@
-------------------------------------------------------------------------------
Copyright &copy; 2012, 2013 Ben Blazak <benblazak.dev@gmail.com>
Copyright &copy; 2012, 2013, 2014 Ben Blazak <benblazak.dev@gmail.com>
Released under The MIT License (see "doc/licenses/MIT.md")
Project located at <https://github.com/benblazak/ergodox-firmware>

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Copyright (c) 2012, 2014 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (see "doc/licenses/MIT.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
@ -57,7 +57,13 @@ void kb__led__delay__usb_init (void);
void kb__led__logical_on (char led);
void kb__led__logical_off (char led);
// -------
void kb__layout__exec_key (bool pressed, uint8_t row, uint8_t column);
void kb__layout__exec_key ( bool pressed,
uint8_t row,
uint8_t column );
void kb__layout__exec_key_layer ( bool pressed,
uint8_t layer,
uint8_t row,
uint8_t column );
// ----------------------------------------------------------------------------
@ -280,3 +286,22 @@ void kb__layout__exec_key (bool pressed, uint8_t row, uint8_t column);
* etc. from `main()`.
*/
// === kb__layout__exec_key_layer ===
/** functions/kb__layout__exec_key_layer/description
* Perform the appropriate actions for a "press" or "release" of the key at the
* given position, on the given layer.
*
* Arguments:
* - `pressed`:
* - `true`: Indicates that the key to be "executed" has been pressed
* - `false`: Indicates that the key to be "executed" has been released
* - `layer`: The layer of the key to be "executed"
* - `row`: The row of the key to be "executed"
* - `column`: The column of the key to be "executed"
*
* Notes:
* - If the implementation does not support layers, the `layer` argument should
* be ignored, and this function will be equivalent to
* `kb__layout__exec_key()`.
*/

View File

@ -20,6 +20,7 @@
#include "../../../../../firmware/lib/timer.h"
#include "../../../../../firmware/lib/usb.h"
#include "../../../../../firmware/lib/usb/usage-page/keyboard.h"
#include "../../../../../firmware/lib/layout/eeprom-macro.h"
#include "../../../../../firmware/lib/layout/key-functions.h"
#include "../../../../../firmware/lib/layout/layer-stack.h"
#include "../../../../../firmware/keyboard.h"

View File

@ -12,55 +12,63 @@
*/
/** functions/kb__layout__exec_key/description
* Assumptions:
* - All arguments are valid.
*
* Implementation notes:
* - The default layer is layer 0.
* - This function is only responsible for layer resolution (which includes the
* handling of transparent keys). Everything else, it passes to
* `kb__layout__exec_key_layer()`.
*/
void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
// if we press a key, we need to keep track of the layer it was pressed on,
// so we can release it on the same layer
// - if the release is transparent, search through the layer stack for a
// non-transparent release in the same position, as normal
// - to keep track of the layer a key was pressed on, so we can release on
// the same layer
static uint8_t pressed_layer[OPT__KB__ROWS][OPT__KB__COLUMNS];
void (*function)(void);
uint8_t layer;
void (*function)(void);
// - add 1 to the stack size because we spend the first iteration checking
// to see if we need to release on a previously stored layer
// - add 1 to the stack size in order to peek out of bounds on the last
// iteration (if we get that far), so that layer 0 is our default (see
// the documentation for ".../firmware/lib/layout/layer-stack.h")
for (uint8_t i=0; i < layer_stack__size()+1+1; i++) { // i = offset+1
if (i == 0)
if (!pressed)
layer = pressed_layer[row][column];
else
continue;
else
layer = layer_stack__peek(i-1);
// handle the case that a key is released, and the layer it was pressed on
// has a non-transparent release function in the given location
if (! pressed) {
layer = pressed_layer[row][column];
function = (void (*)(void))
pgm_read_word( &( layout[ layer ]
[ row ]
[ column ]
[ (pressed) ? 0 : 1 ] ) );
pgm_read_word( &( layout[ layer ]
[ row ]
[ column ]
[ !pressed ] ) );
if (function == &KF(transp))
function = NULL;
if (function != &KF(transp)) {
kb__layout__exec_key_layer( pressed, layer, row, column );
return;
}
}
if (function) {
// otherwise, search through the layer stack for a layer with a
// non-transparent key-function in the given location
// - altogether, unless we find a non-transparent key-function earlier, we
// want to peek at offsets `0` through `layer_stack__size()`. this will
// cause us to peek out of bounds on the last iteration, so that layer 0
// will be the default (see the documentation for
// ".../lib/layout/layer-stack")
for (uint8_t i=0; i <= layer_stack__size(); i++) {
layer = layer_stack__peek(i);
function = (void (*)(void))
pgm_read_word( &( layout[ layer ]
[ row ]
[ column ]
[ !pressed ] ) );
if (function != &KF(transp)) {
if (pressed)
pressed_layer[row][column] = layer;
flags.tick_keypresses = (pressed) ? true : false; // set default
(*function)();
// TODO: *always* tick keypresses
// TODO: instead of this, set a flag for the type of key pressed,
// and any functions that execute can check it, and conditionally
// reschedule themselves to run later, if they so desire
if (flags.tick_keypresses)
timer___tick_keypresses();
kb__layout__exec_key_layer( pressed, layer, row, column );
return;
}
}
@ -68,3 +76,38 @@ void kb__layout__exec_key(bool pressed, uint8_t row, uint8_t column) {
// if we get here, there was a transparent key in layer 0; do nothing
}
/** functions/kb__layout__exec_key_layer/description
* Assumptions:
* - All arguments are valid.
*
* TODO:
* - take care of the recording and such of macros :)
*/
void kb__layout__exec_key_layer( bool pressed,
uint8_t layer,
uint8_t row,
uint8_t column ) {
void (*function)(void) = (void (*)(void))
pgm_read_word( &( layout[ layer ]
[ row ]
[ column ]
[ !pressed ] ) );
if (! function) return;
// set default values
// - the key-function will not be able to see the values set previously
// - any function scheduled to run will be able to see the values set
// previously; but that may change in the future, so it shouldn't be
// relied on. if functions need to communicate with each other, they
// should share a file-local or global variable.
flags.key_type.sticky = false;
flags.key_type.layer_shift = false;
flags.key_type.layer_lock = false;
(*function)();
if (pressed)
timer___tick_keypresses();
}

View File

@ -20,17 +20,24 @@ static layout_t layout PROGMEM;
/** variables/flags/description
* A collection of flags pertaining to the operation of `...exec_key()`
*
* Notes:
* - These should be set within key-functions, but only read inside
* `...exec_key()`. The ability to read them outside that function should
* not be counted on.
*
* Struct members:
* - `tick_keypresses`: A predicate indicating whether or not to "tick"
* keypresses on this run of the function (see the documentation in
* ".../firmware/lib/timer.h" for more precisely what this means)
* - This is useful for defining things like sticky keys, if, e.g., you
* want to make it so that you can press more than one and have none of
* them release until the press of the next normal key.
* - `key_type`: To indicate the type of key most recently pressed
* - More than one type flag may be set (e.g. a key may be both a
* layer-shift key and a sticky key).
* - `key_type.sticky`
* - `key_type.layer_shift`
* - `key_type.layer_lock`
*/
static struct {
bool tick_keypresses : 1;
} flags = {
.tick_keypresses = true,
};
struct {
bool sticky : 1;
bool layer_shift : 1;
bool layer_lock : 1;
} key_type;
} flags;

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* Copyright (c) 2013 Ben Blazak <benblazak.dev@gmail.com>
* Copyright (c) 2013, 2014 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (see "doc/licenses/MIT.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */

View File

@ -20,8 +20,9 @@
* alternating between valid and deleted. This would give us 1019/5/2 ~=
* 100 noncontiguous deleted macros, which would be about as many copy
* objects (plus a few write objects) in ".../lib/eeprom", so about 500
* bytes. SRAM is 2kB. Because of the way ".../lib/eeprom" is written,
* much of this data would have to be contiguous.
* bytes. SRAM is 2560 bytes (per the PJRC website). Because of the way
* ".../lib/eeprom" is written, much of this data would have to be
* contiguous.
* - At some point, I should probably consider changing how
* ".../lib/eeprom" (and the layer-stack code, and everything else that
* needs a variable amount of memory) manages its memory. Again, not

View File

@ -190,7 +190,7 @@ void timer___tick_keypresses (void);
// === timer___tick_keypresses() ===
/** functions/timer___tick_keypresses/description
* Increment the counter for the number of keypresses, and perform scheduled
* Increment the counter for the number of key-presses, and perform scheduled
* tasks
*
* Meant to be used only by `kb__layout__exec_key()`