2017-03-29 00:20:36 +02:00
|
|
|
/* Copyright 2016 Jack Humbert
|
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
|
|
|
|
2020-12-26 05:53:12 +01:00
|
|
|
#pragma once
|
2016-12-09 23:49:11 +01:00
|
|
|
|
|
|
|
#include "progmem.h"
|
|
|
|
#include "quantum.h"
|
Switch process_combo to using global register and timer (#2561)
Since combos keep local state about what keys have been previously pressed, when combos are layered, multiple keypresses will register for any key with multiple combos assigned to it. In order to fix this, I switched process_combo to use a global keycode / keyrecord register and timer. When a keypress is consumed by a combo, it gets stored in the register and the timer is updated; when the next keypress takes too long or a key is pressed that isn't part of any combo, the buffer is emitted and the timer reset. This has a few side effects. For instance, I couldn't _not_ fix combo keys printing out of order while also fixing this bug, so combo keys print in order correctly when a combo fails. since combos no longer have local timers, the logic around when combos time out has changed. now that there is a single timer pressing any combo key (including one in a different combo) will reset the timer for all combos, making combo entry a little more lenient. Since combos no longer have local keycode / keyrecord state, there is an edge case where incomplete combo keys can be consumed. if you have a combo for a+s = tab and a combo for b+n = space, if you press a+b+n, only a space will be emitted. This is because when b+n completes successfully, it drops the register.
2019-04-08 23:07:15 +02:00
|
|
|
#include <stdint.h>
|
2016-12-09 23:49:11 +01:00
|
|
|
|
2021-08-06 01:44:57 +02:00
|
|
|
#ifdef EXTRA_SHORT_COMBOS
|
|
|
|
# define MAX_COMBO_LENGTH 6
|
|
|
|
#elif defined(EXTRA_EXTRA_LONG_COMBOS)
|
2019-08-30 20:19:03 +02:00
|
|
|
# define MAX_COMBO_LENGTH 32
|
2021-08-06 01:44:57 +02:00
|
|
|
#elif defined(EXTRA_LONG_COMBOS)
|
2019-08-30 20:19:03 +02:00
|
|
|
# define MAX_COMBO_LENGTH 16
|
2016-12-16 20:50:28 +01:00
|
|
|
#else
|
2019-08-30 20:19:03 +02:00
|
|
|
# define MAX_COMBO_LENGTH 8
|
2016-12-16 20:50:28 +01:00
|
|
|
#endif
|
Switch process_combo to using global register and timer (#2561)
Since combos keep local state about what keys have been previously pressed, when combos are layered, multiple keypresses will register for any key with multiple combos assigned to it. In order to fix this, I switched process_combo to use a global keycode / keyrecord register and timer. When a keypress is consumed by a combo, it gets stored in the register and the timer is updated; when the next keypress takes too long or a key is pressed that isn't part of any combo, the buffer is emitted and the timer reset. This has a few side effects. For instance, I couldn't _not_ fix combo keys printing out of order while also fixing this bug, so combo keys print in order correctly when a combo fails. since combos no longer have local timers, the logic around when combos time out has changed. now that there is a single timer pressing any combo key (including one in a different combo) will reset the timer for all combos, making combo entry a little more lenient. Since combos no longer have local keycode / keyrecord state, there is an edge case where incomplete combo keys can be consumed. if you have a combo for a+s = tab and a combo for b+n = space, if you press a+b+n, only a space will be emitted. This is because when b+n completes successfully, it drops the register.
2019-04-08 23:07:15 +02:00
|
|
|
|
2021-08-06 01:44:57 +02:00
|
|
|
#ifndef COMBO_KEY_BUFFER_LENGTH
|
|
|
|
# define COMBO_KEY_BUFFER_LENGTH MAX_COMBO_LENGTH
|
|
|
|
#endif
|
|
|
|
#ifndef COMBO_BUFFER_LENGTH
|
|
|
|
# define COMBO_BUFFER_LENGTH 4
|
|
|
|
#endif
|
|
|
|
|
Switch process_combo to using global register and timer (#2561)
Since combos keep local state about what keys have been previously pressed, when combos are layered, multiple keypresses will register for any key with multiple combos assigned to it. In order to fix this, I switched process_combo to use a global keycode / keyrecord register and timer. When a keypress is consumed by a combo, it gets stored in the register and the timer is updated; when the next keypress takes too long or a key is pressed that isn't part of any combo, the buffer is emitted and the timer reset. This has a few side effects. For instance, I couldn't _not_ fix combo keys printing out of order while also fixing this bug, so combo keys print in order correctly when a combo fails. since combos no longer have local timers, the logic around when combos time out has changed. now that there is a single timer pressing any combo key (including one in a different combo) will reset the timer for all combos, making combo entry a little more lenient. Since combos no longer have local keycode / keyrecord state, there is an edge case where incomplete combo keys can be consumed. if you have a combo for a+s = tab and a combo for b+n = space, if you press a+b+n, only a space will be emitted. This is because when b+n completes successfully, it drops the register.
2019-04-08 23:07:15 +02:00
|
|
|
typedef struct {
|
2019-08-30 20:19:03 +02:00
|
|
|
const uint16_t *keys;
|
|
|
|
uint16_t keycode;
|
2021-08-06 01:44:57 +02:00
|
|
|
#ifdef EXTRA_SHORT_COMBOS
|
|
|
|
uint8_t state;
|
|
|
|
#else
|
2021-11-01 20:18:33 +01:00
|
|
|
bool disabled;
|
|
|
|
bool active;
|
2021-08-06 01:44:57 +02:00
|
|
|
# if defined(EXTRA_EXTRA_LONG_COMBOS)
|
2019-08-30 20:19:03 +02:00
|
|
|
uint32_t state;
|
2021-08-06 01:44:57 +02:00
|
|
|
# elif defined(EXTRA_LONG_COMBOS)
|
2019-08-30 20:19:03 +02:00
|
|
|
uint16_t state;
|
2021-08-06 01:44:57 +02:00
|
|
|
# else
|
2019-08-30 20:19:03 +02:00
|
|
|
uint8_t state;
|
2021-08-06 01:44:57 +02:00
|
|
|
# endif
|
2016-12-10 15:11:59 +01:00
|
|
|
#endif
|
2016-12-09 23:49:11 +01:00
|
|
|
} combo_t;
|
|
|
|
|
2019-08-30 20:19:03 +02:00
|
|
|
#define COMBO(ck, ca) \
|
|
|
|
{ .keys = &(ck)[0], .keycode = (ca) }
|
|
|
|
#define COMBO_ACTION(ck) \
|
|
|
|
{ .keys = &(ck)[0] }
|
2016-12-16 20:50:28 +01:00
|
|
|
|
2016-12-09 23:49:11 +01:00
|
|
|
#define COMBO_END 0
|
2016-12-16 20:50:28 +01:00
|
|
|
#ifndef COMBO_TERM
|
2021-08-06 01:44:57 +02:00
|
|
|
# define COMBO_TERM 50
|
2016-12-16 20:50:28 +01:00
|
|
|
#endif
|
2021-08-06 01:44:57 +02:00
|
|
|
#ifndef COMBO_HOLD_TERM
|
|
|
|
# define COMBO_HOLD_TERM TAPPING_TERM
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* check if keycode is only modifiers */
|
2023-02-10 22:10:14 +01:00
|
|
|
#define KEYCODE_IS_MOD(code) (IS_MODIFIER_KEYCODE(code) || (IS_QK_MODS(code) && !QK_MODS_GET_BASIC_KEYCODE(code)))
|
2016-12-09 23:49:11 +01:00
|
|
|
|
|
|
|
bool process_combo(uint16_t keycode, keyrecord_t *record);
|
2021-07-28 13:01:23 +02:00
|
|
|
void combo_task(void);
|
2020-07-16 14:39:01 +02:00
|
|
|
void process_combo_event(uint16_t combo_index, bool pressed);
|
2016-12-09 23:49:11 +01:00
|
|
|
|
2019-07-16 10:37:19 +02:00
|
|
|
void combo_enable(void);
|
|
|
|
void combo_disable(void);
|
|
|
|
void combo_toggle(void);
|
|
|
|
bool is_combo_enabled(void);
|