-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cleanup and refactoring, mostly prepared for custom values #1
Changes from all commits
046bd60
3c1dc57
54ea226
e65a377
3491f86
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,16 +27,14 @@ static uint16_t autoshift_lastkey = KC_NO; | |
static struct { | ||
// Whether autoshift is enabled. | ||
bool enabled : 1; | ||
// Whether the last autoshifted key was released after the timeout. This | ||
// Whether the last auto-shifted key was released after the timeout. This | ||
// is used to replicate the last key for a tap-then-hold. | ||
bool lastshifted : 1; | ||
// Whether an auto-shiftable key is currently being pressed. | ||
// Whether an auto-shiftable key has been pressed but not processed. | ||
bool in_progress : 1; | ||
// Whether the auto-shifted keypress has been registered. | ||
bool registered : 1; | ||
// Whether autoshift is currently "holding" the shift key. | ||
bool holding_shift : 1; | ||
} autoshift_flags = {true, false, false, false, false}; | ||
} autoshift_flags = {true, false, false, false}; | ||
|
||
void autoshift_timer_report(void) { | ||
char display[8]; | ||
|
@@ -46,30 +44,6 @@ void autoshift_timer_report(void) { | |
send_string((const char *)display); | ||
} | ||
|
||
/** \brief Resets the autoshift state */ | ||
static void autoshift_flush(uint16_t now) { | ||
if (autoshift_flags.in_progress && !autoshift_flags.registered) { | ||
// Register the key. | ||
register_code(autoshift_lastkey); | ||
# if TAP_CODE_DELAY > 0 | ||
wait_ms(TAP_CODE_DELAY); | ||
# endif | ||
} | ||
// Roll the autoshift_time forward for detecting tap-and-hold. | ||
autoshift_time = now; | ||
autoshift_flags.in_progress = false; | ||
autoshift_flags.registered = false; | ||
} | ||
|
||
/** \brief Releases the shift key if it was held by auto-shift */ | ||
static void autoshift_flush_shift(void) { | ||
if (autoshift_flags.holding_shift) { | ||
// Release the shift key if it was simulated. | ||
unregister_code(KC_LSFT); | ||
} | ||
autoshift_flags.holding_shift = false; | ||
} | ||
|
||
/** \brief Record the press of an autoshiftable key | ||
* | ||
* \return Whether the record should be further processed. | ||
|
@@ -79,24 +53,35 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { | |
return true; | ||
} | ||
|
||
const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); | ||
autoshift_flush(record->event.time); | ||
|
||
# ifndef AUTO_SHIFT_MODIFIERS | ||
if (get_mods() ^ (autoshift_flags.holding_shift ? MOD_BIT(KC_LSFT) : 0)) { | ||
if (get_mods() & (~MOD_BIT(KC_LSFT))) { | ||
return true; | ||
} | ||
# endif | ||
# ifndef TAPPING_FORCE_HOLD | ||
if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey && !autoshift_flags.lastshifted) { | ||
// Allow a tap-then-hold to hold the unshifted key. | ||
autoshift_lastkey = KC_NO; | ||
return true; | ||
# ifdef AUTO_SHIFT_REPEAT | ||
const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); | ||
# ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
if (!autoshift_flags.lastshifted) { | ||
# endif | ||
if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) { | ||
// Allow a tap-then-hold for keyrepeat. | ||
if (!autoshift_flags.lastshifted) { | ||
register_code(autoshift_lastkey); | ||
} else { | ||
// Simulate pressing the shift key. | ||
add_weak_mods(MOD_BIT(KC_LSFT)); | ||
register_code(autoshift_lastkey); | ||
} | ||
return false; | ||
} | ||
# ifndef AUTO_SHIFT_NO_AUTO_REPEAT | ||
} | ||
# endif | ||
# endif | ||
|
||
// Record the keycode so we can simulate it later. | ||
autoshift_lastkey = keycode; | ||
autoshift_time = record->event.time; | ||
autoshift_flags.in_progress = true; | ||
|
||
# if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING) | ||
|
@@ -107,114 +92,81 @@ static bool autoshift_press(uint16_t keycode, keyrecord_t *record) { | |
|
||
/** \brief Registers an autoshiftable key under the right conditions | ||
* | ||
* If the autoshift delay has elapsed and no shift has already been registered, | ||
* register a shift and the key. | ||
* | ||
* \return True if the timeout had elapsed. | ||
*/ | ||
void autoshift_check_timeout(uint16_t now) { | ||
const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
if (elapsed >= autoshift_timeout) { | ||
// The timeout has expired, so simulate the keypress. | ||
if (!(get_mods() & (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)))) { | ||
// Simulate pressing the shift key. | ||
register_code(KC_LSFT); | ||
autoshift_flags.lastshifted = true; | ||
autoshift_flags.holding_shift = true; | ||
} | ||
register_code(autoshift_lastkey); | ||
autoshift_flags.registered = true; | ||
|
||
# if TAP_CODE_DELAY > 0 | ||
wait_ms(TAP_CODE_DELAY); | ||
# endif | ||
} | ||
} | ||
|
||
/** \brief Registers an autoshiftable key under the right conditions | ||
* | ||
* If the autoshift delay has elapsed and no shift has already been registered, | ||
* register a shift and the key. | ||
* If the autoshift delay has elapsed, register a shift and the key. | ||
* | ||
* If the autoshift key is released before the delay has elapsed, register the | ||
* key without a shift. | ||
* | ||
* If another key is pressed, register the key. | ||
*/ | ||
static void autoshift_check_record(uint16_t keycode, keyrecord_t *record) { | ||
if (!autoshift_flags.in_progress) { | ||
return; | ||
} | ||
static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) { | ||
// Called on key down with KC_NO, auto-shifted key up, and timeout. | ||
if (autoshift_flags.in_progress) { | ||
// Process the auto-shiftable key. | ||
autoshift_flags.in_progress = false; | ||
|
||
// Process the release of the autoshiftable key. | ||
if (keycode == autoshift_lastkey && !record->event.pressed) { | ||
autoshift_flush_shift(); | ||
// Time since the initial press was recorded. | ||
const uint16_t elapsed = TIMER_DIFF_16(record->event.time, autoshift_time); | ||
if (!autoshift_flags.registered && elapsed < autoshift_timeout) { | ||
// Auto-shiftable key is being released before the shift timeout; | ||
// simulate the original press then let the usual processing take | ||
// care of the release. | ||
register_code(keycode); | ||
const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
if (elapsed < autoshift_timeout) { | ||
register_code(autoshift_lastkey); | ||
autoshift_flags.lastshifted = false; | ||
autoshift_flags.registered = true; | ||
# if TAP_CODE_DELAY > 0 | ||
wait_ms(TAP_CODE_DELAY); | ||
} else { | ||
// Simulate pressing the shift key. | ||
add_weak_mods(MOD_BIT(KC_LSFT)); | ||
register_code(autoshift_lastkey); | ||
autoshift_flags.lastshifted = true; | ||
# if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT) | ||
if (matrix_trigger) { | ||
// Prevents release. | ||
return; | ||
} | ||
# endif | ||
} | ||
autoshift_flush(record->event.time); | ||
} else if (record->event.pressed) { | ||
if (keycode == KC_LSFT) { | ||
// If the user presses shift, auto-shift will not hold shift for | ||
// them. | ||
autoshift_flags.holding_shift = false; | ||
} else if (!autoshift_flags.registered) { | ||
// If the key isn't registered yet, it means the timeout hasn't | ||
// elapsed, so register the key without additional shifting. | ||
autoshift_flush(0); | ||
autoshift_lastkey = KC_NO; | ||
} else { | ||
// The key is registered; flush any shift state for the | ||
// non-autoshiftable key. | ||
autoshift_flush_shift(); | ||
|
||
# if TAP_CODE_DELAY > 0 | ||
wait_ms(TAP_CODE_DELAY); | ||
# endif | ||
unregister_code(autoshift_lastkey); | ||
del_weak_mods(MOD_BIT(KC_LSFT)); | ||
} else { | ||
// Release after keyrepeat. | ||
unregister_code(keycode); | ||
if (keycode == autoshift_lastkey) { | ||
// This will only fire when the key was the last auto-shiftable | ||
// pressed. That prevents aaaaBBBB then releasing a from unshifting | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: do you mind putting quotes around the keys here ("releasing a from" is a bit hard to parse eagerly). |
||
// later Bs (if B wasn't auto-shiftable). | ||
del_weak_mods(MOD_BIT(KC_LSFT)); | ||
} | ||
} | ||
send_keyboard_report(); // del_weak_mods doesn't send one. | ||
// Roll the autoshift_time forward for detecting tap-and-hold. | ||
autoshift_time = now; | ||
} | ||
|
||
/** \brief Simulates auto-shifted key presses | ||
/** \brief Simulates auto-shifted key releases when timeout is hit | ||
* | ||
* Can be called from \c matrix_scan_user so that auto-shifted keys are sent | ||
* immediately after the timeout has expired, rather than waiting for the key | ||
* to be released. | ||
*/ | ||
void autoshift_matrix_scan(void) { | ||
if (!autoshift_flags.in_progress || autoshift_flags.registered) { | ||
return; | ||
if (autoshift_flags.in_progress) { | ||
const uint16_t now = timer_read(); | ||
const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time); | ||
if (elapsed >= autoshift_timeout) { | ||
autoshift_end(autoshift_lastkey, now, true); | ||
} | ||
} | ||
|
||
autoshift_check_timeout(timer_read()); | ||
} | ||
|
||
void autoshift_enable(void) { | ||
autoshift_flags.enabled = true; | ||
autoshift_flush_shift(); | ||
autoshift_flush(0); | ||
} | ||
void autoshift_enable(void) { autoshift_flags.enabled = true; } | ||
|
||
void autoshift_disable(void) { | ||
autoshift_flags.enabled = false; | ||
autoshift_flush_shift(); | ||
autoshift_flush(0); | ||
del_weak_mods(MOD_BIT(KC_LSFT)); | ||
} | ||
|
||
void autoshift_toggle(void) { | ||
if (autoshift_flags.enabled) { | ||
autoshift_flags.enabled = false; | ||
autoshift_flush_shift(); | ||
autoshift_flush(0); | ||
} else { | ||
autoshift_flags.enabled = true; | ||
} | ||
autoshift_flags.enabled = !autoshift_flags.enabled; | ||
del_weak_mods(MOD_BIT(KC_LSFT)); | ||
} | ||
|
||
bool get_autoshift_state(void) { return autoshift_flags.enabled; } | ||
|
@@ -225,6 +177,14 @@ void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; } | |
|
||
bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | ||
if (record->event.pressed) { | ||
if (autoshift_flags.in_progress) { | ||
// Evaluate previous key if there is one. Doing this elsewhere is | ||
// more complicated and easier to break. | ||
autoshift_end(KC_NO, record->event.time, false); | ||
IsaacElenbaas marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
// For pressing another key while keyrepeating shifted autoshift. | ||
del_weak_mods(MOD_BIT(KC_LSFT)); | ||
|
||
switch (keycode) { | ||
case KC_ASUP: | ||
autoshift_timeout += 5; | ||
|
@@ -247,26 +207,28 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) { | |
case KC_ASOFF: | ||
autoshift_disable(); | ||
return true; | ||
} | ||
} | ||
|
||
switch (keycode) { | ||
# ifndef NO_AUTO_SHIFT_ALPHA | ||
case KC_A ... KC_Z: | ||
case KC_A ... KC_Z: | ||
# endif | ||
# ifndef NO_AUTO_SHIFT_NUMERIC | ||
case KC_1 ... KC_0: | ||
case KC_1 ... KC_0: | ||
# endif | ||
# ifndef NO_AUTO_SHIFT_SPECIAL | ||
case KC_TAB: | ||
case KC_MINUS ... KC_SLASH: | ||
case KC_NONUS_BSLASH: | ||
case KC_TAB: | ||
case KC_MINUS ... KC_SLASH: | ||
case KC_NONUS_BSLASH: | ||
# endif | ||
if (record->event.pressed) { | ||
return autoshift_press(keycode, record); | ||
|
||
default: | ||
break; | ||
} | ||
} else { | ||
autoshift_end(keycode, record->event.time, false); | ||
return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would it take to rewrite this so that we could return true here (at least for the non-custom case)? I tried to avoid eating records since the behaviour becomes less transparent to things downstream (like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically just not mergng this. It's near impossible to return true and still have control of keyrepeat to make this not a breaking change, and this refactor relies heavily on the assumption that it will be the one pressing and releasing keys (as I was preparing for custom ones). Your original pull is simpler if you want to go with only-keyrepeat, though I would probably submit another cleanup pull to make it handle shift more like this. IMO that is more of a QMK-wide issue. We need a way to let other processes know that a key was pressed but that it's been handled and they shouldn't press anything, avoiding |
||
} | ||
} | ||
|
||
autoshift_check_record(keycode, record); | ||
return true; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good if we could return true here rather than registering the key ourselves. Though you'd miss updating autoshift_time below if you returned directly.