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 "general/custom_keys.h"
|
||||
#include "magic_sturdy/__init__.h"
|
||||
#include "magic_sturdy/context_magic.h"
|
||||
|
|
|
|||
|
|
@ -23,3 +23,5 @@
|
|||
// User Added
|
||||
#define COMBO_COUNT 10
|
||||
#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),
|
||||
};
|
||||
|
||||
extern rgb_config_t rgb_matrix_config;
|
||||
// extern rgb_config_t rgb_matrix_config;
|
||||
|
||||
void keyboard_post_init_user(void) {
|
||||
rgb_matrix_enable();
|
||||
}
|
||||
// void keyboard_post_init_user(void) {
|
||||
// rgb_matrix_enable();
|
||||
// }
|
||||
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
bool return_value;
|
||||
// bool return_value;
|
||||
|
||||
if (sturdy_pr(keycode, record, &return_value))
|
||||
return return_value;
|
||||
// if (sturdy_pr(keycode, record, &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) {
|
||||
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
|
||||
|
||||
// Autocorrection dictionary with longest match semantics:
|
||||
// Autocorrection dictionary (25 entries):
|
||||
// c👆 -> cy
|
||||
// p👆 -> py
|
||||
// d👆 -> dy
|
||||
// y👆 -> yp
|
||||
// g👆 -> gy
|
||||
// Autocorrection dictionary (59 entries):
|
||||
// 👍 -> ↻
|
||||
// i👍 -> ing
|
||||
// a👍 -> and
|
||||
// :👆 -> the
|
||||
// :👍 -> for
|
||||
// .👍 -> .:⇑
|
||||
// j👆 -> just
|
||||
// j👆👆 -> justment
|
||||
// 👆👆 -> 👆n
|
||||
|
|
@ -52,28 +42,87 @@
|
|||
// :i👍m -> I'm
|
||||
// :i👍d -> I'd
|
||||
// :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_MAX_LENGTH 5 // "jud👆👆"
|
||||
#define DICTIONARY_SIZE 134
|
||||
#define COMPLETIONS_SIZE 64
|
||||
#define DICTIONARY_SIZE 270
|
||||
#define COMPLETIONS_SIZE 161
|
||||
#define MAGICKEY_COUNT 4
|
||||
|
||||
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,
|
||||
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,
|
||||
0x0055, 0x000D, 0x0057, 0x0013, 0x0059, 0x001C, 0x005B, 0x0100, 0x005D, 0x0000, 0x8000, 0x001C, 0x8000, 0x0020, 0xC000, 0x0020,
|
||||
0x0018, 0x000D, 0x0000, 0x8000, 0x0022, 0x8000, 0x0020, 0x8000, 0x0025, 0x8000, 0x0020, 0x8000, 0x0029, 0xC000, 0x002B, 0x4007,
|
||||
0x0064, 0x000D, 0x0069, 0x0000, 0x0018, 0x000D, 0x0000, 0x8001, 0x0010, 0x8000, 0x0010, 0xC800, 0x002D, 0x4037, 0x0078, 0x002C,
|
||||
0x007A, 0x0004, 0x007C, 0x000C, 0x007E, 0x000D, 0x0084, 0x0000, 0x9000, 0x002E, 0x8000, 0x0030, 0x8000, 0x0034, 0xC000, 0x0037,
|
||||
0x002C, 0x0000, 0x8001, 0x003A, 0x8000, 0x003C
|
||||
0x0102, 0x0007, 0x0000, 0x8000, 0x0010, 0x0007, 0x0000, 0x8000, 0x0015, 0x4036, 0x0076, 0x0037, 0x0078, 0x002C, 0x007A, 0x0004,
|
||||
0x007C, 0x0005, 0x007E, 0x0006, 0x0080, 0x0007, 0x0082, 0x0008, 0x0089, 0x0009, 0x008B, 0x000A, 0x008D, 0x000B, 0x008F, 0x000C,
|
||||
0x0091, 0x000D, 0x0093, 0x000E, 0x0095, 0x000F, 0x0097, 0x0010, 0x0099, 0x0011, 0x009B, 0x0012, 0x009D, 0x0013, 0x009F, 0x0014,
|
||||
0x00A1, 0x0015, 0x00A3, 0x0016, 0x00A5, 0x0017, 0x00A7, 0x0018, 0x00A9, 0x0019, 0x00AB, 0x001A, 0x00AD, 0x001B, 0x00AF, 0x001C,
|
||||
0x00B1, 0x001D, 0x00B3, 0x0100, 0x00B5, 0x0000, 0x8000, 0x001C, 0x8000, 0x0021, 0x8000, 0x0023, 0x8000, 0x0027, 0x8000, 0x002A,
|
||||
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 = {
|
||||
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,
|
||||
0x79, 0x00, 0x67, 0x65, 0x00, 0x75, 0x73, 0x74, 0x00, 0x70, 0x00, 0x6E, 0x00, 0x00, 0x3A, 0x00,
|
||||
0x66, 0x6F, 0x72, 0x00, 0x6E, 0x64, 0x00, 0x6E, 0x67, 0x00, 0x49, 0x00, 0x6F, 0x69, 0x6E, 0x00
|
||||
0x6D, 0x65, 0x6E, 0x74, 0x00, 0x65, 0x76, 0x65, 0x6C, 0x6F, 0x70, 0x00, 0x20, 0x62, 0x75, 0x74,
|
||||
0x00, 0x5C, 0x00, 0x74, 0x68, 0x65, 0x00, 0x62, 0x6F, 0x00, 0x65, 0x66, 0x6F, 0x72, 0x65, 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👆👆 ⇒ justment
|
||||
|
|
@ -28,3 +18,63 @@ d★d ⇒ developed
|
|||
:i👍m ⇒ I'm
|
||||
:i👍d ⇒ I'd
|
||||
: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.
|
||||
# See rules at https://docs.qmk.fm/#/config_options?id=the-rulesmk-file
|
||||
CONSOLE_ENABLE = no
|
||||
CONSOLE_ENABLE = yes
|
||||
COMMAND_ENABLE = no
|
||||
SPACE_CADET_ENABLE = no
|
||||
COMBO_ENABLE = yes
|
||||
REPEAT_KEY_ENABLE = yes
|
||||
DEFERRED_EXEC_ENABLE = yes
|
||||
|
||||
SRC += magic_sturdy/general.c
|
||||
SRC += magic_sturdy/magic_keys.c
|
||||
SRC += magic_sturdy/context_magic.c
|
||||
SRC += magic_sturdy/utils.c
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include <string.h>
|
||||
#include "trie2.h"
|
||||
#include "stack.h"
|
||||
#include "util.h"
|
||||
#include "util2.h"
|
||||
|
||||
#define KEY_BUFFER_MAX_LENGTH MAGICKEY_MAX_LENGTH
|
||||
#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;
|
||||
uint16_t code = TDATA(offset);
|
||||
assert(code);
|
||||
// MATCH node if bit 16 is set
|
||||
// MATCH node if bit 15 is set
|
||||
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))
|
||||
return true;
|
||||
// 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!
|
||||
return true;
|
||||
}
|
||||
// BRANCH node if bit 15 is set
|
||||
// BRANCH node if bit 14 is set
|
||||
if (code & 0x4000) {
|
||||
if ((v->stack.size+1) > search->size)
|
||||
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)) {
|
||||
const char c = keycode_to_char(code);
|
||||
if (cur_char == c) {
|
||||
// Get 16bit offset to child node
|
||||
// Get 15bit offset to child node
|
||||
const int child_offset = TDATA(offset+1);
|
||||
// Traverse down child node
|
||||
stack_push(&v->stack, c);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "keycodes.h"
|
||||
#include "util.h"
|
||||
#include "keycodes-copy.h"
|
||||
#include "util2.h"
|
||||
|
||||
#define QK_LSFT 0x0200
|
||||
#define pgm_read_byte(address_short) *((uint8_t*)(address_short))
|
||||
Loading…
Add table
Add a link
Reference in a new issue