mirror of
https://github.com/qmk/qmk_userspace.git
synced 2026-03-10 02:10:25 -04:00
context_magic is working.
This commit is contained in:
parent
56ba3974b7
commit
e5acbb294a
19 changed files with 687 additions and 687 deletions
|
|
@ -3,4 +3,4 @@
|
||||||
#include QMK_KEYBOARD_H
|
#include QMK_KEYBOARD_H
|
||||||
|
|
||||||
#include "general/custom_keys.h"
|
#include "general/custom_keys.h"
|
||||||
#include "magic_sturdy/__init__.h"
|
#include "magic_sturdy/context_magic.h"
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,5 @@
|
||||||
// User Added
|
// User Added
|
||||||
#define COMBO_COUNT 10
|
#define COMBO_COUNT 10
|
||||||
#define TAPPING_TOGGLE 2
|
#define TAPPING_TOGGLE 2
|
||||||
|
#define USER_PRINT
|
||||||
|
#define DEBUG
|
||||||
|
|
|
||||||
|
|
@ -109,17 +109,21 @@ combo_t key_combos[COMBO_COUNT] = {
|
||||||
COMBO(combo_RB_IR, US_QUOT_S),
|
COMBO(combo_RB_IR, US_QUOT_S),
|
||||||
};
|
};
|
||||||
|
|
||||||
extern rgb_config_t rgb_matrix_config;
|
// extern rgb_config_t rgb_matrix_config;
|
||||||
|
|
||||||
void keyboard_post_init_user(void) {
|
// void keyboard_post_init_user(void) {
|
||||||
rgb_matrix_enable();
|
// rgb_matrix_enable();
|
||||||
}
|
// }
|
||||||
|
|
||||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||||
bool return_value;
|
// bool return_value;
|
||||||
|
|
||||||
if (sturdy_pr(keycode, record, &return_value))
|
// if (sturdy_pr(keycode, record, &return_value))
|
||||||
return return_value;
|
// return return_value;
|
||||||
|
uprintf("Process_record_user for keycode: %d", keycode);
|
||||||
|
|
||||||
|
if (!process_context_magic(keycode, record))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (record->event.pressed) {
|
if (record->event.pressed) {
|
||||||
switch (keycode) {
|
switch (keycode) {
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
// Originally from QKekos
|
|
||||||
#pragma once
|
|
||||||
#include "../__init__.h"
|
|
||||||
|
|
||||||
#include "general.h"
|
|
||||||
#include "magic_keys.h"
|
|
||||||
|
|
||||||
#define single_queue_check(p_key) queue(-1) == p_key
|
|
||||||
#define double_queue_check(pp_key, p_key) queue(-2) == pp_key && single_queue_check(p_key)
|
|
||||||
#define triple_queue_check(ppp_key, pp_key, p_key) queue(-3) == ppp_key && double_queue_check(pp_key, p_key)
|
|
||||||
#define quadruple_queue_check(pppp_key, ppp_key, pp_key, p_key) queue(-4) == pppp_key && triple_queue_check(ppp_key, pp_key, p_key)
|
|
||||||
|
|
||||||
#define magic_case_core(trigger, condition, supplement) \
|
|
||||||
case trigger: \
|
|
||||||
if (condition) { \
|
|
||||||
record_send_string(supplement); \
|
|
||||||
return; \
|
|
||||||
} \
|
|
||||||
break
|
|
||||||
|
|
||||||
#define magic_switch_core(trigger, body, index) \
|
|
||||||
case trigger: \
|
|
||||||
switch (queue(index)) { \
|
|
||||||
body \
|
|
||||||
} \
|
|
||||||
break
|
|
||||||
|
|
||||||
#define magic_case(trigger, supplement) \
|
|
||||||
case trigger: \
|
|
||||||
record_send_string(supplement); \
|
|
||||||
return
|
|
||||||
|
|
||||||
#define double_magic_switch(trigger, body) \
|
|
||||||
magic_switch_core(trigger, body, -1)
|
|
||||||
|
|
||||||
#define triple_magic_switch(trigger, body) \
|
|
||||||
magic_switch_core(trigger, body, -2)
|
|
||||||
|
|
||||||
#define quadruple_magic_switch(trigger, body) \
|
|
||||||
magic_switch_core(trigger, body, -3)
|
|
||||||
|
|
||||||
#define quintuple_magic_switch(trigger, body) \
|
|
||||||
magic_switch_core(trigger, body, -4)
|
|
||||||
|
|
||||||
#define double_magic_case(trigger, p_key, supplement) \
|
|
||||||
magic_case_core(trigger, single_queue_check(p_key), supplement)
|
|
||||||
|
|
||||||
#define triple_magic_case(trigger, pp_key, p_key, supplement) \
|
|
||||||
magic_case_core(trigger, double_queue_check(pp_key, p_key), supplement)
|
|
||||||
|
|
||||||
#define quadruple_magic_case(trigger, ppp_key, pp_key, p_key, supplement) \
|
|
||||||
magic_case_core(trigger, triple_queue_check(ppp_key, pp_key, p_key), supplement)
|
|
||||||
|
|
||||||
#define quintuple_magic_case(trigger, pppp_key, ppp_key, pp_key, p_key, supplement) \
|
|
||||||
magic_case_core(trigger, quadruple_queue_check(pppp_key, ppp_key, pp_key, p_key), supplement)
|
|
||||||
|
|
@ -0,0 +1,396 @@
|
||||||
|
// Copyright 2021 Google LLC
|
||||||
|
// Copyright 2021 @filterpaper
|
||||||
|
// Copyright 2023 Pablo Martinez (@elpekenin) <elpekenin@elpekenin.dev>
|
||||||
|
// Copyright 2024 Guillaume Stordeur <guillaume.stordeur@gmail.com>
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// Original source: https://getreuer.info/posts/keyboards/autocorrection
|
||||||
|
|
||||||
|
#include "context_magic.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include "keycodes.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
#include "quantum_keycodes.h"
|
||||||
|
#include "keycode_config.h"
|
||||||
|
#include "send_string.h"
|
||||||
|
#include "action_util.h"
|
||||||
|
#include "magickey_data.h"
|
||||||
|
#include "../general/custom_keys.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
// todo: compute max in script
|
||||||
|
#define CONTEXT_MAGIC_MAX_LENGTH MAGICKEY_MAX_LENGTH
|
||||||
|
#define MAGIC_DICTIONARY_SIZE DICTIONARY_SIZE
|
||||||
|
#define TDATA(L) pgm_read_word(&trie->data[L])
|
||||||
|
#define CDATA(L) pgm_read_byte(&trie->completions[L])
|
||||||
|
#define IS_ALPHA_KEYCODE(code) ((code) >= KC_A && (code) <= KC_Z)
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Add KC_SPC on timeout
|
||||||
|
#if MAGIC_IDLE_TIMEOUT > 0
|
||||||
|
static uint32_t magic_timer = 0;
|
||||||
|
void context_magic_task(void)
|
||||||
|
{
|
||||||
|
if (timer_elapsed32(magic_timer) > MAGIC_IDLE_TIMEOUT) {
|
||||||
|
reset_buffer();
|
||||||
|
magic_timer = timer_read32();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Key history buffer
|
||||||
|
static uint16_t key_buffer[CONTEXT_MAGIC_MAX_LENGTH] = {KC_SPC};
|
||||||
|
static uint16_t key_buffer_size = 1;
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// List of tries
|
||||||
|
static trie_t trie = {
|
||||||
|
MAGIC_DICTIONARY_SIZE, magickey_data, COMPLETIONS_SIZE, magickey_completions_data
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief determine if context_magic should process this keypress,
|
||||||
|
* and remove any mods from keycode.
|
||||||
|
*
|
||||||
|
* @param keycode Keycode registered by matrix press, per keymap
|
||||||
|
* @param record keyrecord_t structure
|
||||||
|
* @param mods allow processing of mod status
|
||||||
|
* @return true Allow context_magic
|
||||||
|
* @return false Stop processing and escape from context_magic.
|
||||||
|
*/
|
||||||
|
bool process_check(uint16_t *keycode, keyrecord_t *record, uint8_t *mods)
|
||||||
|
{
|
||||||
|
// See quantum_keycodes.h for reference on these matched ranges.
|
||||||
|
switch (*keycode) {
|
||||||
|
// Exclude these keycodes from processing.
|
||||||
|
case KC_LSFT:
|
||||||
|
case KC_RSFT:
|
||||||
|
case KC_CAPS:
|
||||||
|
case QK_TO ... QK_TO_MAX:
|
||||||
|
case QK_MOMENTARY ... QK_MOMENTARY_MAX:
|
||||||
|
case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:
|
||||||
|
case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:
|
||||||
|
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
|
||||||
|
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
|
||||||
|
case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
|
||||||
|
case QK_ONE_SHOT_MOD ... QK_ONE_SHOT_MOD_MAX:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Mask for base keycode from shifted keys.
|
||||||
|
case QK_LSFT ... QK_LSFT + 255:
|
||||||
|
case QK_RSFT ... QK_RSFT + 255:
|
||||||
|
if (*keycode >= QK_LSFT && *keycode <= (QK_LSFT + 255)) {
|
||||||
|
*mods |= MOD_LSFT;
|
||||||
|
} else {
|
||||||
|
*mods |= MOD_RSFT;
|
||||||
|
}
|
||||||
|
*keycode = QK_MODS_GET_BASIC_KEYCODE(*keycode); // Get the basic keycode.
|
||||||
|
return true;
|
||||||
|
#ifndef NO_ACTION_TAPPING
|
||||||
|
// Exclude tap-hold keys when they are held down
|
||||||
|
// and mask for base keycode when they are tapped.
|
||||||
|
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
|
||||||
|
# ifdef NO_ACTION_LAYER
|
||||||
|
// Exclude Layer Tap, if layers are disabled
|
||||||
|
// but action tapping is still enabled.
|
||||||
|
return false;
|
||||||
|
# else
|
||||||
|
// Exclude hold keycode
|
||||||
|
if (!record->tap.count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*keycode = QK_LAYER_TAP_GET_TAP_KEYCODE(*keycode);
|
||||||
|
break;
|
||||||
|
# endif
|
||||||
|
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
|
||||||
|
// Exclude hold keycode
|
||||||
|
if (!record->tap.count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*keycode = QK_MOD_TAP_GET_TAP_KEYCODE(*keycode);
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
|
||||||
|
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
|
||||||
|
// Exclude if disabled
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
// Exclude swap hands keys when they are held down
|
||||||
|
// and mask for base keycode when they are tapped.
|
||||||
|
case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
|
||||||
|
#ifdef SWAP_HANDS_ENABLE
|
||||||
|
// Note: IS_SWAP_HANDS_KEYCODE() actually tests for the special action keycodes like SH_TOGG, SH_TT, ...,
|
||||||
|
// which currently overlap the SH_T(kc) range.
|
||||||
|
if (IS_SWAP_HANDS_KEYCODE(*keycode)
|
||||||
|
# ifndef NO_ACTION_TAPPING
|
||||||
|
|| !record->tap.count
|
||||||
|
# endif // NO_ACTION_TAPPING
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*keycode = QK_SWAP_HANDS_GET_TAP_KEYCODE(*keycode);
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
// Exclude if disabled
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// Disable autocorrect while a mod other than shift is active.
|
||||||
|
if ((*mods & ~MOD_MASK_SHIFT) != 0) {
|
||||||
|
reset_buffer();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add keycode to our key buffer.
|
||||||
|
*
|
||||||
|
* @param keycode Keycode registered by matrix press, per keymap
|
||||||
|
*/
|
||||||
|
void enqueue_keycode(uint16_t keycode)
|
||||||
|
{
|
||||||
|
// Store all alpha chars as lowercase
|
||||||
|
const bool shifted = keycode & QK_LSFT;
|
||||||
|
const uint8_t lowkey = keycode & 0xFF;
|
||||||
|
if (shifted && IS_ALPHA_KEYCODE(lowkey))
|
||||||
|
keycode = lowkey;
|
||||||
|
// Rotate oldest character if buffer is full.
|
||||||
|
if (key_buffer_size >= CONTEXT_MAGIC_MAX_LENGTH) {
|
||||||
|
memmove(key_buffer, key_buffer + 1, sizeof(uint16_t) * (CONTEXT_MAGIC_MAX_LENGTH - 1));
|
||||||
|
key_buffer_size = CONTEXT_MAGIC_MAX_LENGTH - 1;
|
||||||
|
}
|
||||||
|
key_buffer[key_buffer_size++] = keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
void reset_buffer(void)
|
||||||
|
{
|
||||||
|
key_buffer[0] = KC_SPC;
|
||||||
|
key_buffer_size = 1;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief Remove num keys from our buffer.
|
||||||
|
*
|
||||||
|
* @param num number of keys to remove
|
||||||
|
*/
|
||||||
|
void dequeue_keycodes(uint8_t num)
|
||||||
|
{
|
||||||
|
key_buffer_size -= MIN(num, key_buffer_size);
|
||||||
|
if (!key_buffer_size)
|
||||||
|
reset_buffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Find longest chain in trie matching our current key_buffer.
|
||||||
|
*
|
||||||
|
* @param trie trie_t struct containing trie data/size
|
||||||
|
* @param res result containing current best
|
||||||
|
* @param offset current offset in trie data
|
||||||
|
* @param depth current depth in trie
|
||||||
|
* @return true if match found
|
||||||
|
*/
|
||||||
|
bool find_longest_chain(trie_t *trie, trie_search_result_t *res, int offset, int depth)
|
||||||
|
{
|
||||||
|
// Sanity checks
|
||||||
|
if (offset >= trie->data_size) {
|
||||||
|
uprintf("find_longest_chain() Error: tried reading outside trie data! Offset: %d", offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint16_t code = TDATA(offset);
|
||||||
|
if (!code) {
|
||||||
|
uprintf("find_longest_chain() Error: unexpected null code! Offset: %d", offset);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uprintf("FIND_LONGEST_CHAIN (%d, %d)", offset, code);
|
||||||
|
// Match Node if bit 15 is set
|
||||||
|
if (code & 0x8000) {
|
||||||
|
uprintf("Match found at Offset: %d", offset);
|
||||||
|
// match nodes are side attachments, so decrease depth
|
||||||
|
depth--;
|
||||||
|
// If bit 14 is also set, there is a child node after the completion string
|
||||||
|
if ((code & 0x4000) && find_longest_chain(trie, res, offset+2, depth+1)) {
|
||||||
|
uprintf("Looking for deeper match at Offset: %d", offset+2);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If no better match found deeper, this is the result!
|
||||||
|
// char buf[20];
|
||||||
|
// sprintf(buf, "|0x%04x|", code);
|
||||||
|
// send_string(buf);
|
||||||
|
res->completion_offset = TDATA(offset + 1);
|
||||||
|
res->func_code = (code >> 11 & 0x0007);
|
||||||
|
res->num_backspaces = (code & 0x003F);
|
||||||
|
// Found a match so return true!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Branch Node (with multiple children) if bit 14 is set
|
||||||
|
if (code & 0x4000) {
|
||||||
|
if (depth > key_buffer_size)
|
||||||
|
return false;
|
||||||
|
code &= 0x3FFF;
|
||||||
|
// Find child that matches our current buffer location
|
||||||
|
const uint16_t cur_key = key_buffer[key_buffer_size - depth];
|
||||||
|
for (; code; offset += 2, code = TDATA(offset)) {
|
||||||
|
if (code == cur_key) {
|
||||||
|
// 16bit offset to child node is built from next uint16_t
|
||||||
|
const int child_offset = TDATA(offset+1);
|
||||||
|
// Traverse down child node
|
||||||
|
return find_longest_chain(trie, res, child_offset, depth+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Couldn't go deeper, so return false.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// No high bits set, so this is a chain node
|
||||||
|
// Travel down chain until we reach a zero byte, or we no longer match our buffer
|
||||||
|
for (; code; depth++, code = TDATA(++offset)) {
|
||||||
|
if (depth > key_buffer_size ||
|
||||||
|
code != key_buffer[key_buffer_size - depth])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// After a chain, there should be a leaf or branch
|
||||||
|
return find_longest_chain(trie, res, offset+1, depth);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void record_send_key(uint16_t keycode)
|
||||||
|
{
|
||||||
|
enqueue_keycode(keycode);
|
||||||
|
// Apply shift to sent key if caps word is enabled.
|
||||||
|
#ifdef CAPS_WORD_ENABLED
|
||||||
|
if (is_caps_word_on() && IS_ALPHA_KEYCODE(keycode))
|
||||||
|
add_weak_mods(MOD_BIT(KC_LSFT));
|
||||||
|
#endif
|
||||||
|
tap_code16(keycode);
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void handle_repeat_key()
|
||||||
|
{
|
||||||
|
uint16_t keycode = KC_NO;
|
||||||
|
for (int i = key_buffer_size - 1; i >= 0; --i) {
|
||||||
|
keycode = key_buffer[i];
|
||||||
|
if (!(keycode & 0x0100)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (keycode && !(keycode & 0x0100)) {
|
||||||
|
dequeue_keycodes(1);
|
||||||
|
enqueue_keycode(keycode);
|
||||||
|
// Apply shift to sent key if caps word is enabled.
|
||||||
|
#ifdef CAPS_WORD_ENABLED
|
||||||
|
if (is_caps_word_on() && IS_ALPHA_KEYCODE(keycode))
|
||||||
|
add_weak_mods(MOD_BIT(KC_LSFT));
|
||||||
|
#endif
|
||||||
|
tap_code16(keycode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void handle_result(trie_t *trie, trie_search_result_t *res)
|
||||||
|
{
|
||||||
|
// Send backspaces
|
||||||
|
multi_tap(KC_BSPC, res->num_backspaces);
|
||||||
|
// Send completion string
|
||||||
|
for (int i = res->completion_offset; i < trie->completions_size; ++i) {
|
||||||
|
char ascii_code = CDATA(i);
|
||||||
|
if (!ascii_code) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tap_code16(char_to_keycode(ascii_code));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (res->func_code) {
|
||||||
|
case 1: // repeat
|
||||||
|
handle_repeat_key();
|
||||||
|
return;
|
||||||
|
case 2: // set one-shot shift
|
||||||
|
set_oneshot_mods(MOD_LSFT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles magic/repeat key press
|
||||||
|
*
|
||||||
|
* @param keycode Keycode registered by matrix press, per keymap
|
||||||
|
* @return false if keycode isn't a registered magic key
|
||||||
|
*/
|
||||||
|
bool perform_magic()
|
||||||
|
{
|
||||||
|
// Do nothing if key buffer is empty
|
||||||
|
if (!key_buffer_size)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Look for chain matching our buffer in the trie.
|
||||||
|
trie_search_result_t res = {0, 0};
|
||||||
|
if (find_longest_chain(&trie, &res, 0, 1)) {
|
||||||
|
handle_result(&trie, &res);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Process handler for context_magic feature.
|
||||||
|
*
|
||||||
|
* @param keycode Keycode registered by matrix press, per keymap
|
||||||
|
* @param record keyrecord_t structure
|
||||||
|
* @return true Continue processing keycodes, and send to host
|
||||||
|
* @return false Stop processing keycodes, and don't send to host
|
||||||
|
*/
|
||||||
|
bool process_context_magic(uint16_t keycode, keyrecord_t *record)
|
||||||
|
{
|
||||||
|
|
||||||
|
uprintf("Process_context_magic for keycode: %d", keycode);
|
||||||
|
#if MAGIC_IDLE_TIMEOUT > 0
|
||||||
|
magic_timer = timer_read32();
|
||||||
|
#endif
|
||||||
|
uint8_t mods = get_mods();
|
||||||
|
#ifndef NO_ACTION_ONESHOT
|
||||||
|
mods |= get_oneshot_mods();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!record->event.pressed)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// keycode verification and extraction
|
||||||
|
if (!process_check(&keycode, record, &mods))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// keycode buffer check
|
||||||
|
switch (keycode) {
|
||||||
|
case US_MAG1 ... US_MAG4:
|
||||||
|
// convert to special 0x01nn code
|
||||||
|
keycode = 0x0100 + keycode - US_MAG1;
|
||||||
|
break;
|
||||||
|
case KC_A ... KC_0:
|
||||||
|
// process normally
|
||||||
|
break;
|
||||||
|
case KC_MINUS ...KC_SLASH:
|
||||||
|
// treat " (shifted ') as a word boundary
|
||||||
|
if (keycode == KC_QUOTE && (mods & MOD_MASK_SHIFT) != 0)
|
||||||
|
keycode = KC_SPC;
|
||||||
|
break;
|
||||||
|
case S(KC_MINUS) ...S(KC_SLASH):
|
||||||
|
// treat " (shifted ') as a word boundary
|
||||||
|
if (S(KC_QUOTE))
|
||||||
|
keycode = KC_SPC;
|
||||||
|
break;
|
||||||
|
case KC_BSPC:
|
||||||
|
// remove last character from the buffer
|
||||||
|
reset_buffer();
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
// set word boundary if some other non-alpha key is pressed
|
||||||
|
keycode = KC_SPC;
|
||||||
|
}
|
||||||
|
// append `keycode` to buffer
|
||||||
|
enqueue_keycode(keycode);
|
||||||
|
|
||||||
|
uprintf(" translated keycode: %d", keycode);
|
||||||
|
|
||||||
|
// perform magic action if this is one of our registered keycodes
|
||||||
|
if (perform_magic())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "action.h"
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Public API
|
||||||
|
bool process_context_magic(uint16_t keycode, keyrecord_t *record);
|
||||||
|
|
||||||
|
#if MAGIC_IDLE_TIMEOUT > 0
|
||||||
|
void context_magic_task(void);
|
||||||
|
#else
|
||||||
|
static inline void context_magic_task(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////
|
||||||
|
// Internal
|
||||||
|
typedef void (*trie_fallback)(void);
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int data_size;
|
||||||
|
const uint16_t *data;
|
||||||
|
int completions_size;
|
||||||
|
const uint8_t *completions;
|
||||||
|
} trie_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t func_code;
|
||||||
|
uint8_t num_backspaces;
|
||||||
|
int completion_offset;
|
||||||
|
} trie_search_result_t;
|
||||||
|
|
||||||
|
// trie_t *get_trie(uint16_t keycode);
|
||||||
|
bool process_check(uint16_t *keycode, keyrecord_t *record, uint8_t *mods);
|
||||||
|
void enqueue_keycode(uint16_t keycode);
|
||||||
|
void reset_buffer(void);
|
||||||
|
void dequeue_keycodes(uint8_t num);
|
||||||
|
bool find_longest_chain(trie_t *trie, trie_search_result_t *res, int offset, int depth);
|
||||||
|
void record_send_key(uint16_t keycode);
|
||||||
|
void repeat_key_fallback(void);
|
||||||
|
void handle_repeat_key(void);
|
||||||
|
void handle_result(trie_t *trie, trie_search_result_t *res);
|
||||||
|
bool perform_magic(void);
|
||||||
|
|
@ -1,181 +0,0 @@
|
||||||
|
|
||||||
#include "magic_sturdy/general.h"
|
|
||||||
#include "../__init__.h"
|
|
||||||
|
|
||||||
int mag1_key_count = 0;
|
|
||||||
int mag2_key_count = 0;
|
|
||||||
int mag3_key_count = 0;
|
|
||||||
int mag4_key_count = 0;
|
|
||||||
int last_key_pressed_time = 0;
|
|
||||||
int prev_key_time;
|
|
||||||
|
|
||||||
int prev_keys_queue[PREV_KEYS_QUEUE_SIZE] = {KC_NO};
|
|
||||||
deferred_token magic_timeout_token = INVALID_DEFERRED_TOKEN;
|
|
||||||
|
|
||||||
uint32_t enqueue_space(uint32_t trigger_time, void *cb_arg) {
|
|
||||||
enqueue(KC_SPC);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void refresh_token(void) {
|
|
||||||
if (magic_timeout_token != INVALID_DEFERRED_TOKEN)
|
|
||||||
cancel_deferred_exec(magic_timeout_token);
|
|
||||||
|
|
||||||
magic_timeout_token = defer_exec(MAGIC_KEY_TIMEOUT, enqueue_space, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void record_send_string(const char *str) {
|
|
||||||
for (int i = 0; str[i] != '\0'; i++) {
|
|
||||||
if (str[i] == 8) dequeue(); // dequeue when sending backspace
|
|
||||||
else if (65 <= str[i] && str[i] <= 90) enqueue(str[i] - 61);
|
|
||||||
else if (97 <= str[i] && str[i] <= 122) enqueue(str[i] - 93);
|
|
||||||
}
|
|
||||||
|
|
||||||
SEND_STRING(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enqueue(int keycode) {
|
|
||||||
for (int i = 0; i < PREV_KEYS_QUEUE_SIZE - 1; i += 1)
|
|
||||||
prev_keys_queue[i] = prev_keys_queue[i + 1];
|
|
||||||
|
|
||||||
prev_keys_queue[PREV_KEYS_QUEUE_SIZE - 1] = keycode;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dequeue(void) {
|
|
||||||
set_last_keycode(prev_keys_queue[PREV_KEYS_QUEUE_SIZE - 1]);
|
|
||||||
|
|
||||||
for (int i = PREV_KEYS_QUEUE_SIZE - 1; i > 0; i -= 1)
|
|
||||||
prev_keys_queue[i] = prev_keys_queue[i - 1];
|
|
||||||
|
|
||||||
prev_keys_queue[0] = KC_NO;
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_queue(void) {
|
|
||||||
uprintf("queue: ");
|
|
||||||
|
|
||||||
for (int i = 0; i < PREV_KEYS_QUEUE_SIZE - 1; i += 1)
|
|
||||||
uprintf("%d, ", prev_keys_queue[i]);
|
|
||||||
|
|
||||||
uprintf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t normalize_keycode(uint16_t keycode) {
|
|
||||||
if (IS_QK_MOD_TAP(keycode)) return QK_MOD_TAP_GET_TAP_KEYCODE(keycode);
|
|
||||||
if (IS_QK_LAYER_TAP(keycode)) return QK_LAYER_TAP_GET_TAP_KEYCODE(keycode);
|
|
||||||
|
|
||||||
return keycode;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record, uint8_t* mods) {
|
|
||||||
keycode = normalize_keycode(keycode);
|
|
||||||
|
|
||||||
switch (keycode) {
|
|
||||||
case KC_BSPC:
|
|
||||||
case KC_LEFT:
|
|
||||||
dequeue();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(*mods & MOD_MASK_CTRL) &&
|
|
||||||
((keycode == KC_BSPC && record->tap.count) || (keycode == KC_BSPC))
|
|
||||||
) keycode = KC_SPC;
|
|
||||||
|
|
||||||
switch (keycode) {
|
|
||||||
case KC_ENT:
|
|
||||||
case KC_TAB:
|
|
||||||
case KC_BSPC:
|
|
||||||
case LCTL(KC_BSPC):
|
|
||||||
case KC_LEFT:
|
|
||||||
case KC_DQUO:
|
|
||||||
case KC_LPRN:
|
|
||||||
case KC_SPC:
|
|
||||||
keycode = KC_SPC;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KC_A ... KC_Z:
|
|
||||||
if ((*mods & ~(MOD_MASK_SHIFT)) == 0) {
|
|
||||||
*mods &= ~MOD_MASK_SHIFT;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case US_MAG1:
|
|
||||||
case US_MAG2:
|
|
||||||
case US_MAG3:
|
|
||||||
case US_MAG4:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueue(keycode);
|
|
||||||
print_queue();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sturdy_pr(uint16_t keycode, keyrecord_t *record, bool *return_value) {
|
|
||||||
*return_value = false;
|
|
||||||
prev_key_time = last_key_pressed_time;
|
|
||||||
|
|
||||||
if (record->event.pressed) {
|
|
||||||
last_key_pressed_time = timer_read();
|
|
||||||
refresh_token();
|
|
||||||
|
|
||||||
if (keycode != US_MAG1) mag1_key_count = 0;
|
|
||||||
else mag1_key_count += 1;
|
|
||||||
|
|
||||||
if (keycode != US_MAG2) mag2_key_count = 0;
|
|
||||||
else mag2_key_count += 1;
|
|
||||||
|
|
||||||
if (keycode != US_MAG4) mag3_key_count = 0;
|
|
||||||
else mag3_key_count += 1;
|
|
||||||
|
|
||||||
if (keycode != US_MAG4) mag4_key_count = 0;
|
|
||||||
else mag4_key_count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (keycode) {
|
|
||||||
case US_MAG1:
|
|
||||||
if (record->event.pressed)
|
|
||||||
process_magic_key_1();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case US_MAG2:
|
|
||||||
if (record->event.pressed)
|
|
||||||
process_magic_key_2();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case US_MAG3:
|
|
||||||
if (record->event.pressed)
|
|
||||||
process_magic_key_3();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case US_MAG4:
|
|
||||||
if (record->event.pressed)
|
|
||||||
process_magic_key_4();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// case KC_B:
|
|
||||||
// case KC_Z:
|
|
||||||
// case KC_F:
|
|
||||||
// return process_double_tap(keycode, record);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// bool process_double_tap(uint16_t keycode, keyrecord_t *record) {
|
|
||||||
// if (
|
|
||||||
// !record->event.pressed ||
|
|
||||||
// highest_layer != STURDY ||
|
|
||||||
// queue(-2) != keycode ||
|
|
||||||
// timer_elapsed(prev_key_time) > (get_tapping_term(keycode, NULL) + 50)
|
|
||||||
// ) return false;
|
|
||||||
|
|
||||||
// dequeue();
|
|
||||||
// process_magic_key();
|
|
||||||
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
// Originally from QKekos
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "../__init__.h"
|
|
||||||
|
|
||||||
#define PREV_KEYS_QUEUE_SIZE 10
|
|
||||||
#define MAGIC_KEY_TIMEOUT 2000
|
|
||||||
|
|
||||||
bool sturdy_pr(uint16_t keycode, keyrecord_t *record, bool *return_value);
|
|
||||||
bool remember_last_key_user(uint16_t keycode, keyrecord_t* record, uint8_t* mods);
|
|
||||||
bool process_double_tap(uint16_t keycode, keyrecord_t *record);
|
|
||||||
void record_send_string(const char *str);
|
|
||||||
void enqueue(int keycode);
|
|
||||||
void dequeue(void);
|
|
||||||
void print_queue(void);
|
|
||||||
|
|
||||||
uint32_t enqueue_space(uint32_t trigger_time, void *cb_arg);
|
|
||||||
void refresh_token(void);
|
|
||||||
|
|
||||||
extern int prev_keys_queue[];
|
|
||||||
extern int mag1_key_count;
|
|
||||||
extern int mag2_key_count;
|
|
||||||
extern int mag3_key_count;
|
|
||||||
extern int mag4_key_count;
|
|
||||||
extern int last_key_pressed_time;
|
|
||||||
|
|
||||||
#define queue(i) prev_keys_queue[PREV_KEYS_QUEUE_SIZE + i]
|
|
||||||
|
|
||||||
#define record_case(symbol, keycode) \
|
|
||||||
case symbol: \
|
|
||||||
enqueue(keycode); \
|
|
||||||
continue
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
|
|
||||||
#include "../__init__.h"
|
|
||||||
#include "keycodes.h"
|
|
||||||
#include "keymap_us.h"
|
|
||||||
#include "magic_sturdy/__init__.h"
|
|
||||||
#include "magic_sturdy/general.h"
|
|
||||||
|
|
||||||
void process_magic_key_1(void) {
|
|
||||||
if (mag1_key_count >= 2) {
|
|
||||||
switch (queue(-5)) {
|
|
||||||
quintuple_magic_case(KC_J, KC_U, KC_D, KC_G, KC_E, "\bment");
|
|
||||||
}
|
|
||||||
switch (queue(-4)) {
|
|
||||||
quadruple_magic_case(KC_SPC, KC_A, KC_L, KC_R, "eady");
|
|
||||||
quadruple_magic_switch(KC_J,
|
|
||||||
triple_magic_switch(KC_U,
|
|
||||||
double_magic_case(KC_D, KC_G, "ment");
|
|
||||||
double_magic_case(KC_S, KC_T, "ment");
|
|
||||||
);
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-3)) {
|
|
||||||
triple_magic_case(KC_A, KC_B, KC_O, "ve");
|
|
||||||
default: record_send_string("n"); return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-5)) {
|
|
||||||
quintuple_magic_switch(KC_B,
|
|
||||||
quadruple_magic_case(KC_A, KC_L, KC_L, KC_I, "st");
|
|
||||||
quadruple_magic_case(KC_L, KC_I, KC_V, KC_I, "on");
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-4)) {
|
|
||||||
quadruple_magic_case(KC_A, KC_B, KC_E, KC_T, "ment");
|
|
||||||
quadruple_magic_case(KC_V, KC_I, KC_L, KC_I, "on");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-3)) {
|
|
||||||
triple_magic_switch(KC_SPC,
|
|
||||||
double_magic_switch(KC_A,
|
|
||||||
magic_case(KC_L, "r");
|
|
||||||
magic_case(KC_N, "other");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_switch(KC_E,
|
|
||||||
magic_case(KC_D, "ge");
|
|
||||||
magic_case(KC_X, "ample");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_switch(KC_T,
|
|
||||||
magic_case(KC_A, "ke");
|
|
||||||
magic_case(KC_I, "me");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_case(KC_M, KC_A, "ke");
|
|
||||||
|
|
||||||
double_magic_case(KC_U, KC_S, "e");
|
|
||||||
double_magic_case(KC_I, KC_N, "form");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_B,
|
|
||||||
double_magic_switch(KC_E,
|
|
||||||
magic_case(KC_T, "ween");
|
|
||||||
magic_case(KC_L, "ieve");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_case(KC_U, KC_D, "ge");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_V,
|
|
||||||
double_magic_switch(KC_A,
|
|
||||||
magic_case(KC_R, "ious");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_case(KC_I, KC_D, "eo");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_R,
|
|
||||||
double_magic_case(KC_I, KC_D, "ge");
|
|
||||||
double_magic_case(KC_E, KC_D, "ge");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_S,
|
|
||||||
double_magic_case(KC_Y, KC_S, "tem");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_G,
|
|
||||||
double_magic_case(KC_E, KC_N, "ious");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_D,
|
|
||||||
double_magic_case(KC_I, KC_F, "feren");
|
|
||||||
double_magic_case(KC_E, KC_F, "inite");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_L,
|
|
||||||
double_magic_case(KC_E, KC_D, "ge");
|
|
||||||
double_magic_case(KC_L, KC_I, "on");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_A,
|
|
||||||
double_magic_case(KC_N, KC_Y, "way");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_case(KC_J, KC_U, KC_D, "ge");
|
|
||||||
triple_magic_case(KC_O, KC_B, KC_V, "ious");
|
|
||||||
triple_magic_case(KC_H, KC_I, KC_L, "arious");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-2)) {
|
|
||||||
double_magic_switch(KC_SPC,
|
|
||||||
magic_case(KC_T, "han");
|
|
||||||
magic_case(KC_L, "ittle");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_switch(KC_P,
|
|
||||||
magic_case(KC_L, "y");
|
|
||||||
magic_case(KC_A, "ge");
|
|
||||||
magic_case(KC_E, "ople");
|
|
||||||
magic_case(KC_R, "evious");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_switch(KC_D,
|
|
||||||
magic_case(KC_A, "y");
|
|
||||||
magic_case(KC_R, "y");
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_case(KC_W, KC_A, "y");
|
|
||||||
double_magic_case(KC_B, KC_E, "en");
|
|
||||||
double_magic_case(KC_L, KC_I, "st");
|
|
||||||
double_magic_case(KC_V, KC_I, "sion");
|
|
||||||
double_magic_case(KC_A, KC_B, "ility");
|
|
||||||
double_magic_case(KC_I, KC_B, "ility");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-1)) {
|
|
||||||
magic_case(KC_SPC, "the");
|
|
||||||
|
|
||||||
magic_case(KC_V, "er");
|
|
||||||
magic_case(KC_S, "k");
|
|
||||||
magic_case(KC_X, "es");
|
|
||||||
|
|
||||||
magic_case(KC_M, "ent");
|
|
||||||
magic_case(KC_T, "ment");
|
|
||||||
magic_case(KC_K, "s");
|
|
||||||
|
|
||||||
magic_case(KC_L, "k");
|
|
||||||
magic_case(KC_R, "l");
|
|
||||||
magic_case(KC_J, "ust");
|
|
||||||
|
|
||||||
magic_case(KC_C, "y");
|
|
||||||
magic_case(KC_D, "y");
|
|
||||||
magic_case(KC_G, "y");
|
|
||||||
magic_case(KC_P, "y");
|
|
||||||
magic_case(KC_Y, "p");
|
|
||||||
magic_case(KC_W, "hich");
|
|
||||||
magic_case(KC_Q, "uestion");
|
|
||||||
|
|
||||||
magic_case(KC_B, "efore");
|
|
||||||
magic_case(KC_F, "irst");
|
|
||||||
magic_case(KC_Z, "one");
|
|
||||||
// US_MAG1
|
|
||||||
magic_case(KC_N, "ion");
|
|
||||||
magic_case(KC_H, "owever");
|
|
||||||
|
|
||||||
magic_case(KC_U, "e");
|
|
||||||
magic_case(KC_E, "u");
|
|
||||||
// KC_QUOT
|
|
||||||
|
|
||||||
magic_case(KC_O, "a");
|
|
||||||
magic_case(KC_A, "bo");
|
|
||||||
// KC_QUES
|
|
||||||
|
|
||||||
magic_case(KC_COMM, get_last_mods() & MOD_MASK_SHIFT ? "=" : " but");
|
|
||||||
magic_case(KC_I, "on");
|
|
||||||
magic_case(KC_DOT, get_last_mods() & MOD_MASK_SHIFT ? "=" : "\\");
|
|
||||||
magic_case(KC_MINS, ">");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_magic_key_2(void) {
|
|
||||||
switch (queue(-5)) {
|
|
||||||
quintuple_magic_switch(KC_SPC,
|
|
||||||
quadruple_magic_case(KC_M, KC_A, KC_K, KC_E, "\bing");
|
|
||||||
quadruple_magic_case(KC_T, KC_A, KC_K, KC_E, "\bing");
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-4)) {
|
|
||||||
quadruple_magic_switch(KC_SPC,
|
|
||||||
triple_magic_case(KC_A, KC_L, KC_R, "ight");
|
|
||||||
triple_magic_case(KC_R, KC_E, KC_V, "iew");
|
|
||||||
triple_magic_switch(KC_U,
|
|
||||||
double_magic_switch(KC_N,
|
|
||||||
magic_case(KC_F, "ollow");
|
|
||||||
magic_case(KC_P, "roblem");
|
|
||||||
);
|
|
||||||
);
|
|
||||||
);
|
|
||||||
}
|
|
||||||
switch (queue(-3)) {
|
|
||||||
triple_magic_switch(KC_SPC,
|
|
||||||
double_magic_case(KC_O, KC_X, "ygen");
|
|
||||||
double_magic_case(KC_S, KC_C, "hool");
|
|
||||||
double_magic_case(KC_P, KC_S, "ych");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_switch(KC_A,
|
|
||||||
double_magic_case(KC_B, KC_O, "ut");
|
|
||||||
double_magic_case(KC_N, KC_Y, "where");
|
|
||||||
);
|
|
||||||
|
|
||||||
triple_magic_case(KC_R, KC_S, KC_C, "hool");
|
|
||||||
triple_magic_case(KC_I, KC_T, KC_Y, "\bies");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-2)) {
|
|
||||||
double_magic_switch(KC_SPC,
|
|
||||||
magic_case(KC_V, "iew");
|
|
||||||
magic_case(KC_S, "hould");
|
|
||||||
// KC_X, "er"
|
|
||||||
|
|
||||||
magic_case(KC_M, "ight");
|
|
||||||
magic_case(KC_T, "hrough");
|
|
||||||
// KC_K, "now"
|
|
||||||
|
|
||||||
magic_case(KC_L, "ight");
|
|
||||||
magic_case(KC_R, "ight");
|
|
||||||
// KC_J, "oin"
|
|
||||||
|
|
||||||
magic_case(KC_C, "ould");
|
|
||||||
magic_case(KC_D, "on't");
|
|
||||||
magic_case(KC_G, "eneral");
|
|
||||||
|
|
||||||
magic_case(KC_P, "roblem");
|
|
||||||
// KC_Y, "ou"
|
|
||||||
// KC_W, "ould"
|
|
||||||
|
|
||||||
magic_case(KC_B, "ecause");
|
|
||||||
magic_case(KC_F, "ollow");
|
|
||||||
magic_case(KC_Z, "ero");
|
|
||||||
|
|
||||||
// KC_MAG1
|
|
||||||
magic_case(KC_N, "umber");
|
|
||||||
magic_case(KC_H, "owever");
|
|
||||||
|
|
||||||
magic_case(KC_U, "pdate");
|
|
||||||
magic_case(KC_E, "nough");
|
|
||||||
// KC_QUOT
|
|
||||||
|
|
||||||
magic_case(KC_O, "ften");
|
|
||||||
// KC_A, "nd"
|
|
||||||
// KC_QUES, " " OSS
|
|
||||||
|
|
||||||
// KC_COMM, " and"
|
|
||||||
magic_case(KC_I, "ncrease");
|
|
||||||
// KC_DOT, " " OSS
|
|
||||||
);
|
|
||||||
|
|
||||||
double_magic_case(KC_F, KC_R, "om");
|
|
||||||
double_magic_case(KC_A, KC_U, "ght");
|
|
||||||
double_magic_case(KC_O, KC_U, "ght");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (queue(-1)) {
|
|
||||||
magic_case(KC_SPC, "for");
|
|
||||||
magic_case(KC_A, "nd");
|
|
||||||
magic_case(KC_X, "er");
|
|
||||||
magic_case(KC_K, "now");
|
|
||||||
magic_case(KC_I, "ng");
|
|
||||||
magic_case(KC_Y, "ou");
|
|
||||||
magic_case(KC_Q, "uick");
|
|
||||||
magic_case(KC_J, "oin");
|
|
||||||
magic_case(KC_W, "ould");
|
|
||||||
magic_case(KC_C, "k");
|
|
||||||
magic_case(KC_N, "f");
|
|
||||||
magic_case(KC_H, "n");
|
|
||||||
magic_case(KC_COMMA, " and");
|
|
||||||
case KC_DOT:
|
|
||||||
case KC_QUES:
|
|
||||||
case KC_EXLM:
|
|
||||||
case KC_COLN:
|
|
||||||
case KC_SCLN:
|
|
||||||
unregister_weak_mods(MOD_MASK_CSAG);
|
|
||||||
send_char(' ');
|
|
||||||
add_oneshot_mods(MOD_MASK_SHIFT);
|
|
||||||
enqueue(KC_SPC);
|
|
||||||
return;
|
|
||||||
default: tap_code16(queue(-1)); enqueue(queue(-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_magic_key_3(void) {
|
|
||||||
switch (queue(-1)) {
|
|
||||||
magic_case(KC_V, "isit");
|
|
||||||
magic_case(KC_S, "mall");
|
|
||||||
// KC_X
|
|
||||||
|
|
||||||
magic_case(KC_M, "anage");
|
|
||||||
magic_case(KC_T, "hough");
|
|
||||||
magic_case(KC_K, "new");
|
|
||||||
|
|
||||||
magic_case(KC_L, "ocation");
|
|
||||||
magic_case(KC_R, "ecommend");
|
|
||||||
magic_case(KC_J, "udge");
|
|
||||||
|
|
||||||
magic_case(KC_C, "onsider");
|
|
||||||
magic_case(KC_D, "evelop");
|
|
||||||
magic_case(KC_G, "overn");
|
|
||||||
|
|
||||||
magic_case(KC_P, "ower");
|
|
||||||
// KC_Y
|
|
||||||
magic_case(KC_W, "here");
|
|
||||||
magic_case(KC_Q, "mlativ");
|
|
||||||
|
|
||||||
magic_case(KC_B, "ecome");
|
|
||||||
magic_case(KC_F, "ound");
|
|
||||||
// KC_Z
|
|
||||||
|
|
||||||
// KC_MAG1
|
|
||||||
magic_case(KC_N, "eighbor");
|
|
||||||
magic_case(KC_H, "appen");
|
|
||||||
|
|
||||||
magic_case(KC_U, "pgrade");
|
|
||||||
magic_case(KC_E, "'ll");
|
|
||||||
// KC_QUOT
|
|
||||||
|
|
||||||
magic_case(KC_O, "ther");
|
|
||||||
magic_case(KC_A, "fter");
|
|
||||||
// KC_QUES
|
|
||||||
|
|
||||||
magic_case(KC_COMM, " however");
|
|
||||||
magic_case(KC_I, "'ll");
|
|
||||||
magic_case(KC_DOT, "org");
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_magic_key_4(void) {
|
|
||||||
switch (queue(-1)) {
|
|
||||||
magic_case(KC_B, "etween");
|
|
||||||
magic_case(KC_N, "ation");
|
|
||||||
magic_case(KC_U, "nivers");
|
|
||||||
magic_case(KC_O, "ption");
|
|
||||||
magic_case(KC_A, "gainst");
|
|
||||||
magic_case(KC_P, "rogram");
|
|
||||||
magic_case(KC_I, "'m");
|
|
||||||
magic_case(KC_T, "echnology");
|
|
||||||
magic_case(KC_C, "rowd");
|
|
||||||
magic_case(KC_W, "orld");
|
|
||||||
magic_case(KC_S, "ervice");
|
|
||||||
magic_case(KC_E, "'re");
|
|
||||||
magic_case(KC_Q, "uiet");
|
|
||||||
magic_case(KC_DOT, "com");
|
|
||||||
magic_case(KC_COMM, " since");
|
|
||||||
default: return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "../__init__.h"
|
|
||||||
|
|
||||||
void process_magic_key_1(void);
|
|
||||||
void process_magic_key_2(void);
|
|
||||||
void process_magic_key_3(void);
|
|
||||||
void process_magic_key_4(void);
|
|
||||||
82
keyboards/moonlander/keymaps/ikcelaks/magic_sturdy/utils.c
Normal file
82
keyboards/moonlander/keymaps/ikcelaks/magic_sturdy/utils.c
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "utils.h"
|
||||||
|
#include "send_string.h"
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
// Note: we bit-pack in "reverse" order to optimize loading
|
||||||
|
#define PGM_LOADBIT(mem, pos) ((pgm_read_byte(&((mem)[(pos) / 8])) >> ((pos) % 8)) & 0x01)
|
||||||
|
|
||||||
|
const char unshifted_keycode_to_ascii_lut[53] PROGMEM = {
|
||||||
|
// KC_A KC_B KC_C KC_D
|
||||||
|
'a', 'b', 'c', 'd',
|
||||||
|
// KC_E KC_F KC_G KC_H KC_I KC_J KC_K KC_L
|
||||||
|
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l',
|
||||||
|
// KC_M KC_N KC_O KC_P KC_Q KC_R KC_S KC_T
|
||||||
|
'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||||
|
// KC_U KC_V KC_W KC_X KC_Y KC_Z KC_1 KC_2
|
||||||
|
'u', 'v', 'w', 'x', 'y', 'z', '1', '2',
|
||||||
|
// KC_3 KC_4 KC_5 KC_6 KC_7 KC_8 KC_9 KC_0
|
||||||
|
'3', '4', '5', '6', '7', '8', '9', '0',
|
||||||
|
// KC_ENTR KC_ESC KC_BSPC KC_TAB KC_SPC KC_MINS KC_EQL KC_LBRC
|
||||||
|
' ', ' ', ' ', ' ', ' ', '-', '=', '[',
|
||||||
|
// KC_RBRC KC_BSLS KC_NUHS KC_SCLN KC_QUOT KC_GRV KC_COMM KC_DOT
|
||||||
|
']', '\\', ' ', ';', '\'', '`', ',', '.',
|
||||||
|
// KC_SLSH
|
||||||
|
'/'
|
||||||
|
};
|
||||||
|
const char shifted_keycode_to_ascii_lut[53] PROGMEM = {
|
||||||
|
// KC_A KC_B KC_C KC_D
|
||||||
|
'A', 'B', 'C', 'D',
|
||||||
|
// KC_E KC_F KC_G KC_H KC_I KC_J KC_K KC_L
|
||||||
|
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
|
||||||
|
// KC_M KC_N KC_O KC_P KC_Q KC_R KC_S KC_T
|
||||||
|
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
|
||||||
|
// KC_U KC_V KC_W KC_X KC_Y KC_Z KC_EXLM KC_AT
|
||||||
|
'U', 'V', 'W', 'X', 'Y', 'Z', '!', '@',
|
||||||
|
// KC_HASH KC_DLR KC_PERC KC_CIRC KC_AMPR KC_ASTR KC_LPRN KC_RPRN
|
||||||
|
'#', '$', '%', '^', '&', '*', '(', ')',
|
||||||
|
// KC_ENTR KC_ESC KC_BSPC KC_TAB KC_SPC KC_UNDS KC_PLUS KC_LCBR
|
||||||
|
' ', ' ', ' ', ' ', ' ', '_', '+', '{',
|
||||||
|
// KC_RCBR KC_PIPE KC_NUHS KC_COLN KC_DQUO KC_GRV KC_LABK KC_RABK
|
||||||
|
'}', '|', ' ', ':', '"', '~', '<', '>',
|
||||||
|
// KC_QUES
|
||||||
|
'?'
|
||||||
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
char keycode_to_char(uint16_t keycode)
|
||||||
|
{
|
||||||
|
const bool shifted = keycode & QK_LSFT;
|
||||||
|
keycode &= 0xFF;
|
||||||
|
if (keycode >= KC_A && keycode <= KC_SLASH) {
|
||||||
|
keycode -= KC_A;
|
||||||
|
return shifted ? pgm_read_byte(&shifted_keycode_to_ascii_lut[keycode]) :
|
||||||
|
pgm_read_byte(&unshifted_keycode_to_ascii_lut[keycode]);
|
||||||
|
}
|
||||||
|
return ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
uint16_t char_to_keycode(char c)
|
||||||
|
{
|
||||||
|
uint16_t k = pgm_read_byte(&ascii_to_keycode_lut[(uint8_t)c]);
|
||||||
|
bool is_shifted = PGM_LOADBIT(ascii_to_shift_lut, (uint8_t)c);
|
||||||
|
if (is_shifted)
|
||||||
|
k = S(k);
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// removes mod or layer info from a keycode
|
||||||
|
uint16_t normalize_keycode(uint16_t keycode)
|
||||||
|
{
|
||||||
|
if (IS_QK_MOD_TAP(keycode))
|
||||||
|
return QK_MOD_TAP_GET_TAP_KEYCODE(keycode);
|
||||||
|
if (IS_QK_LAYER_TAP(keycode))
|
||||||
|
return QK_LAYER_TAP_GET_TAP_KEYCODE(keycode);
|
||||||
|
return keycode;
|
||||||
|
}
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
void multi_tap(uint16_t keycode, int count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; ++i)
|
||||||
|
tap_code16(keycode);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint16_t char_to_keycode(char c);
|
||||||
|
char keycode_to_char(uint16_t keycode);
|
||||||
|
uint16_t normalize_keycode(uint16_t keycode);
|
||||||
|
void multi_tap(uint16_t keycode, int count);
|
||||||
|
|
@ -26,18 +26,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
// Autocorrection dictionary with longest match semantics:
|
// Autocorrection dictionary with longest match semantics:
|
||||||
// Autocorrection dictionary (25 entries):
|
// Autocorrection dictionary (59 entries):
|
||||||
// c👆 -> cy
|
|
||||||
// p👆 -> py
|
|
||||||
// d👆 -> dy
|
|
||||||
// y👆 -> yp
|
|
||||||
// g👆 -> gy
|
|
||||||
// 👍 -> ↻
|
// 👍 -> ↻
|
||||||
// i👍 -> ing
|
|
||||||
// a👍 -> and
|
|
||||||
// :👆 -> the
|
|
||||||
// :👍 -> for
|
|
||||||
// .👍 -> .:⇑
|
|
||||||
// j👆 -> just
|
// j👆 -> just
|
||||||
// j👆👆 -> justment
|
// j👆👆 -> justment
|
||||||
// 👆👆 -> 👆n
|
// 👆👆 -> 👆n
|
||||||
|
|
@ -52,28 +42,87 @@
|
||||||
// :i👍m -> I'm
|
// :i👍m -> I'm
|
||||||
// :i👍d -> I'd
|
// :i👍d -> I'd
|
||||||
// :i👍l -> I'll
|
// :i👍l -> I'll
|
||||||
|
// :👆 -> the
|
||||||
|
// v👆 -> ver
|
||||||
|
// s👆 -> sk
|
||||||
|
// x👆 -> es
|
||||||
|
// m👆 -> ment
|
||||||
|
// t👆 -> tment
|
||||||
|
// k👆 -> ks
|
||||||
|
// l👆 -> lk
|
||||||
|
// r👆 -> rl
|
||||||
|
// c👆 -> cy
|
||||||
|
// p👆 -> py
|
||||||
|
// d👆 -> dy
|
||||||
|
// y👆 -> yp
|
||||||
|
// g👆 -> gy
|
||||||
|
// w👆 -> which
|
||||||
|
// q👆 -> question
|
||||||
|
// b👆 -> before
|
||||||
|
// f👆 -> first
|
||||||
|
// z👆 -> zone
|
||||||
|
// n👆 -> nion
|
||||||
|
// h👆 -> however
|
||||||
|
// u👆 -> eu
|
||||||
|
// e👆 -> ue
|
||||||
|
// o👆 -> oa
|
||||||
|
// a👆 -> abo
|
||||||
|
// ,👆 -> ,:but
|
||||||
|
// i👆 -> ion
|
||||||
|
// .👆 -> .\ [escape]
|
||||||
|
// :👍 -> for
|
||||||
|
// a👍 -> and
|
||||||
|
// x👍 -> xer
|
||||||
|
// k👍 -> know
|
||||||
|
// i👍 -> ing
|
||||||
|
// y👍 -> you
|
||||||
|
// q👍 -> quick
|
||||||
|
// w👍 -> would
|
||||||
|
// c👍 -> ck
|
||||||
|
// n👍 -> nf
|
||||||
|
// h👍 -> hn
|
||||||
|
// ,👍 -> ,:and
|
||||||
|
// .👍 -> .:⇑
|
||||||
|
// ?👍 -> ?:⇑
|
||||||
|
// ;👍 -> ;:⇑
|
||||||
|
// !👍 -> !:⇑
|
||||||
|
|
||||||
#define MAGICKEY_MIN_LENGTH 1 // "👍"
|
#define MAGICKEY_MIN_LENGTH 1 // "👍"
|
||||||
#define MAGICKEY_MAX_LENGTH 5 // "jud👆👆"
|
#define MAGICKEY_MAX_LENGTH 5 // "jud👆👆"
|
||||||
#define DICTIONARY_SIZE 134
|
#define DICTIONARY_SIZE 270
|
||||||
#define COMPLETIONS_SIZE 64
|
#define COMPLETIONS_SIZE 161
|
||||||
#define MAGICKEY_COUNT 4
|
#define MAGICKEY_COUNT 4
|
||||||
|
|
||||||
static const uint16_t magickey_data[DICTIONARY_SIZE] PROGMEM = {
|
static const uint16_t magickey_data[DICTIONARY_SIZE] PROGMEM = {
|
||||||
0x4007, 0x0011, 0x000F, 0x001F, 0x0010, 0x0025, 0x0015, 0x002B, 0x0017, 0x0030, 0x0102, 0x0035, 0x0100, 0x0039, 0x0101, 0x006B,
|
0x4007, 0x0011, 0x000F, 0x001F, 0x0010, 0x0025, 0x0015, 0x002B, 0x0017, 0x0030, 0x0102, 0x0035, 0x0100, 0x0039, 0x0101, 0x00C3,
|
||||||
0x0000, 0x4102, 0x0016, 0x0101, 0x001A, 0x0000, 0x0007, 0x0000, 0x8000, 0x0000, 0x000C, 0x002C, 0x0000, 0x8000, 0x0003, 0x0101,
|
0x0000, 0x4102, 0x0016, 0x0101, 0x001A, 0x0000, 0x0007, 0x0000, 0x8000, 0x0000, 0x000C, 0x002C, 0x0000, 0x8000, 0x0003, 0x0101,
|
||||||
0x000C, 0x002C, 0x0000, 0x8000, 0x0006, 0x0101, 0x000C, 0x002C, 0x0000, 0x8000, 0x000A, 0x0102, 0x0007, 0x0000, 0x8000, 0x000D,
|
0x000C, 0x002C, 0x0000, 0x8000, 0x0006, 0x0101, 0x000C, 0x002C, 0x0000, 0x8000, 0x000A, 0x0102, 0x0007, 0x0000, 0x8000, 0x000D,
|
||||||
0x0102, 0x0007, 0x0000, 0x8000, 0x0010, 0x0007, 0x0000, 0x8000, 0x0015, 0x402C, 0x004A, 0x0006, 0x004C, 0x0007, 0x004E, 0x000A,
|
0x0102, 0x0007, 0x0000, 0x8000, 0x0010, 0x0007, 0x0000, 0x8000, 0x0015, 0x4036, 0x0076, 0x0037, 0x0078, 0x002C, 0x007A, 0x0004,
|
||||||
0x0055, 0x000D, 0x0057, 0x0013, 0x0059, 0x001C, 0x005B, 0x0100, 0x005D, 0x0000, 0x8000, 0x001C, 0x8000, 0x0020, 0xC000, 0x0020,
|
0x007C, 0x0005, 0x007E, 0x0006, 0x0080, 0x0007, 0x0082, 0x0008, 0x0089, 0x0009, 0x008B, 0x000A, 0x008D, 0x000B, 0x008F, 0x000C,
|
||||||
0x0018, 0x000D, 0x0000, 0x8000, 0x0022, 0x8000, 0x0020, 0x8000, 0x0025, 0x8000, 0x0020, 0x8000, 0x0029, 0xC000, 0x002B, 0x4007,
|
0x0091, 0x000D, 0x0093, 0x000E, 0x0095, 0x000F, 0x0097, 0x0010, 0x0099, 0x0011, 0x009B, 0x0012, 0x009D, 0x0013, 0x009F, 0x0014,
|
||||||
0x0064, 0x000D, 0x0069, 0x0000, 0x0018, 0x000D, 0x0000, 0x8001, 0x0010, 0x8000, 0x0010, 0xC800, 0x002D, 0x4037, 0x0078, 0x002C,
|
0x00A1, 0x0015, 0x00A3, 0x0016, 0x00A5, 0x0017, 0x00A7, 0x0018, 0x00A9, 0x0019, 0x00AB, 0x001A, 0x00AD, 0x001B, 0x00AF, 0x001C,
|
||||||
0x007A, 0x0004, 0x007C, 0x000C, 0x007E, 0x000D, 0x0084, 0x0000, 0x9000, 0x002E, 0x8000, 0x0030, 0x8000, 0x0034, 0xC000, 0x0037,
|
0x00B1, 0x001D, 0x00B3, 0x0100, 0x00B5, 0x0000, 0x8000, 0x001C, 0x8000, 0x0021, 0x8000, 0x0023, 0x8000, 0x0027, 0x8000, 0x002A,
|
||||||
0x002C, 0x0000, 0x8001, 0x003A, 0x8000, 0x003C
|
0x8000, 0x0030, 0xC000, 0x0030, 0x0018, 0x000D, 0x0000, 0x8000, 0x0032, 0x8001, 0x0035, 0x8000, 0x0038, 0x8000, 0x0030, 0x8000,
|
||||||
|
0x003D, 0x8000, 0x0044, 0x8000, 0x0047, 0x8000, 0x004B, 0x8000, 0x004D, 0x8000, 0x004F, 0x8000, 0x0053, 0x8000, 0x0057, 0x8000,
|
||||||
|
0x0030, 0x8000, 0x0059, 0x8000, 0x0061, 0x8000, 0x004D, 0x8000, 0x0010, 0x8001, 0x0063, 0x8000, 0x000D, 0x8000, 0x0066, 0x8001,
|
||||||
|
0x006B, 0x8000, 0x006E, 0x8000, 0x0070, 0xC000, 0x0074, 0x4007, 0x00BC, 0x000D, 0x00C1, 0x0000, 0x0018, 0x000D, 0x0000, 0x8001,
|
||||||
|
0x0010, 0x8000, 0x0010, 0xC800, 0x0076, 0x421E, 0x00E8, 0x0036, 0x00EA, 0x0037, 0x00EC, 0x002C, 0x00EE, 0x0033, 0x00F0, 0x0238,
|
||||||
|
0x00F2, 0x0004, 0x00F4, 0x0006, 0x00F6, 0x000B, 0x00F8, 0x000C, 0x00FA, 0x000D, 0x0100, 0x000E, 0x0102, 0x0011, 0x0104, 0x0014,
|
||||||
|
0x0106, 0x001A, 0x0108, 0x001B, 0x010A, 0x001C, 0x010C, 0x0000, 0x9000, 0x0077, 0x8000, 0x0079, 0x9000, 0x0077, 0x8000, 0x007E,
|
||||||
|
0x9000, 0x0077, 0x9000, 0x0077, 0x8000, 0x0082, 0x8000, 0x004D, 0x8000, 0x0074, 0xC000, 0x0085, 0x002C, 0x0000, 0x8001, 0x0088,
|
||||||
|
0x8000, 0x008A, 0x8000, 0x008E, 0x8000, 0x0092, 0x8000, 0x0094, 0x8000, 0x0099, 0x8000, 0x000D, 0x8000, 0x009E
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t magickey_completions_data[COMPLETIONS_SIZE] PROGMEM = {
|
static const uint8_t magickey_completions_data[COMPLETIONS_SIZE] PROGMEM = {
|
||||||
0x65, 0x64, 0x00, 0x27, 0x64, 0x00, 0x27, 0x6C, 0x6C, 0x00, 0x27, 0x6D, 0x00, 0x65, 0x72, 0x00,
|
0x65, 0x64, 0x00, 0x27, 0x64, 0x00, 0x27, 0x6C, 0x6C, 0x00, 0x27, 0x6D, 0x00, 0x65, 0x72, 0x00,
|
||||||
0x6D, 0x65, 0x6E, 0x74, 0x00, 0x65, 0x76, 0x65, 0x6C, 0x6F, 0x70, 0x00, 0x74, 0x68, 0x65, 0x00,
|
0x6D, 0x65, 0x6E, 0x74, 0x00, 0x65, 0x76, 0x65, 0x6C, 0x6F, 0x70, 0x00, 0x20, 0x62, 0x75, 0x74,
|
||||||
0x79, 0x00, 0x67, 0x65, 0x00, 0x75, 0x73, 0x74, 0x00, 0x70, 0x00, 0x6E, 0x00, 0x00, 0x3A, 0x00,
|
0x00, 0x5C, 0x00, 0x74, 0x68, 0x65, 0x00, 0x62, 0x6F, 0x00, 0x65, 0x66, 0x6F, 0x72, 0x65, 0x00,
|
||||||
0x66, 0x6F, 0x72, 0x00, 0x6E, 0x64, 0x00, 0x6E, 0x67, 0x00, 0x49, 0x00, 0x6F, 0x69, 0x6E, 0x00
|
0x79, 0x00, 0x67, 0x65, 0x00, 0x75, 0x65, 0x00, 0x69, 0x72, 0x73, 0x74, 0x00, 0x6F, 0x77, 0x65,
|
||||||
|
0x76, 0x65, 0x72, 0x00, 0x6F, 0x6E, 0x00, 0x75, 0x73, 0x74, 0x00, 0x73, 0x00, 0x6B, 0x00, 0x65,
|
||||||
|
0x6E, 0x74, 0x00, 0x69, 0x6F, 0x6E, 0x00, 0x61, 0x00, 0x75, 0x65, 0x73, 0x74, 0x69, 0x6F, 0x6E,
|
||||||
|
0x00, 0x6C, 0x00, 0x65, 0x75, 0x00, 0x68, 0x69, 0x63, 0x68, 0x00, 0x65, 0x73, 0x00, 0x70, 0x00,
|
||||||
|
0x6F, 0x6E, 0x65, 0x00, 0x6E, 0x00, 0x00, 0x20, 0x00, 0x20, 0x61, 0x6E, 0x64, 0x00, 0x66, 0x6F,
|
||||||
|
0x72, 0x00, 0x6E, 0x64, 0x00, 0x6E, 0x67, 0x00, 0x49, 0x00, 0x6F, 0x69, 0x6E, 0x00, 0x6E, 0x6F,
|
||||||
|
0x77, 0x00, 0x66, 0x00, 0x75, 0x69, 0x63, 0x6B, 0x00, 0x6F, 0x75, 0x6C, 0x64, 0x00, 0x6F, 0x75,
|
||||||
|
0x00
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,7 @@
|
||||||
# 👆👍★✪
|
# 👆👍★✪
|
||||||
# ↻⇑
|
# ↻⇑
|
||||||
|
|
||||||
c👆 ⇒ cy
|
|
||||||
p👆 ⇒ py
|
|
||||||
d👆 ⇒ dy
|
|
||||||
y👆 ⇒ yp
|
|
||||||
g👆 ⇒ gy
|
|
||||||
👍 ⇒ ↻
|
👍 ⇒ ↻
|
||||||
i👍 ⇒ ing
|
|
||||||
a👍 ⇒ and
|
|
||||||
:👆 ⇒ the
|
|
||||||
:👍 ⇒ for
|
|
||||||
.👍 ⇒ .:⇑
|
|
||||||
|
|
||||||
j👆 ⇒ just
|
j👆 ⇒ just
|
||||||
j👆👆 ⇒ justment
|
j👆👆 ⇒ justment
|
||||||
|
|
@ -28,3 +18,63 @@ d★d ⇒ developed
|
||||||
:i👍m ⇒ I'm
|
:i👍m ⇒ I'm
|
||||||
:i👍d ⇒ I'd
|
:i👍d ⇒ I'd
|
||||||
:i👍l ⇒ I'll
|
:i👍l ⇒ I'll
|
||||||
|
|
||||||
|
# final
|
||||||
|
|
||||||
|
:👆 ⇒ the
|
||||||
|
|
||||||
|
v👆 ⇒ ver
|
||||||
|
s👆 ⇒ sk
|
||||||
|
x👆 ⇒ es
|
||||||
|
|
||||||
|
m👆 ⇒ ment
|
||||||
|
t👆 ⇒ tment
|
||||||
|
k👆 ⇒ ks
|
||||||
|
|
||||||
|
l👆 ⇒ lk
|
||||||
|
r👆 ⇒ rl
|
||||||
|
j👆 ⇒ just
|
||||||
|
|
||||||
|
c👆 ⇒ cy
|
||||||
|
p👆 ⇒ py
|
||||||
|
d👆 ⇒ dy
|
||||||
|
y👆 ⇒ yp
|
||||||
|
g👆 ⇒ gy
|
||||||
|
w👆 ⇒ which
|
||||||
|
q👆 ⇒ question
|
||||||
|
|
||||||
|
b👆 ⇒ before
|
||||||
|
f👆 ⇒ first
|
||||||
|
z👆 ⇒ zone
|
||||||
|
👆👆 ⇒ 👆n
|
||||||
|
n👆 ⇒ nion
|
||||||
|
h👆 ⇒ however
|
||||||
|
|
||||||
|
u👆 ⇒ eu
|
||||||
|
e👆 ⇒ ue
|
||||||
|
|
||||||
|
o👆 ⇒ oa
|
||||||
|
a👆 ⇒ abo
|
||||||
|
|
||||||
|
,👆 ⇒ ,:but
|
||||||
|
i👆 ⇒ ion
|
||||||
|
.👆 ⇒ .\
|
||||||
|
|
||||||
|
:👍 ⇒ for
|
||||||
|
a👍 ⇒ and
|
||||||
|
x👍 ⇒ xer
|
||||||
|
k👍 ⇒ know
|
||||||
|
i👍 ⇒ ing
|
||||||
|
y👍 ⇒ you
|
||||||
|
q👍 ⇒ quick
|
||||||
|
j👍 ⇒ join
|
||||||
|
w👍 ⇒ would
|
||||||
|
c👍 ⇒ ck
|
||||||
|
n👍 ⇒ nf
|
||||||
|
h👍 ⇒ hn
|
||||||
|
,👍 ⇒ ,:and
|
||||||
|
.👍 ⇒ .:⇑
|
||||||
|
?👍 ⇒ ?:⇑
|
||||||
|
:👍 ⇒ ::⇑
|
||||||
|
;👍 ⇒ ;:⇑
|
||||||
|
!👍 ⇒ !:⇑
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
# Set any rules.mk overrides for your specific keymap here.
|
# Set any rules.mk overrides for your specific keymap here.
|
||||||
# See rules at https://docs.qmk.fm/#/config_options?id=the-rulesmk-file
|
# See rules at https://docs.qmk.fm/#/config_options?id=the-rulesmk-file
|
||||||
CONSOLE_ENABLE = no
|
CONSOLE_ENABLE = yes
|
||||||
COMMAND_ENABLE = no
|
COMMAND_ENABLE = no
|
||||||
SPACE_CADET_ENABLE = no
|
SPACE_CADET_ENABLE = no
|
||||||
COMBO_ENABLE = yes
|
COMBO_ENABLE = yes
|
||||||
REPEAT_KEY_ENABLE = yes
|
REPEAT_KEY_ENABLE = yes
|
||||||
DEFERRED_EXEC_ENABLE = yes
|
DEFERRED_EXEC_ENABLE = yes
|
||||||
|
|
||||||
SRC += magic_sturdy/general.c
|
SRC += magic_sturdy/context_magic.c
|
||||||
SRC += magic_sturdy/magic_keys.c
|
SRC += magic_sturdy/utils.c
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "trie2.h"
|
#include "trie2.h"
|
||||||
#include "stack.h"
|
#include "stack.h"
|
||||||
#include "util.h"
|
#include "util2.h"
|
||||||
|
|
||||||
#define KEY_BUFFER_MAX_LENGTH MAGICKEY_MAX_LENGTH
|
#define KEY_BUFFER_MAX_LENGTH MAGICKEY_MAX_LENGTH
|
||||||
#define TDATA(i) trie->dict[i]
|
#define TDATA(i) trie->dict[i]
|
||||||
|
|
@ -80,9 +80,9 @@ bool search_trie2(const trie2_t *trie, int offset, trie2_visitor_t *v)
|
||||||
search_buffer_t *search = (search_buffer_t*)v->cb_data;
|
search_buffer_t *search = (search_buffer_t*)v->cb_data;
|
||||||
uint16_t code = TDATA(offset);
|
uint16_t code = TDATA(offset);
|
||||||
assert(code);
|
assert(code);
|
||||||
// MATCH node if bit 16 is set
|
// MATCH node if bit 15 is set
|
||||||
if (code & 0x8000) {
|
if (code & 0x8000) {
|
||||||
// If bit 15 is also set, there's a child node after the completion string
|
// If bit 14 is also set, there's a child node after the completion string
|
||||||
if ((code & 0x4000) && search_trie2(trie, offset+2, v))
|
if ((code & 0x4000) && search_trie2(trie, offset+2, v))
|
||||||
return true;
|
return true;
|
||||||
// If no better match found deeper, this is the result!
|
// If no better match found deeper, this is the result!
|
||||||
|
|
@ -94,7 +94,7 @@ bool search_trie2(const trie2_t *trie, int offset, trie2_visitor_t *v)
|
||||||
// Found a match so return true!
|
// Found a match so return true!
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// BRANCH node if bit 15 is set
|
// BRANCH node if bit 14 is set
|
||||||
if (code & 0x4000) {
|
if (code & 0x4000) {
|
||||||
if ((v->stack.size+1) > search->size)
|
if ((v->stack.size+1) > search->size)
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -104,7 +104,7 @@ bool search_trie2(const trie2_t *trie, int offset, trie2_visitor_t *v)
|
||||||
for (; code; offset += 2, code = TDATA(offset)) {
|
for (; code; offset += 2, code = TDATA(offset)) {
|
||||||
const char c = keycode_to_char(code);
|
const char c = keycode_to_char(code);
|
||||||
if (cur_char == c) {
|
if (cur_char == c) {
|
||||||
// Get 16bit offset to child node
|
// Get 15bit offset to child node
|
||||||
const int child_offset = TDATA(offset+1);
|
const int child_offset = TDATA(offset+1);
|
||||||
// Traverse down child node
|
// Traverse down child node
|
||||||
stack_push(&v->stack, c);
|
stack_push(&v->stack, c);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#include "keycodes.h"
|
#include "keycodes-copy.h"
|
||||||
#include "util.h"
|
#include "util2.h"
|
||||||
|
|
||||||
#define QK_LSFT 0x0200
|
#define QK_LSFT 0x0200
|
||||||
#define pgm_read_byte(address_short) *((uint8_t*)(address_short))
|
#define pgm_read_byte(address_short) *((uint8_t*)(address_short))
|
||||||
Loading…
Add table
Add a link
Reference in a new issue