~ruther/qmk_firmware

74aea627e7bb924df81d7944705ab40db036be93 — tmk 12 years ago d44290b
Clean action.c
1 files changed, 246 insertions(+), 242 deletions(-)

M common/action.c
M common/action.c => common/action.c +246 -242
@@ 31,20 31,11 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.


static void process_action(keyrecord_t *record);
#ifndef NO_ACTION_TAPPING
static bool process_tapping(keyrecord_t *record);
static void waiting_buffer_scan_tap(void);
#endif

static void debug_event(keyevent_t event);
static void debug_record(keyrecord_t record);
static void debug_action(action_t action);
#ifndef NO_ACTION_TAPPING
static void debug_tapping_key(void);
static void debug_waiting_buffer(void);
#endif


#ifndef NO_ACTION_TAPPING
/*
 * Tapping
 */


@@ 58,7 49,6 @@ static void debug_waiting_buffer(void);
#define TAPPING_TOGGLE  5
#endif

#ifndef NO_ACTION_TAPPING
/* stores a key event of current tap. */
static keyrecord_t tapping_key = {};



@@ 76,59 66,25 @@ static keyrecord_t tapping_key = {};
 */
#define WAITING_BUFFER_SIZE 8
static keyrecord_t waiting_buffer[WAITING_BUFFER_SIZE] = {};

/* point to empty cell to enq */
static uint8_t waiting_buffer_head = 0;

/* point to the oldest data cell to deq */
static uint8_t waiting_buffer_tail = 0;

static bool waiting_buffer_enq(keyrecord_t record)
{
    if (IS_NOEVENT(record.event)) {
        return true;
    }

    if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
        debug("waiting_buffer_enq: Over flow.\n");
        return false;
    }

    waiting_buffer[waiting_buffer_head] = record;
    waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;

    debug("waiting_buffer_enq: "); debug_waiting_buffer();
    return true;
}

static void waiting_buffer_clear(void)
{
    waiting_buffer_head = 0;
    waiting_buffer_tail = 0;
}

static bool process_tapping(keyrecord_t *record);
static bool waiting_buffer_enq(keyrecord_t record);
static void waiting_buffer_clear(void);
#if TAPPING_TERM >= 500
static bool waiting_buffer_typed(keyevent_t event)
{
    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed !=  waiting_buffer[i].event.pressed) {
            return true;
        }
    }
    return false;
}
static bool waiting_buffer_typed(keyevent_t event);
#endif

bool waiting_buffer_has_anykey_pressed(void)
{
    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (waiting_buffer[i].event.pressed) return true;
    }
    return false;
}
static void waiting_buffer_scan_tap(void);
static void debug_tapping_key(void);
static void debug_waiting_buffer(void);
#endif



void action_exec(keyevent_t event)
{
    if (!IS_NOEVENT(event)) {


@@ 139,13 95,11 @@ void action_exec(keyevent_t event)
    keyrecord_t record = { .event = event };

#ifndef NO_ACTION_TAPPING
    // pre-process on tapping
    if (process_tapping(&record)) {
        if (!IS_NOEVENT(record.event)) {
            debug("processed: "); debug_record(record); debug("\n");
        }
    } else {
        // enqueue
        if (!waiting_buffer_enq(record)) {
            // clear all in case of overflow.
            debug("OVERFLOW: CLEAR ALL STATES\n");


@@ 159,7 113,6 @@ void action_exec(keyevent_t event)
    if (!IS_NOEVENT(event) && waiting_buffer_head != waiting_buffer_tail) {
        debug("---- action_exec: process waiting_buffer -----\n");
    }

    for (; waiting_buffer_tail != waiting_buffer_head; waiting_buffer_tail = (waiting_buffer_tail + 1) % WAITING_BUFFER_SIZE) {
        if (process_tapping(&waiting_buffer[waiting_buffer_tail])) {
            debug("processed: waiting_buffer["); debug_dec(waiting_buffer_tail); debug("] = ");


@@ 298,7 251,6 @@ static void process_action(keyrecord_t *record)
            }
            break;
#endif

#ifdef EXTRAKEY_ENABLE
        /* other HID usage */
        case ACT_USAGE:


@@ 320,7 272,6 @@ static void process_action(keyrecord_t *record)
            }
            break;
#endif

#ifdef MOUSEKEY_ENABLE
        /* Mouse key */
        case ACT_MOUSEKEY:


@@ 333,7 284,6 @@ static void process_action(keyrecord_t *record)
            }
            break;
#endif

#ifndef NO_ACTION_KEYMAP
        case ACT_KEYMAP:
            switch (action.layer.code) {


@@ 497,7 447,6 @@ static void process_action(keyrecord_t *record)
            }
            break;
#endif

#ifndef NO_ACTION_OVERLAY
        case ACT_OVERLAY:
            switch (action.layer.code) {


@@ 653,7 602,6 @@ static void process_action(keyrecord_t *record)
            }
            break;
#endif

        /* Extentions */
#ifndef NO_ACTION_MACRO
        case ACT_MACRO:


@@ 672,6 620,198 @@ static void process_action(keyrecord_t *record)
    }
}




/*
 * Utilities for actions.
 */
void register_code(uint8_t code)
{
    if (code == KC_NO) {
        return;
    }
#ifdef CAPSLOCK_LOCKING_ENABLE
    else if (KC_LOCKING_CAPS == code) {
#ifdef CAPSLOCK_LOCKING_RESYNC_ENABLE
        // Resync: ignore if caps lock already is on
        if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return;
#endif
        host_add_key(KC_CAPSLOCK);
        host_send_keyboard_report();
        host_del_key(KC_CAPSLOCK);
        host_send_keyboard_report();
    }
#endif
    else if IS_KEY(code) {
        // TODO: should push command_proc out of this block?
        if (command_proc(code)) return;

#ifndef NO_ACTION_ONESHOT
        if (oneshot_state.mods && !oneshot_state.disabled) {
            uint8_t tmp_mods = host_get_mods();
            host_add_mods(oneshot_state.mods);

            host_add_key(code);
            host_send_keyboard_report();

            host_set_mods(tmp_mods);
            oneshot_cancel();
        } else 
#endif
        {
            host_add_key(code);
            host_send_keyboard_report();
        }
    }
    else if IS_MOD(code) {
        host_add_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
}

void unregister_code(uint8_t code)
{
    if (code == KC_NO) {
        return;
    }
#ifdef CAPSLOCK_LOCKING_ENABLE
    else if (KC_LOCKING_CAPS == code) {
#ifdef CAPSLOCK_LOCKING_RESYNC_ENABLE
        // Resync: ignore if caps lock already is off
        if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return;
#endif
        host_add_key(KC_CAPSLOCK);
        host_send_keyboard_report();
        host_del_key(KC_CAPSLOCK);
        host_send_keyboard_report();
    }
#endif
    else if IS_KEY(code) {
        host_del_key(code);
        host_send_keyboard_report();
    }
    else if IS_MOD(code) {
        host_del_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
}

void add_mods(uint8_t mods)
{
    if (mods) {
        host_add_mods(mods);
        host_send_keyboard_report();
    }
}

void del_mods(uint8_t mods)
{
    if (mods) {
        host_del_mods(mods);
        host_send_keyboard_report();
    }
}

void set_mods(uint8_t mods)
{
    host_set_mods(mods);
    host_send_keyboard_report();
}

void clear_keyboard(void)
{
    host_clear_mods();
    clear_keyboard_but_mods();
}

void clear_keyboard_but_mods(void)
{
    host_clear_keys();
    host_send_keyboard_report();
#ifdef MOUSEKEY_ENABLE
    mousekey_clear();
    mousekey_send();
#endif
#ifdef EXTRAKEY_ENABLE
    host_system_send(0);
    host_consumer_send(0);
#endif
}

bool sending_anykey(void)
{
    return (host_has_anykey() || host_mouse_in_use() ||
            host_last_sysytem_report() || host_last_consumer_report());
}

bool is_tap_key(key_t key)
{
    action_t action = layer_switch_get_action(key);

    switch (action.kind.id) {
        case ACT_LMODS_TAP:
        case ACT_RMODS_TAP:
            return true;
        case ACT_KEYMAP:
        case ACT_OVERLAY:
            switch (action.layer.code) {
                case 0x04 ... 0xEF:    /* tap key */
                case OP_INV:
                    return true;
                default:
                    return false;
            }
        case ACT_MACRO:
        case ACT_FUNCTION:
            if (action.func.opt & FUNC_TAP) { return true; }
            return false;
    }
    return false;
}


/*
 * debug print
 */
static void debug_event(keyevent_t event)
{
    debug_hex16((event.key.row<<8) | event.key.col);
    if (event.pressed) debug("d("); else debug("u(");
    debug_dec(event.time); debug(")");
}

static void debug_record(keyrecord_t record)
{
    debug_event(record.event); debug(":"); debug_dec(record.tap.count);
    if (record.tap.interrupted) debug("-");
}

static void debug_action(action_t action)
{
    switch (action.kind.id) {
        case ACT_LMODS:             debug("ACT_LMODS");             break;
        case ACT_RMODS:             debug("ACT_RMODS");             break;
        case ACT_LMODS_TAP:         debug("ACT_LMODS_TAP");         break;
        case ACT_RMODS_TAP:         debug("ACT_RMODS_TAP");         break;
        case ACT_USAGE:             debug("ACT_USAGE");             break;
        case ACT_MOUSEKEY:          debug("ACT_MOUSEKEY");          break;
        case ACT_KEYMAP:            debug("ACT_KEYMAP");            break;
        case ACT_OVERLAY:           debug("ACT_OVERLAY");           break;
        case ACT_MACRO:             debug("ACT_MACRO");             break;
        case ACT_COMMAND:           debug("ACT_COMMAND");           break;
        case ACT_FUNCTION:          debug("ACT_FUNCTION");          break;
        default:                    debug("UNKNOWN");               break;
    }
    debug("[");
    debug_hex4(action.kind.param>>8);
    debug(":");
    debug_hex8(action.kind.param & 0xff);
    debug("]");
}



#ifndef NO_ACTION_TAPPING
/* Tapping
 *


@@ 845,221 985,85 @@ static bool process_tapping(keyrecord_t *keyp)
    }
}

/* scan buffer for tapping */
static void waiting_buffer_scan_tap(void)
{
    // tapping already is settled
    if (tapping_key.tap.count > 0) return;
    // invalid state: tapping_key released && tap.count == 0
    if (!tapping_key.event.pressed) return;

    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (IS_TAPPING_KEY(waiting_buffer[i].event.key) &&
                !waiting_buffer[i].event.pressed &&
                WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
            tapping_key.tap.count = 1;
            waiting_buffer[i].tap.count = 1;
            process_action(&tapping_key);

            debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
            debug_waiting_buffer();
            return;
        }
    }
}
#endif



/*
 * Utilities for actions.
 * Waiting buffer
 */
void register_code(uint8_t code)
static bool waiting_buffer_enq(keyrecord_t record)
{
    if (code == KC_NO) {
        return;
    }
#ifdef CAPSLOCK_LOCKING_ENABLE
    else if (KC_LOCKING_CAPS == code) {
#ifdef CAPSLOCK_LOCKING_RESYNC_ENABLE
        // Resync: ignore if caps lock already is on
        if (host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK)) return;
#endif
        host_add_key(KC_CAPSLOCK);
        host_send_keyboard_report();
        host_del_key(KC_CAPSLOCK);
        host_send_keyboard_report();
    if (IS_NOEVENT(record.event)) {
        return true;
    }
#endif
    else if IS_KEY(code) {
        // TODO: should push command_proc out of this block?
        if (command_proc(code)) return;

#ifndef NO_ACTION_ONESHOT
        if (oneshot_state.mods && !oneshot_state.disabled) {
            uint8_t tmp_mods = host_get_mods();
            host_add_mods(oneshot_state.mods);
    if ((waiting_buffer_head + 1) % WAITING_BUFFER_SIZE == waiting_buffer_tail) {
        debug("waiting_buffer_enq: Over flow.\n");
        return false;
    }

            host_add_key(code);
            host_send_keyboard_report();
    waiting_buffer[waiting_buffer_head] = record;
    waiting_buffer_head = (waiting_buffer_head + 1) % WAITING_BUFFER_SIZE;

            host_set_mods(tmp_mods);
            oneshot_cancel();
        } else 
#endif
        {
            host_add_key(code);
            host_send_keyboard_report();
        }
    }
    else if IS_MOD(code) {
        host_add_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
    debug("waiting_buffer_enq: "); debug_waiting_buffer();
    return true;
}

void unregister_code(uint8_t code)
static void waiting_buffer_clear(void)
{
    if (code == KC_NO) {
        return;
    }
#ifdef CAPSLOCK_LOCKING_ENABLE
    else if (KC_LOCKING_CAPS == code) {
#ifdef CAPSLOCK_LOCKING_RESYNC_ENABLE
        // Resync: ignore if caps lock already is off
        if (!(host_keyboard_leds() & (1<<USB_LED_CAPS_LOCK))) return;
#endif
        host_add_key(KC_CAPSLOCK);
        host_send_keyboard_report();
        host_del_key(KC_CAPSLOCK);
        host_send_keyboard_report();
    }
#endif
    else if IS_KEY(code) {
        host_del_key(code);
        host_send_keyboard_report();
    }
    else if IS_MOD(code) {
        host_del_mods(MOD_BIT(code));
        host_send_keyboard_report();
    }
    waiting_buffer_head = 0;
    waiting_buffer_tail = 0;
}

void add_mods(uint8_t mods)
#if TAPPING_TERM >= 500
static bool waiting_buffer_typed(keyevent_t event)
{
    if (mods) {
        host_add_mods(mods);
        host_send_keyboard_report();
    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (KEYEQ(event.key, waiting_buffer[i].event.key) && event.pressed !=  waiting_buffer[i].event.pressed) {
            return true;
        }
    }
    return false;
}
#endif

void del_mods(uint8_t mods)
bool waiting_buffer_has_anykey_pressed(void)
{
    if (mods) {
        host_del_mods(mods);
        host_send_keyboard_report();
    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (waiting_buffer[i].event.pressed) return true;
    }
    return false;
}

void set_mods(uint8_t mods)
{
    host_set_mods(mods);
    host_send_keyboard_report();
}

void clear_keyboard(void)
{
    host_clear_mods();
    clear_keyboard_but_mods();
}

void clear_keyboard_but_mods(void)
{
    host_clear_keys();
    host_send_keyboard_report();
#ifdef MOUSEKEY_ENABLE
    mousekey_clear();
    mousekey_send();
#endif
#ifdef EXTRAKEY_ENABLE
    host_system_send(0);
    host_consumer_send(0);
#endif
}

bool sending_anykey(void)
/* scan buffer for tapping */
static void waiting_buffer_scan_tap(void)
{
    return (host_has_anykey() || host_mouse_in_use() ||
            host_last_sysytem_report() || host_last_consumer_report());
}
    // tapping already is settled
    if (tapping_key.tap.count > 0) return;
    // invalid state: tapping_key released && tap.count == 0
    if (!tapping_key.event.pressed) return;

bool is_tap_key(key_t key)
{
    action_t action = layer_switch_get_action(key);
    for (uint8_t i = waiting_buffer_tail; i != waiting_buffer_head; i = (i + 1) % WAITING_BUFFER_SIZE) {
        if (IS_TAPPING_KEY(waiting_buffer[i].event.key) &&
                !waiting_buffer[i].event.pressed &&
                WITHIN_TAPPING_TERM(waiting_buffer[i].event)) {
            tapping_key.tap.count = 1;
            waiting_buffer[i].tap.count = 1;
            process_action(&tapping_key);

    switch (action.kind.id) {
        case ACT_LMODS_TAP:
        case ACT_RMODS_TAP:
            return true;
        case ACT_KEYMAP:
        case ACT_OVERLAY:
            switch (action.layer.code) {
                case 0x04 ... 0xEF:    /* tap key */
                case OP_INV:
                    return true;
                default:
                    return false;
            }
        case ACT_MACRO:
        case ACT_FUNCTION:
            if (action.func.opt & FUNC_TAP) { return true; }
            return false;
            debug("waiting_buffer_scan_tap: found at ["); debug_dec(i); debug("]\n");
            debug_waiting_buffer();
            return;
        }
    }
    return false;
}


/*
 * debug print
 */
static void debug_event(keyevent_t event)
{
    debug_hex16((event.key.row<<8) | event.key.col);
    if (event.pressed) debug("d("); else debug("u(");
    debug_dec(event.time); debug(")");
}
static void debug_record(keyrecord_t record)
{
    debug_event(record.event); debug(":"); debug_dec(record.tap.count);
    if (record.tap.interrupted) debug("-");
}
static void debug_action(action_t action)
{
    switch (action.kind.id) {
        case ACT_LMODS:             debug("ACT_LMODS");             break;
        case ACT_RMODS:             debug("ACT_RMODS");             break;
        case ACT_LMODS_TAP:         debug("ACT_LMODS_TAP");         break;
        case ACT_RMODS_TAP:         debug("ACT_RMODS_TAP");         break;
        case ACT_USAGE:             debug("ACT_USAGE");             break;
        case ACT_MOUSEKEY:          debug("ACT_MOUSEKEY");          break;
        case ACT_KEYMAP:            debug("ACT_KEYMAP");            break;
        case ACT_OVERLAY:           debug("ACT_OVERLAY");           break;
        case ACT_MACRO:             debug("ACT_MACRO");             break;
        case ACT_COMMAND:           debug("ACT_COMMAND");           break;
        case ACT_FUNCTION:          debug("ACT_FUNCTION");          break;
        default:                    debug("UNKNOWN");               break;
    }
    debug("[");
    debug_hex4(action.kind.param>>8);
    debug(":");
    debug_hex8(action.kind.param & 0xff);
    debug("]");
}
#ifndef NO_ACTION_TAPPING
static void debug_tapping_key(void)
{
    debug("TAPPING_KEY="); debug_record(tapping_key); debug("\n");
}

static void debug_waiting_buffer(void)
{
    debug("{ ");