Add Repeat Key and Alt Repeat Key to vial-qmk. (#906)

* Repeat Key for vial-qmk.

* Add new keycodes to vial_ensure_keycode.h.
This commit is contained in:
Pascal Getreuer 2025-06-29 14:32:04 -07:00 committed by GitHub
parent 000d5fd8d3
commit f5eb9a8e92
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 265 additions and 13 deletions

View file

@ -10,6 +10,7 @@ CAPS_WORD_ENABLE ?= yes
COMBO_ENABLE ?= yes
KEY_OVERRIDE_ENABLE ?= yes
LAYER_LOCK_ENABLE ?= yes
REPEAT_KEY_ENABLE ?= yes
SRC += $(QUANTUM_DIR)/vial.c
OPT_DEFS += -DVIAL_ENABLE -DNO_DEBUG -DSERIAL_NUMBER=\"vial:f64c2b3c\" -DCAPS_WORD_INVERT_ON_SHIFT

View file

@ -103,6 +103,16 @@ int dynamic_keymap_set_key_override(uint8_t index, const vial_key_override_entry
}
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
int dynamic_keymap_get_alt_repeat_key(uint8_t index, vial_alt_repeat_key_entry_t *entry) {
return nvm_dynamic_keymap_get_alt_repeat_key(index, entry);
}
int dynamic_keymap_set_alt_repeat_key(uint8_t index, const vial_alt_repeat_key_entry_t *entry) {
return nvm_dynamic_keymap_set_alt_repeat_key(index, entry);
}
#endif
void dynamic_keymap_reset(void) {
#ifdef VIAL_ENABLE
/* temporarily unlock the keyboard so we can set hardcoded QK_BOOT keycode */
@ -133,24 +143,38 @@ void dynamic_keymap_reset(void) {
#endif
#ifdef VIAL_TAP_DANCE_ENABLE
vial_tap_dance_entry_t td = { KC_NO, KC_NO, KC_NO, KC_NO, TAPPING_TERM };
for (size_t i = 0; i < VIAL_TAP_DANCE_ENTRIES; ++i) {
dynamic_keymap_set_tap_dance(i, &td);
{
vial_tap_dance_entry_t td = { KC_NO, KC_NO, KC_NO, KC_NO, TAPPING_TERM };
for (size_t i = 0; i < VIAL_TAP_DANCE_ENTRIES; ++i) {
dynamic_keymap_set_tap_dance(i, &td);
}
}
#endif
#ifdef VIAL_COMBO_ENABLE
vial_combo_entry_t combo = { 0 };
for (size_t i = 0; i < VIAL_COMBO_ENTRIES; ++i)
dynamic_keymap_set_combo(i, &combo);
{
vial_combo_entry_t combo = { 0 };
for (size_t i = 0; i < VIAL_COMBO_ENTRIES; ++i)
dynamic_keymap_set_combo(i, &combo);
}
#endif
#ifdef VIAL_KEY_OVERRIDE_ENABLE
vial_key_override_entry_t ko = { 0 };
ko.layers = ~0;
ko.options = vial_ko_option_activation_negative_mod_up | vial_ko_option_activation_required_mod_down | vial_ko_option_activation_trigger_down;
for (size_t i = 0; i < VIAL_KEY_OVERRIDE_ENTRIES; ++i)
dynamic_keymap_set_key_override(i, &ko);
{
vial_key_override_entry_t ko = { 0 };
ko.layers = ~0;
ko.options = vial_ko_option_activation_negative_mod_up | vial_ko_option_activation_required_mod_down | vial_ko_option_activation_trigger_down;
for (size_t i = 0; i < VIAL_KEY_OVERRIDE_ENTRIES; ++i)
dynamic_keymap_set_key_override(i, &ko);
}
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
{
vial_alt_repeat_key_entry_t arep = { 0 };
for (size_t i = 0; i < VIAL_ALT_REPEAT_KEY_ENTRIES; ++i)
dynamic_keymap_set_alt_repeat_key(i, &arep);
}
#endif
#ifdef VIAL_ENABLE

View file

@ -53,6 +53,10 @@ int dynamic_keymap_set_combo(uint8_t index, const vial_combo_entry_t *entry);
int dynamic_keymap_get_key_override(uint8_t index, vial_key_override_entry_t *entry);
int dynamic_keymap_set_key_override(uint8_t index, const vial_key_override_entry_t *entry);
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
int dynamic_keymap_get_alt_repeat_key(uint8_t index, vial_alt_repeat_key_entry_t *entry);
int dynamic_keymap_set_alt_repeat_key(uint8_t index, const vial_alt_repeat_key_entry_t *entry);
#endif
void dynamic_keymap_reset(void);
// These get/set the keycodes as stored in the EEPROM buffer
// Data is big-endian 16-bit values (the keycodes)

View file

@ -81,9 +81,18 @@ STATIC_ASSERT(DYNAMIC_KEYMAP_EEPROM_MAX_ADDR <= 65535, "DYNAMIC_KEYMAP_EEPROM_MA
#define VIAL_KEY_OVERRIDE_SIZE 0
#endif
// Alt Repeat Key
#define VIAL_ALT_REPEAT_KEY_EEPROM_ADDR (VIAL_KEY_OVERRIDE_EEPROM_ADDR + VIAL_KEY_OVERRIDE_SIZE)
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
#define VIAL_ALT_REPEAT_KEY_SIZE (sizeof(vial_alt_repeat_key_entry_t) * VIAL_ALT_REPEAT_KEY_ENTRIES)
#else
#define VIAL_ALT_REPEAT_KEY_SIZE 0
#endif
// Dynamic macro
#ifndef DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR
# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (VIAL_KEY_OVERRIDE_EEPROM_ADDR + VIAL_KEY_OVERRIDE_SIZE)
# define DYNAMIC_KEYMAP_MACRO_EEPROM_ADDR (VIAL_ALT_REPEAT_KEY_EEPROM_ADDR + VIAL_ALT_REPEAT_KEY_SIZE)
#endif
// Sanity check that dynamic keymaps fit in available EEPROM
@ -355,3 +364,25 @@ int nvm_dynamic_keymap_set_key_override(uint8_t index, const vial_key_override_e
return 0;
}
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
int nvm_dynamic_keymap_get_alt_repeat_key(uint8_t index, vial_alt_repeat_key_entry_t *entry) {
if (index >= VIAL_ALT_REPEAT_KEY_ENTRIES)
return -1;
void *address = (void*)(VIAL_ALT_REPEAT_KEY_EEPROM_ADDR + index * sizeof(vial_alt_repeat_key_entry_t));
eeprom_read_block(entry, address, sizeof(vial_alt_repeat_key_entry_t));
return 0;
}
int nvm_dynamic_keymap_set_alt_repeat_key(uint8_t index, const vial_alt_repeat_key_entry_t *entry) {
if (index >= VIAL_ALT_REPEAT_KEY_ENTRIES)
return -1;
void *address = (void*)(VIAL_ALT_REPEAT_KEY_EEPROM_ADDR + index * sizeof(vial_alt_repeat_key_entry_t));
eeprom_write_block(entry, address, sizeof(vial_alt_repeat_key_entry_t));
return 0;
}
#endif

View file

@ -45,3 +45,8 @@ int nvm_dynamic_keymap_set_combo(uint8_t index, const vial_combo_entry_t *entry)
int nvm_dynamic_keymap_get_key_override(uint8_t index, vial_key_override_entry_t *entry);
int nvm_dynamic_keymap_set_key_override(uint8_t index, const vial_key_override_entry_t *entry);
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
int nvm_dynamic_keymap_get_alt_repeat_key(uint8_t index, vial_alt_repeat_key_entry_t *entry);
int nvm_dynamic_keymap_set_alt_repeat_key(uint8_t index, const vial_alt_repeat_key_entry_t *entry);
#endif

View file

@ -58,6 +58,10 @@ static void reload_combo(void);
static void reload_key_override(void);
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
static void reload_alt_repeat_key(void);
#endif
void vial_init(void) {
#ifdef VIAL_TAP_DANCE_ENABLE
reload_tap_dance();
@ -68,6 +72,9 @@ void vial_init(void) {
#ifdef VIAL_KEY_OVERRIDE_ENABLE
reload_key_override();
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
reload_alt_repeat_key();
#endif
}
__attribute__((unused)) static uint16_t vial_keycode_firewall(uint16_t in) {
@ -224,6 +231,7 @@ void vial_handle_cmd(uint8_t *msg, uint8_t length) {
msg[0] = VIAL_TAP_DANCE_ENTRIES;
msg[1] = VIAL_COMBO_ENTRIES;
msg[2] = VIAL_KEY_OVERRIDE_ENTRIES;
msg[3] = VIAL_ALT_REPEAT_KEY_ENTRIES;
// The last byte of msg indicates optionally supported features.
msg[length - 1] = (0
@ -292,6 +300,25 @@ void vial_handle_cmd(uint8_t *msg, uint8_t length) {
reload_key_override();
break;
}
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
case dynamic_vial_alt_repeat_key_get: {
uint8_t idx = msg[3];
vial_alt_repeat_key_entry_t entry = { 0 };
msg[0] = dynamic_keymap_get_alt_repeat_key(idx, &entry);
memcpy(&msg[1], &entry, sizeof(entry));
break;
}
case dynamic_vial_alt_repeat_key_set: {
uint8_t idx = msg[3];
vial_alt_repeat_key_entry_t entry;
memcpy(&entry, &msg[4], sizeof(entry));
entry.keycode = vial_keycode_firewall(entry.keycode);
entry.alt_keycode = vial_keycode_firewall(entry.alt_keycode);
msg[0] = dynamic_keymap_set_alt_repeat_key(idx, &entry);
reload_alt_repeat_key();
break;
}
#endif
}
@ -628,3 +655,123 @@ const key_override_t* key_override_get(uint16_t key_override_idx) {
return &vial_key_overrides[key_override_idx];
}
#endif
#ifdef VIAL_ALT_REPEAT_KEY_ENABLE
typedef struct {
uint16_t keycode;
uint16_t alt_keycode;
uint8_t required_mods;
uint8_t alt_required_mods;
uint8_t allowed_mods;
uint8_t options;
} alt_repeat_key_t;
static alt_repeat_key_t vial_alt_repeat_key[VIAL_ALT_REPEAT_KEY_ENTRIES] = { 0 };
static uint8_t unpack_mods5(uint8_t mods5) {
return (mods5 & 0x10) != 0 ? (mods5 << 4) : mods5;
}
static uint16_t alt_repeat_key_normalize_keycode(uint16_t keycode, uint8_t *mods) {
switch (keycode) {
case QK_MODS ... QK_MODS_MAX: // Unpack modifier + basic key.
*mods |= unpack_mods5(QK_MODS_GET_MODS(keycode));
keycode = QK_MODS_GET_BASIC_KEYCODE(keycode);
break;
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
keycode = QK_MOD_TAP_GET_TAP_KEYCODE(keycode);
break;
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(keycode);
break;
}
return keycode;
}
static int vial_get_alt_repeat_key(uint8_t index, alt_repeat_key_t *out) {
vial_alt_repeat_key_entry_t entry;
int ret;
if ((ret = dynamic_keymap_get_alt_repeat_key(index, &entry)) != 0) {
return ret;
}
memset(out, 0, sizeof(*out));
out->keycode = alt_repeat_key_normalize_keycode(entry.keycode, &out->required_mods);
out->alt_keycode = alt_repeat_key_normalize_keycode(entry.alt_keycode, &out->alt_required_mods);
out->allowed_mods = entry.allowed_mods;
out->options = entry.options;
return 0;
}
static void reload_alt_repeat_key(void) {
for (size_t i = 0; i < VIAL_ALT_REPEAT_KEY_ENTRIES; ++i) {
vial_get_alt_repeat_key(i, &vial_alt_repeat_key[i]);
}
}
uint16_t alt_repeat_key_count(void) {
return VIAL_ALT_REPEAT_KEY_ENTRIES;
}
static bool alt_repeat_key_mods_match(uint8_t mods, uint8_t required_mods, uint8_t allowed_mods, uint8_t options) {
allowed_mods |= required_mods; // Required mods, if any, are allowed.
// If ignoring mod handedness, bitwise-or low (lhs) 4 bits with upper (rhs) 4 bits.
if ((options & vial_arep_option_ignore_mod_handedness)) {
mods = (mods & 0xf) | (mods >> 4);
required_mods = (required_mods & 0xf) | (required_mods >> 4);
allowed_mods = (allowed_mods & 0xf) | (allowed_mods >> 4);
}
// Check that all required mods are set and all disallowed mods are unset.
return (mods & required_mods) == required_mods && (mods & ~allowed_mods) == 0;
}
uint16_t get_alt_repeat_key_keycode_user(uint16_t keycode, uint8_t mods) {
uint16_t alt_keycode = KC_TRNS;
int8_t best_fit = -1;
keycode = alt_repeat_key_normalize_keycode(keycode, &mods);
for (size_t i = 0; i < VIAL_ALT_REPEAT_KEY_ENTRIES; ++i) {
const alt_repeat_key_t* entry = &vial_alt_repeat_key[i];
const uint8_t options = entry->options;
if (!(options & vial_arep_enabled)) { // Skip disabled entries.
continue;
}
// Search for an entry with matching keycode and mods. If there is more
// than one match, the entry with the most mods wins.
if (entry->keycode == keycode &&
alt_repeat_key_mods_match(mods, entry->required_mods, entry->allowed_mods, options)) {
const int8_t fit = bitpop(entry->required_mods);
if (fit > best_fit) {
alt_keycode = (entry->alt_required_mods << 8) | entry->alt_keycode;
best_fit = fit;
}
}
// If the entry is bidirectional, check for match with the alt keycode.
if (entry->alt_keycode == keycode &&
(options & vial_arep_option_bidirectional) != 0 &&
alt_repeat_key_mods_match(mods, entry->alt_required_mods, entry->allowed_mods, options)) {
const int8_t fit = bitpop(entry->alt_required_mods);
if (fit > best_fit) {
alt_keycode = (entry->required_mods << 8) | entry->keycode;
best_fit = fit;
}
}
// If this entry is the default alt key and allowed mods are satisfied,
// use it if no there is no other match.
if ((options & vial_arep_option_default_to_this_alt_key) != 0 &&
best_fit == -1 && alt_keycode == KC_TRNS &&
alt_repeat_key_mods_match(mods, 0, entry->allowed_mods, options)) {
alt_keycode = (entry->alt_required_mods << 8) | entry->alt_keycode;
}
}
return alt_keycode;
}
#endif

View file

@ -58,6 +58,8 @@ enum {
dynamic_vial_combo_set = 0x04,
dynamic_vial_key_override_get = 0x05,
dynamic_vial_key_override_set = 0x06,
dynamic_vial_alt_repeat_key_get = 0x07,
dynamic_vial_alt_repeat_key_set = 0x08,
};
#define VIAL_MACRO_EXT_TAP 5
@ -181,3 +183,40 @@ enum {
#undef VIAL_KEY_OVERRIDE_ENTRIES
#define VIAL_KEY_OVERRIDE_ENTRIES 0
#endif
#if defined(REPEAT_KEY_ENABLE) && !defined(NO_ALT_REPEAT_KEY)
#define VIAL_ALT_REPEAT_KEY_ENABLE
#ifndef VIAL_ALT_REPEAT_KEY_ENTRIES
#if TOTAL_EEPROM_BYTE_COUNT > 4000
#define VIAL_ALT_REPEAT_KEY_ENTRIES 32
#elif TOTAL_EEPROM_BYTE_COUNT > 2000
#define VIAL_ALT_REPEAT_KEY_ENTRIES 16
#elif TOTAL_EEPROM_BYTE_COUNT > 1000
#define VIAL_ALT_REPEAT_KEY_ENTRIES 8
#else
#define VIAL_ALT_REPEAT_KEY_ENTRIES 4
#endif
#endif
/* alt repeat key struct as it is stored in eeprom and transferred to vial-gui */
typedef struct {
uint16_t keycode;
uint16_t alt_keycode;
uint8_t allowed_mods;
uint8_t options;
} vial_alt_repeat_key_entry_t;
_Static_assert(sizeof(vial_alt_repeat_key_entry_t) == 6, "Unexpected size of the vial_alt_repeat_key_entry_t structure");
enum {
vial_arep_option_default_to_this_alt_key = (1 << 0),
vial_arep_option_bidirectional = (1 << 1),
vial_arep_option_ignore_mod_handedness = (1 << 2),
vial_arep_enabled = (1 << 3),
};
#else
#undef VIAL_ALT_REPEAT_KEY_ENTRIES
#define VIAL_ALT_REPEAT_KEY_ENTRIES 0
#endif

View file

@ -815,7 +815,8 @@ _Static_assert(QK_CAPS_WORD_TOGGLE == 0x7C73, "");
_Static_assert(FN_MO13 == 0x7C77, "");
_Static_assert(FN_MO23 == 0x7C78, "");
_Static_assert(QK_REPEAT_KEY == 0x7C79, "");
_Static_assert(QK_ALT_REPEAT_KEY == 0x7C7A, "");
_Static_assert(QK_LAYER_LOCK == 0x7C7B, "");
/* Ensure that we have 64 USERxx keycodes */