~ruther/qmk_firmware

768ea72f109fee2411c77bf2fabcbede5f98650d — tmk 12 years ago c74ad26
Add layer_stack files taking apart from action.c
4 files changed, 167 insertions(+), 105 deletions(-)

M common.mk
M common/action.c
A common/layer_stack.c
A common/layer_stack.h
M common.mk => common.mk +1 -0
@@ 3,6 3,7 @@ SRC +=	$(COMMON_DIR)/host.c \
	$(COMMON_DIR)/keyboard.c \
	$(COMMON_DIR)/action.c \
	$(COMMON_DIR)/action_macro.c \
	$(COMMON_DIR)/layer_stack.c \
	$(COMMON_DIR)/keymap.c \
	$(COMMON_DIR)/command.c \
	$(COMMON_DIR)/timer.c \

M common/action.c => common/action.c +22 -105
@@ 24,6 24,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
#include "util.h"
#include "debug.h"
#include "action.h"
#include "layer_stack.h"


/* default layer indicates base layer */


@@ 163,85 164,6 @@ static void oneshot_toggle(void)
}


/*
 * Layer stack
 */
#define LAYER_STACK_SIZE 8
typedef struct {
    uint8_t layer:4;
    uint8_t next:3;
    bool    used;
} layer_item_t;

static uint8_t top_layer = 0;
// [0] is sentinel and not used. [0] is null item.
static layer_item_t layer_stack[LAYER_STACK_SIZE] = {};

static bool layer_push(uint8_t layer)
{
    for (uint8_t i = 1; i < LAYER_STACK_SIZE; i++) {
        if (!layer_stack[i].used) {
            layer_stack[i] = (layer_item_t){ .layer = layer,
                                              .next = top_layer,
                                              .used = true };
            top_layer = i;
            return true;
        }
    }
    return false;
}
static bool layer_pop(void)
{
    if (layer_stack[top_layer].used) {
        uint8_t popped = top_layer;
        top_layer = layer_stack[popped].next;
        layer_stack[popped] = (layer_item_t){};
        return true;
    }
    return false;
}
static bool layer_remove(uint8_t layer)
{
    if (layer_stack[top_layer].used && layer_stack[top_layer].layer == layer) {
        layer_pop();
        debug("layer_remove: top_layer\n");
        return true;
    }

    for (uint8_t i = top_layer; layer_stack[i].used; i = layer_stack[i].next) {
        debug("layer_remove: ["); debug_dec(i); debug("]");
        debug_dec(layer_stack[i].layer); debug("\n");
        uint8_t removed = layer_stack[i].next;
        if (layer_stack[removed].used && layer_stack[removed].layer == layer) {
            layer_stack[i].next = layer_stack[removed].next;
            layer_stack[removed] = (layer_item_t){};
            debug("layer_remove: removed.\n");
            return true;
        }
    }
    return false;
}
static bool layer_remove_then_push(uint8_t layer)
{
    layer_remove(layer);
    return layer_push(layer);
}
static bool layer_remove_or_push(uint8_t layer)
{
    return (layer_remove(layer)) || layer_push(layer);
}
static void debug_layer_stack(void)
{
    debug("layer_stack: ");
    layer_item_t item = layer_stack[top_layer];
    while (item.used) {
        debug_dec(item.layer);
        debug("["); debug_dec(item.next); debug("]");
        item = layer_stack[item.next];
    }
    debug("\n");
}


void action_exec(keyevent_t event)
{


@@ 292,14 214,9 @@ static action_t get_action(key_t key)
    action.code = ACTION_NO;

    /* layer stack */
    for (layer_item_t i = layer_stack[top_layer]; i.used; i = layer_stack[i.next]) {
        action = action_for_key(i.layer, key);
        if (action.code != ACTION_TRANSPARENT) {
            debug_layer_stack();
            debug("layer_stack: used. "); debug_dec(i.layer); debug("\n");
            return action;
        }
        debug("layer_stack: through. "); debug_dec(i.layer); debug("\n");
    action = layer_stack_get_action(key);
    if (action.code != ACTION_TRANSPARENT) {
        return action;
    }

    /* current layer: 0 means default layer */


@@ 618,41 535,41 @@ static void process_action(keyrecord_t *record)
            switch (action.layer.code) {
                case LAYER_MOMENTARY:  /* momentary */
                    if (event.pressed) {
                        layer_remove_then_push(action.layer.val);
                        debug_layer_stack();
                        layer_stack_remove_then_push(action.layer.val);
                        layer_stack_debug();
                    } else {
                        layer_remove(action.layer.val);
                        debug_layer_stack();
                        layer_stack_remove(action.layer.val);
                        layer_stack_debug();
                    }
                    break;
                case LAYER_ON_PRESS:
                    if (event.pressed) {
                        layer_remove_or_push(action.layer.val);
                        debug_layer_stack();
                        layer_stack_remove_or_push(action.layer.val);
                        layer_stack_debug();
                    }
                    break;
                case LAYER_ON_RELEASE:
                    if (!event.pressed) {
                        layer_remove_or_push(action.layer.val);
                        debug_layer_stack();
                        layer_stack_remove_or_push(action.layer.val);
                        layer_stack_debug();
                    }
                    break;
                case LAYER_ON_BOTH:
                    layer_remove_or_push(action.layer.val);
                    debug_layer_stack();
                    layer_stack_remove_or_push(action.layer.val);
                    layer_stack_debug();
                    break;
                case LAYER_TAP_TOGGLE:  /* switch on hold and toggle on several taps */
                    if (event.pressed) {
                        if (tap_count < TAPPING_TOGGLE) {
                            debug("LAYER_STACK: tap toggle(press).\n");
                            layer_remove_or_push(action.layer.val);
                            debug_layer_stack();
                            layer_stack_remove_or_push(action.layer.val);
                            layer_stack_debug();
                        }
                    } else {
                        if (tap_count <= TAPPING_TOGGLE) {
                            debug("LAYER_STACK: tap toggle(release).\n");
                            layer_remove_or_push(action.layer.val);
                            debug_layer_stack();
                            layer_stack_remove_or_push(action.layer.val);
                            layer_stack_debug();
                        }
                    }
                    break;


@@ 664,8 581,8 @@ static void process_action(keyrecord_t *record)
                            register_code(action.layer.code);
                        } else {
                            debug("LAYER_STACK: No tap: layer_stack(on press)\n");
                            layer_remove_or_push(action.layer.val);
                            debug_layer_stack();
                            layer_stack_remove_or_push(action.layer.val);
                            layer_stack_debug();
                        }
                    } else {
                        if (IS_TAPPING_KEY(event.key) && tap_count > 0) {


@@ 673,8 590,8 @@ static void process_action(keyrecord_t *record)
                            unregister_code(action.layer.code);
                        } else {
                            debug("LAYER_STACK: No tap: layer_stack(on release)\n");
                            layer_remove_or_push(action.layer.val);
                            debug_layer_stack();
                            layer_stack_remove_or_push(action.layer.val);
                            layer_stack_debug();
                        }
                    }
                    break;

A common/layer_stack.c => common/layer_stack.c +100 -0
@@ 0,0 1,100 @@
#include <stdint.h>
#include "keyboard.h"
#include "layer_stack.h"
#include "debug.h"


static uint8_t top_layer = 0;

/* [0] always works as sentinel and not used for store.*/
static layer_item_t layer_stack[LAYER_STACK_SIZE] = {};

bool layer_stack_push(uint8_t layer)
{
    for (uint8_t i = 1; i < LAYER_STACK_SIZE; i++) {
        if (!layer_stack[i].used) {
            layer_stack[i] = (layer_item_t){ .layer = layer,
                                              .next = top_layer,
                                              .used = true };
            top_layer = i;
            return true;
        }
    }
    return false;
}

bool layer_stack_pop(void)
{
    if (layer_stack[top_layer].used) {
        uint8_t popped = top_layer;
        top_layer = layer_stack[popped].next;
        layer_stack[popped] = (layer_item_t){};
        return true;
    }
    return false;
}

bool layer_stack_remove(uint8_t layer)
{
    if (layer_stack[top_layer].used && layer_stack[top_layer].layer == layer) {
        layer_stack_pop();
        debug("layer_stack_remove: top_layer\n");
        return true;
    }

    for (uint8_t i = top_layer; layer_stack[i].used; i = layer_stack[i].next) {
        debug("layer_stack_remove: ["); debug_dec(i); debug("]");
        debug_dec(layer_stack[i].layer); debug("\n");
        uint8_t removed = layer_stack[i].next;
        if (layer_stack[removed].used && layer_stack[removed].layer == layer) {
            layer_stack[i].next = layer_stack[removed].next;
            layer_stack[removed] = (layer_item_t){};
            debug("layer_stack_remove: removed.\n");
            return true;
        }
    }
    return false;
}

bool layer_stack_remove_then_push(uint8_t layer)
{
    layer_stack_remove(layer);
    return layer_stack_push(layer);
}

bool layer_stack_remove_or_push(uint8_t layer)
{
    return (layer_stack_remove(layer)) || layer_stack_push(layer);
}

void layer_stack_debug(void)
{
    debug("layer_stack: ");
    layer_item_t item = layer_stack[top_layer];
    while (item.used) {
        debug_dec(item.layer);
        debug("["); debug_dec(item.next); debug("]");
        item = layer_stack[item.next];
    }
    debug("\n");
}



action_t layer_stack_get_action(key_t key)
{
    action_t action;
    action.code = ACTION_TRANSPARENT;

    /* layer stack */
    for (layer_item_t i = layer_stack[top_layer]; i.used; i = layer_stack[i.next]) {
        action = action_for_key(i.layer, key);
        if (action.code != ACTION_TRANSPARENT) {
            layer_stack_debug();
            debug("layer_stack: used. "); debug_dec(i.layer); debug("\n");
            return action;
        }
        debug("layer_stack: through. "); debug_dec(i.layer); debug("\n");
    }
    return action;
}

A common/layer_stack.h => common/layer_stack.h +44 -0
@@ 0,0 1,44 @@
/*
Copyright 2013 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LAYER_STACK_H
#define LAYER_STACK_H

#include <stdint.h>
#include "action.h"


/*
 * Layer stack
 */
#define LAYER_STACK_SIZE 8
typedef struct {
    uint8_t layer:4;
    uint8_t next:3;
    bool    used;
} layer_item_t;


bool layer_stack_push(uint8_t layer);
bool layer_stack_pop(void);
bool layer_stack_remove(uint8_t layer);
bool layer_stack_remove_then_push(uint8_t layer);
bool layer_stack_remove_or_push(uint8_t layer);
void layer_stack_debug(void);
action_t layer_stack_get_action(key_t key);

#endif