Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard combination triggers #960

Merged
merged 5 commits into from
Feb 7, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Added support for timing out combos if a key as been pressed for long…
…er than COMBO_TERM
  • Loading branch information
ofples committed Dec 10, 2016
commit b6bf4e0dce062a535685c4e772f613252d401ed3
107 changes: 79 additions & 28 deletions quantum/process_keycode/process_combo.c
Original file line number Diff line number Diff line change
@@ -1,66 +1,117 @@
#include "process_combo.h"
#include "print.h"

// __attribute__ ((weak))
// combo_t key_combos[] = {

// };

#define SEND_KEY(key) \
do { \
register_code16(key); \
send_keyboard_report(); \
unregister_code16(key); \
} while(0)

#define COMBO_TIMER_ELAPSED -1

#if COMBO_TERM
#define IS_COMBO_KEY_HELD(combo) (COMBO_TIMER_ELAPSED == combo->timer ? false : true)
#define RESET_COMBO_TIMER_AND_KEY(combo) combo->timer = 0; combo->key = 0
#else
#define IS_COMBO_KEY_HELD(combo) (true)
#define RESET_COMBO_TIMER_AND_KEY(combo) do {} while (0)
#endif


__attribute__ ((weak))
combo_t key_combos[COMBO_COUNT] = {

};

static inline void reset_combo(combo_t *combo)
{
combo->state = 0;
RESET_COMBO_TIMER_AND_KEY(combo);
}

#define ALL_COMBO_KEYS_ARE_DOWN (((1<<count)-1) == combo->state)
#define NO_COMBO_KEYS_ARE_DOWN (0 == combo->state)
#define KEY_STATE_DOWN(key) do{ combo->state |= (1<<key); } while(0)
#define KEY_STATE_UP(key) do{ combo->state &= ~(1<<key); } while(0)
static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record)
{
uint8_t count = 0;
bool is_combo_key = false;
// bool combo_key_released = false;
uint8_t index = -1;
/* Find index of keycode and number of combo keys */
for (const uint16_t *keys = combo->keys; ;++count) {
uint16_t key = pgm_read_word(&keys[count]);
if (keycode == key) index = count;
if (COMBO_END == key) break;
}

// Count the number of combo keys
for (const uint16_t *key = combo->keys; COMBO_END != pgm_read_word(key); ++key, ++count);
/* Return if not a combo key */
if (-1 == index) return false;

for (uint8_t i = 0; i < count; ++i) {
uint16_t key = pgm_read_word(&combo->keys[i]);
bool is_combo_active = IS_COMBO_KEY_HELD(combo);

if (key == keycode) {
is_combo_key = true;
if (record->event.pressed) {
KEY_STATE_DOWN(index);

#if COMBO_TERM
if (is_combo_active) {
combo->timer = timer_read();
combo->key = keycode;
}
#endif

if (record->event.pressed) {
combo->state |= (1<<i);
} else { // Combo key released
if (!combo->state) {
// The combo was sent, no need to send released key
return true;
}
} else {
if (is_combo_active && combo->state) { /* Combo key was tapped */
RESET_COMBO_TIMER_AND_KEY(combo);
SEND_KEY(keycode);
}

combo->state &= ~(1<<i);
SEND_KEY(key);
}
#if COMBO_TERM
if (!is_combo_active && keycode == combo->key) { /* Held combo key was released */
unregister_code16(combo->key);
}
#endif

KEY_STATE_UP(index);
}

if (ALL_COMBO_KEYS_ARE_DOWN) {
if (ALL_COMBO_KEYS_ARE_DOWN && is_combo_active) {
SEND_KEY(combo->action);
combo->state = 0;
reset_combo(combo);
}

if(NO_COMBO_KEYS_ARE_DOWN && !is_combo_active) {
reset_combo(combo);
}

return is_combo_key;
return is_combo_active;
}


bool process_combo(uint16_t keycode, keyrecord_t *record)
{
bool is_combo_key = false;

for (int i = 0; i < NUM_ELEMS(key_combos); ++i) {
for (int i = 0; i < COMBO_COUNT; ++i) {
combo_t *combo = &key_combos[i];
is_combo_key |= process_single_combo(combo, keycode, record);
}

return !is_combo_key;
}

void matrix_scan_combo(void)
{
#if COMBO_TERM
for (int i = 0; i < COMBO_COUNT; ++i) {
combo_t *combo = &key_combos[i];
if (combo->timer &&
combo->timer != COMBO_TIMER_ELAPSED &&
timer_elapsed(combo->timer) > COMBO_TERM) {

combo->timer = COMBO_TIMER_ELAPSED;
unregister_code16(combo->key);
register_code16(combo->key);
}
}
#endif
}
20 changes: 17 additions & 3 deletions quantum/process_keycode/process_combo.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,35 @@
#include "progmem.h"
#include "quantum.h"

#ifndef COMBO_TERM
#define COMBO_TERM TAPPING_TERM
#endif

typedef struct
{
const uint16_t *keys;
uint16_t action;
uint32_t state;
#if COMBO_TERM
uint16_t timer;
uint16_t key;
#endif
} combo_t;


#if COMBO_TERM
#define COMBO(ck, ca) {.keys = &(ck)[0], .action = (ca), .state = 0, .timer = 0, .key = 0}
#else
#define COMBO(ck, ca) {.keys = &(ck)[0], .action = (ca), .state = 0 }
#endif
#define COMBO_END 0
#define NUM_ELEMS(a) (sizeof(a)/sizeof 0[a])
#ifndef COMBO_COUNT
#define COMBO_COUNT 0
#endif


extern combo_t key_combos[1];
extern combo_t key_combos[COMBO_COUNT];

bool process_combo(uint16_t keycode, keyrecord_t *record);
void matrix_scan_combo(void);

#endif
5 changes: 5 additions & 0 deletions quantum/quantum.c
Original file line number Diff line number Diff line change
Expand Up @@ -509,6 +509,11 @@ void matrix_scan_quantum() {
#ifdef TAP_DANCE_ENABLE
matrix_scan_tap_dance();
#endif

#ifdef COMBO_ENABLE
matrix_scan_combo();
#endif

matrix_scan_kb();
}

Expand Down