/* ---------------------------------------------------------------------------- * main() * ---------------------------------------------------------------------------- * Copyright (c) 2012 Ben Blazak * Released under The MIT License (MIT) (see "license.md") * Project located at * ------------------------------------------------------------------------- */ #include #include // -------------------------------------------------------------------- // hardware // -------------------------------------------------------------------- #define KBD_DEBUG // comment out to disable the debug interface completely #include "./keyboard/controller.c" #include "./keyboard/keyboard.h" // -------------------------------------------------------------------- // types and forward declarations // -------------------------------------------------------------------- typedef uint8_t u8; typedef uint16_t u16; typedef enum StickyState { StickyNone, StickyOnceDown, StickyOnceUp, } StickyState; typedef u8 keycode; typedef u16 media_keycode; typedef u8 layer; typedef void (*keyfunc)(void); #include "./main.h" // ---------------------------------------------------------------------------- // layout data // ---------------------------------------------------------------------------- #include "./keyboard/layout.c" // defines: // #define KB_Layers #{Layers.size} // static const keycode PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS]; // static const keyfunc PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS]; // static const keyfunc PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS]; // ---------------------------------------------------------------------------- // globals // ---------------------------------------------------------------------------- static bool _kb_is_pressed[KB_ROWS][KB_COLUMNS]; static bool (*kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_is_pressed; static bool _kb_was_pressed[KB_ROWS][KB_COLUMNS]; static bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_was_pressed; static layer layers_pressed[KB_ROWS][KB_COLUMNS]; static u8 current_row; static u8 current_col; static layer current_layer; static keycode current_keycode; static bool current_is_pressed; static bool sticky_done; static bool layers_active[KB_LAYERS]; static StickyState layers_sticky[KB_LAYERS]; static layer layers_top = 0; // ---------------------------------------------------------------------------- int main() { kb_init(); usb_init(); while (!usb_configured()); // initialize layers init_layers(); // never return main_key_loop(); return 0; } // -------------------------------------------------------------------------------------- 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); // - execute key functions when their key changes state // - keep track of which layers the keys were on when they were pressed // (so they can be released using the function from that layer) for (u8 row=0; row 0 && l < KB_LAYERS; l--) { if (layers_active[l]) { return l; } } } // the base layer is always active return 0; } // return if highest active layer is sticky StickyState layer_top_sticky() { return layer_sticky(layers_top); } // return if layer is sticky StickyState layer_sticky(layer l) { if (l < KB_LAYERS) { return layers_sticky[l]; } return StickyNone; } // enable a layer void layer_enable(layer l, StickyState sticky) { // FIXME split off sticky part if (l >= KB_LAYERS) { return; } layers_active[l] = true; layers_sticky[l] = sticky; if (l > layers_top) { layers_top = l; } } // disable a layer void layer_disable(layer l) { // base layer stays always on if (l >= KB_LAYERS || l == 0) { return; } layers_active[l] = false; if (layers_sticky[l] != StickyNone) { debug_printf("sticky %d up!\n", l); } layers_sticky[l] = StickyNone; if (l == layers_top) { layers_top = highest_active_layer(1); } } // disable the highest active layer void layer_disable_top() { layer_disable(layers_top); } // return layer offset elements below the top layer layer_peek(layer offset) { return highest_active_layer(offset); } bool is_layer_enable(keyfunc f) { if (f == &kbfun_layer_enable || f == &kbfun_layer_sticky) { return true; } return false; } bool is_layer_disable(keyfunc f) { if (f == &kbfun_layer_disable || f == &kbfun_layer_sticky) { return true; } return false; } void layer_enable_upto(layer max_layer) { // FIXME clean this up // pressing a key implicitly activates all lower layers as well for (layer l=0; l <= KB_LAYERS; l++) { void (*key_function)(void) = kb_keyfunc_press(l, current_row, current_col); if (is_layer_enable(key_function)) { layer enable_layer = (layer) kb_keycode(l, current_row, current_col); if (enable_layer <= max_layer) { layer_enable(enable_layer, StickyNone); } } } } // ---------------------------------------------------------------------------- // layout info // ---------------------------------------------------------------------------- keycode kb_keycode (layer l, u8 row, u8 col) { return (keycode) pgm_read_byte(&(_kb_layout[l][row][col])); } keyfunc kb_keyfunc_press (layer l, u8 row, u8 col) { return (keyfunc) pgm_read_word(&(_kb_layout_press[l][row][col])); } keyfunc kb_keyfunc_release (layer l, u8 row, u8 col) { return (keyfunc) pgm_read_word(&(_kb_layout_release[l][row][col])); } // ---------------------------------------------------------------------------- // keyfunc primitives // ---------------------------------------------------------------------------- // basic keypresses void _kbfun_normal_press_release(bool press, keycode key) { if (key == 0) { return; } // noop if (press) { for (u8 i=0; i < sizeof(keyboard_keys); i++) { if (keyboard_keys[i] == 0) { keyboard_keys[i] = key; return; } } } else { for (u8 i=0; i < sizeof(keyboard_keys); i++) { if (keyboard_keys[i] == key) { keyboard_keys[i] = 0; return; } } } } void _kbfun_mediakey_press_release(bool press, keycode key) { media_keycode media_key = _media_code_lookup_table[key]; if (press) { 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; } } } void _kbfun_modifier_press_release(bool press, keycode key) { if (press) { keyboard_modifier_keys |= (1<