Skip to content
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

Support for custom keys/custom shifted keys in Autoshift #8127

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions docs/feature_auto_shift.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,41 @@ Do not Auto Shift numeric keys, zero through nine.

Do not Auto Shift alpha characters, which include A through Z.

### Custom Keys and Shifted Keycodes
Often, with small keyboards (on which Auto Shift is most common), it is convenient to rearrange the shifted values of symbols due to many not being on the base layer. This lead to the creation of `autoshift_custom_shifts`. It is called when any key is pressed, and used to determine whether a key is included in Auto Shift and/or its shifted value.

Here is an example `keymap.c`:

```c
int16_t autoshift_custom_shifts(uint16_t keycode, keyrecord_t *record) {
switch(keycode) {
case KC_TAB:
case KC_ENT:
case KC_QUOT:
return -1; // adds the key to Auto Shift with its default shifted action
case KC_COMM:
return KC_QUES; // send ? when , is held
case KC_DOT:
return KC_EXLM;
case KC_SLSH:
return KC_BSLASH;
case KC_AMPR:
return KC_PIPE;
case KC_LPRN:
return KC_LBRC;
case KC_RPRN:
return KC_RBRC;
case KC_A:
// note you can override the actions of already enabled keys, and KC_NO is supported
// which allows you to make keys do nothing when held for longer than the timeout
return KC_NO;
}
return -2; // default - not an Auto Shift key
}
```

Returning `-2` indicates that the key press we just processed should continue to be processed as normal (not be included in Auto Shift). `-1` is used to add individual keys to Auto Shift, if there is not a relevant `#define` (or not everything from it is desired, such as `KC_TAB` in the above example). Returning anything else will make that the shifted value for the processed key.

## Using Auto Shift Setup

This will enable you to define three keys temporarily to increase, decrease and report your `AUTO_SHIFT_TIMEOUT`.
Expand Down
85 changes: 53 additions & 32 deletions quantum/process_keycode/process_auto_shift.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@

# include "process_auto_shift.h"

static bool autoshift_enabled = true;
static uint16_t autoshift_time = 0;
static bool autoshift_enabled = true;
static uint16_t autoshift_time = 0;
static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
static uint16_t autoshift_lastkey = KC_NO;
static int16_t autoshift_lastkey = -1; // -1 is what KC_NO was before - 'not currently autoshifting'.
IsaacElenbaas marked this conversation as resolved.
Show resolved Hide resolved
static int16_t autoshift_lastkey_shifted = -2; // set in the top of process_auto_shift.
// process_custom_shifts return values:
// -2 - not a custom autoshift key
// -1 - custom key, use default shifted value
// 0 = KC_NO, allowing for keys to not have an action when held.
// other - the code to send when timeout exceeded.
uint8_t permissive_mods;

__attribute__((weak)) int16_t autoshift_custom_shifts(uint16_t keycode, keyrecord_t *record) { return -2; }

void autoshift_timer_report(void) {
char display[8];
Expand All @@ -33,23 +42,44 @@ void autoshift_timer_report(void) {
send_string((const char *)display);
}

void autoshift_on(uint16_t keycode) {
autoshift_time = timer_read();
bool autoshift_on(uint16_t keycode) {
if (!autoshift_enabled) { return true; }
# ifndef AUTO_SHIFT_MODIFIERS
if (get_mods()) {
return true;
}
# endif
autoshift_time = timer_read();
autoshift_lastkey = keycode;

// We need some extra handling here for OSL edge cases
# if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
# endif
return false;
}

void autoshift_flush(void) {
if (autoshift_lastkey != KC_NO) {
if (autoshift_lastkey != -1) {
uint16_t elapsed = timer_elapsed(autoshift_time);

# ifdef PERMISSIVE_HOLD
IsaacElenbaas marked this conversation as resolved.
Show resolved Hide resolved
uint8_t old_weak_mods = get_weak_mods();
set_weak_mods(permissive_mods);
# endif
if (elapsed > autoshift_timeout) {
tap_code16(LSFT(autoshift_lastkey));
} else {
tap_code(autoshift_lastkey);
tap_code16((autoshift_lastkey_shifted == -1) ? LSFT(autoshift_lastkey) : autoshift_lastkey_shifted);
}
else {
tap_code16(autoshift_lastkey);
}
# ifdef PERMISSIVE_HOLD
IsaacElenbaas marked this conversation as resolved.
Show resolved Hide resolved
set_weak_mods(old_weak_mods);
# endif

autoshift_time = 0;
autoshift_lastkey = KC_NO;
autoshift_time = 0;
autoshift_lastkey = -1;
// no need to reset shifted
}
}

Expand All @@ -75,20 +105,28 @@ uint16_t get_autoshift_timeout(void) { return autoshift_timeout; }
void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }

bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
autoshift_flush();
if (record->event.pressed) {
# ifdef PERMISSIVE_HOLD
IsaacElenbaas marked this conversation as resolved.
Show resolved Hide resolved
permissive_mods = get_weak_mods() | get_mods();
# endif
autoshift_lastkey_shifted = autoshift_custom_shifts(keycode, record);
if (autoshift_lastkey_shifted > -2) {
return autoshift_on(keycode);
}
else {
autoshift_lastkey_shifted = LSFT(keycode);
}
switch (keycode) {
case KC_ASUP:
autoshift_timeout += 5;
return true;

case KC_ASDN:
autoshift_timeout -= 5;
return true;

case KC_ASRP:
autoshift_timer_report();
return true;

case KC_ASTG:
autoshift_toggle();
return true;
Expand All @@ -110,28 +148,11 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
case KC_MINUS ... KC_SLASH:
case KC_NONUS_BSLASH:
# endif
autoshift_flush();
if (!autoshift_enabled) return true;

# ifndef AUTO_SHIFT_MODIFIERS
if (get_mods()) {
return true;
}
# endif
autoshift_on(keycode);

// We need some extra handling here for OSL edge cases
# if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
# endif
return false;
return autoshift_on(keycode);

default:
autoshift_flush();
return true;
}
} else {
autoshift_flush();
}

return true;
Expand Down