One shot support for swap hands (#8590)

This commits add the SH_OS keycode, which works similarly to one shot
layers:
* while pressed, the keyboard is swapped
* if no keys were pressed while it was pressed, the next key press is
swapped

SH_OS also supports chaining with one shot layers:
OSL(x) + SH_OS + key interprets the key press on the oneshot layer.

The ONESHOT_TIMEOUT setting used by one shot keys and layers is also
used by oneshot swap hands. In the above chaining scenario the timeout
of the oneshot layer is reset when swap hands is activated.

Resolves #2682
master
Zsolt Parragi 2020-05-13 23:36:55 +02:00 committed by GitHub
parent a8a8bf0ff3
commit 805f5cb72b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 1 deletions

View File

@ -28,3 +28,4 @@ Note that the array indices are reversed same as the matrix and the values are o
|`SH_MOFF` |Momentarily turns off swap. | |`SH_MOFF` |Momentarily turns off swap. |
|`SH_TG` |Toggles swap on and off with every key press. | |`SH_TG` |Toggles swap on and off with every key press. |
|`SH_TT` |Toggles with a tap; momentary when held. | |`SH_TT` |Toggles with a tap; momentary when held. |
|`SH_OS` |One shot swap hands: toggles while pressed or until next key press. |

View File

@ -531,6 +531,7 @@ See also: [Swap Hands](feature_swap_hands.md)
|`SH_MOFF` |Momentarily turns off swap. | |`SH_MOFF` |Momentarily turns off swap. |
|`SH_TG` |Toggles swap on and off with every key press. | |`SH_TG` |Toggles swap on and off with every key press. |
|`SH_TT` |Toggles with a tap; momentary when held. | |`SH_TT` |Toggles with a tap; momentary when held. |
|`SH_OS` |One shot swap hands: toggle while pressed or until next key press. |
## Unicode Support :id=unicode-support ## Unicode Support :id=unicode-support

View File

@ -794,6 +794,7 @@ enum quantum_keycodes {
# define SH_T(kc) (QK_SWAP_HANDS | (kc)) # define SH_T(kc) (QK_SWAP_HANDS | (kc))
# define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE) # define SH_TG (QK_SWAP_HANDS | OP_SH_TOGGLE)
# define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE) # define SH_TT (QK_SWAP_HANDS | OP_SH_TAP_TOGGLE)
# define SH_OS (QK_SWAP_HANDS | OP_SH_ONESHOT)
# define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF) # define SH_MON (QK_SWAP_HANDS | OP_SH_ON_OFF)
# define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON) # define SH_MOFF (QK_SWAP_HANDS | OP_SH_OFF_ON)
# define SH_ON (QK_SWAP_HANDS | OP_SH_ON) # define SH_ON (QK_SWAP_HANDS | OP_SH_ON)

View File

@ -98,6 +98,11 @@ void action_exec(keyevent_t event) {
if (has_oneshot_mods_timed_out()) { if (has_oneshot_mods_timed_out()) {
clear_oneshot_mods(); clear_oneshot_mods();
} }
# ifdef SWAP_HANDS_ENABLE
if (has_oneshot_swaphands_timed_out()) {
clear_oneshot_swaphands();
}
# endif
# endif # endif
#endif #endif
@ -165,6 +170,8 @@ void process_record_tap_hint(keyrecord_t *record) {
# ifdef SWAP_HANDS_ENABLE # ifdef SWAP_HANDS_ENABLE
case ACT_SWAP_HANDS: case ACT_SWAP_HANDS:
switch (action.swap.code) { switch (action.swap.code) {
case OP_SH_ONESHOT:
break;
case OP_SH_TAP_TOGGLE: case OP_SH_TAP_TOGGLE:
default: default:
swap_hands = !swap_hands; swap_hands = !swap_hands;
@ -224,7 +231,11 @@ void process_action(keyrecord_t *record, action_t action) {
#ifndef NO_ACTION_ONESHOT #ifndef NO_ACTION_ONESHOT
bool do_release_oneshot = false; bool do_release_oneshot = false;
// notice we only clear the one shot layer if the pressed key is not a modifier. // notice we only clear the one shot layer if the pressed key is not a modifier.
if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)) { if (is_oneshot_layer_active() && event.pressed && !IS_MOD(action.key.code)
# ifdef SWAP_HANDS_ENABLE
&& !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)
# endif
) {
clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED); clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
do_release_oneshot = !is_oneshot_layer_active(); do_release_oneshot = !is_oneshot_layer_active();
} }
@ -593,6 +604,14 @@ void process_action(keyrecord_t *record, action_t action) {
swap_hands = false; swap_hands = false;
} }
break; break;
case OP_SH_ONESHOT:
if (event.pressed) {
set_oneshot_swaphands();
} else {
release_oneshot_swaphands();
}
break;
# ifndef NO_ACTION_TAPPING # ifndef NO_ACTION_TAPPING
case OP_SH_TAP_TOGGLE: case OP_SH_TAP_TOGGLE:
/* tap toggle */ /* tap toggle */
@ -681,6 +700,12 @@ void process_action(keyrecord_t *record, action_t action) {
# endif # endif
#endif #endif
#ifdef SWAP_HANDS_ENABLE
if (event.pressed && !(action.kind.id == ACT_SWAP_HANDS && action.swap.code == OP_SH_ONESHOT)) {
use_oneshot_swaphands();
}
#endif
#ifndef NO_ACTION_ONESHOT #ifndef NO_ACTION_ONESHOT
/* Because we switch layers after a oneshot event, we need to release the /* Because we switch layers after a oneshot event, we need to release the
* key before we leave the layer or no key up event will be generated. * key before we leave the layer or no key up event will be generated.

View File

@ -294,11 +294,13 @@ enum swap_hands_param_tap_op {
OP_SH_OFF_ON, OP_SH_OFF_ON,
OP_SH_OFF, OP_SH_OFF,
OP_SH_ON, OP_SH_ON,
OP_SH_ONESHOT,
}; };
#define ACTION_SWAP_HANDS() ACTION_SWAP_HANDS_ON_OFF() #define ACTION_SWAP_HANDS() ACTION_SWAP_HANDS_ON_OFF()
#define ACTION_SWAP_HANDS_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TOGGLE) #define ACTION_SWAP_HANDS_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TOGGLE)
#define ACTION_SWAP_HANDS_TAP_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TAP_TOGGLE) #define ACTION_SWAP_HANDS_TAP_TOGGLE() ACTION(ACT_SWAP_HANDS, OP_SH_TAP_TOGGLE)
#define ACTION_SWAP_HANDS_ONESHOT() ACTION(ACT_SWAP_HANDS, OP_SH_ONESHOT)
#define ACTION_SWAP_HANDS_TAP_KEY(key) ACTION(ACT_SWAP_HANDS, key) #define ACTION_SWAP_HANDS_TAP_KEY(key) ACTION(ACT_SWAP_HANDS, key)
#define ACTION_SWAP_HANDS_ON_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_ON_OFF) #define ACTION_SWAP_HANDS_ON_OFF() ACTION(ACT_SWAP_HANDS, OP_SH_ON_OFF)
#define ACTION_SWAP_HANDS_OFF_ON() ACTION(ACT_SWAP_HANDS, OP_SH_OFF_ON) #define ACTION_SWAP_HANDS_OFF_ON() ACTION(ACT_SWAP_HANDS, OP_SH_OFF_ON)

View File

@ -83,9 +83,63 @@ static int8_t oneshot_layer_data = 0;
inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; } inline uint8_t get_oneshot_layer(void) { return oneshot_layer_data >> 3; }
inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; } inline uint8_t get_oneshot_layer_state(void) { return oneshot_layer_data & 0b111; }
# ifdef SWAP_HANDS_ENABLE
enum {
SHO_OFF,
SHO_ACTIVE, // Swap hands button was pressed, and we didn't send any swapped keys yet
SHO_PRESSED, // Swap hands button is currently pressed
SHO_USED, // Swap hands button is still pressed, and we already sent swapped keys
} swap_hands_oneshot = SHO_OFF;
# endif
# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0)) # if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
static uint16_t oneshot_layer_time = 0; static uint16_t oneshot_layer_time = 0;
inline bool has_oneshot_layer_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED); } inline bool has_oneshot_layer_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_layer_time) >= ONESHOT_TIMEOUT && !(get_oneshot_layer_state() & ONESHOT_TOGGLED); }
# ifdef SWAP_HANDS_ENABLE
static uint16_t oneshot_swaphands_time = 0;
inline bool has_oneshot_swaphands_timed_out() { return TIMER_DIFF_16(timer_read(), oneshot_swaphands_time) >= ONESHOT_TIMEOUT && !(swap_hands_oneshot >= SHO_PRESSED); }
# endif
# endif
# ifdef SWAP_HANDS_ENABLE
void set_oneshot_swaphands(void) {
swap_hands_oneshot = SHO_PRESSED;
swap_hands = true;
# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
oneshot_swaphands_time = timer_read();
if (oneshot_layer_time != 0) {
oneshot_layer_time = oneshot_swaphands_time;
}
# endif
}
void release_oneshot_swaphands(void) {
if (swap_hands_oneshot == SHO_PRESSED) {
swap_hands_oneshot = SHO_ACTIVE;
}
if (swap_hands_oneshot == SHO_USED) {
clear_oneshot_swaphands();
}
}
void use_oneshot_swaphands(void) {
if (swap_hands_oneshot == SHO_PRESSED) {
swap_hands_oneshot = SHO_USED;
}
if (swap_hands_oneshot == SHO_ACTIVE) {
clear_oneshot_swaphands();
}
}
void clear_oneshot_swaphands(void) {
swap_hands_oneshot = SHO_OFF;
swap_hands = false;
# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
oneshot_swaphands_time = 0;
# endif
}
# endif # endif
/** \brief Set oneshot layer /** \brief Set oneshot layer

View File

@ -77,6 +77,7 @@ void reset_oneshot_layer(void);
bool is_oneshot_layer_active(void); bool is_oneshot_layer_active(void);
uint8_t get_oneshot_layer_state(void); uint8_t get_oneshot_layer_state(void);
bool has_oneshot_layer_timed_out(void); bool has_oneshot_layer_timed_out(void);
bool has_oneshot_swaphands_timed_out(void);
void oneshot_locked_mods_changed_user(uint8_t mods); void oneshot_locked_mods_changed_user(uint8_t mods);
void oneshot_locked_mods_changed_kb(uint8_t mods); void oneshot_locked_mods_changed_kb(uint8_t mods);
@ -88,6 +89,13 @@ void oneshot_layer_changed_kb(uint8_t layer);
/* inspect */ /* inspect */
uint8_t has_anymod(void); uint8_t has_anymod(void);
#ifdef SWAP_HANDS_ENABLE
void set_oneshot_swaphands(void);
void release_oneshot_swaphands(void);
void use_oneshot_swaphands(void);
void clear_oneshot_swaphands(void);
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif