mirror of
https://github.com/openstenoproject/qmk
synced 2024-11-22 08:24:41 +00:00
Added Auto Shift, tap key = normal, hold key = shifted state.
This commit is contained in:
parent
87021371e6
commit
abba393f57
8 changed files with 375 additions and 0 deletions
|
@ -119,6 +119,11 @@ ifeq ($(strip $(PRINTING_ENABLE)), yes)
|
||||||
SRC += $(TMK_DIR)/protocol/serial_uart.c
|
SRC += $(TMK_DIR)/protocol/serial_uart.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
|
||||||
|
OPT_DEFS += -DAUTO_SHIFT_ENABLE
|
||||||
|
SRC += $(QUANTUM_DIR)/process_keycode/process_auto_shift.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
|
ifeq ($(strip $(SERIAL_LINK_ENABLE)), yes)
|
||||||
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
|
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
|
||||||
OPT_DEFS += $(SERIAL_DEFS)
|
OPT_DEFS += $(SERIAL_DEFS)
|
||||||
|
|
161
docs/feature_auto_shift.md
Normal file
161
docs/feature_auto_shift.md
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
# Auto Shift: Why do we need a shift key?
|
||||||
|
|
||||||
|
Tap a key and you get its character. Tap a key, but hold it *slightly* longer
|
||||||
|
and you get its shifted state. Viola! No shift key needeed!
|
||||||
|
|
||||||
|
## Why Auto Shift?
|
||||||
|
|
||||||
|
Many people suffer from various forms of RSI. A common cause is stretching your
|
||||||
|
fingers repeitively long distances. For us on the keyboard, the pinky does that
|
||||||
|
all too often when reaching for the shift key. Auto Shift looks to aliviate that
|
||||||
|
problem.
|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
|
||||||
|
When you tap a key, it stays depressed for a short period of time before it is
|
||||||
|
then released. This depressed time is a different length everyone. Auto Shift
|
||||||
|
defines a constant `AUTO_SHIFT_TIMEOUT` which is typically set to twice your
|
||||||
|
normal pressed state time. When you press a key, a timer starts and then stops
|
||||||
|
when you release the key. If the time depressed is greater than or equal to the
|
||||||
|
`AUTO_SHIFT_TIMEOUT` then a shifted version of the key is emitted. If the time
|
||||||
|
is less than the `AUTO_SHIFT_TIMEOUT` time, then the normal state is emitted.
|
||||||
|
|
||||||
|
## Are there limitations to Auto Shift?
|
||||||
|
|
||||||
|
Yes, unfortunately.
|
||||||
|
|
||||||
|
1. Key repeat will cease to work. For example, before if you wanted 20 'a'
|
||||||
|
characters, you could press and hold the 'a' key for a second or two. This no
|
||||||
|
longer works with Auto Shift because it is timing your depressed time instead
|
||||||
|
of emitting a depressed key state to your operating system.
|
||||||
|
2. Auto Shift is disabled for any key press that is accompanied by one or more
|
||||||
|
modifiers. Thus, Ctrl+A that you hold for a really long time is not the same
|
||||||
|
as Ctrl+Shift+A.
|
||||||
|
3. You will have characters that are shifted you did not intend on shifting, and
|
||||||
|
other characters you wanted shifted, but were not. This simply comes down to
|
||||||
|
practice. As we get in a hurry, we think we might have hit the key long enough
|
||||||
|
for a shifted version, but we did not. On the other hand, we may think we are
|
||||||
|
tapping the keys, but really we have held it for a little longer than
|
||||||
|
anticipated.
|
||||||
|
|
||||||
|
## How do I enable Auto Shift?
|
||||||
|
|
||||||
|
Add to your `rules.mk` in the keymap folder:
|
||||||
|
|
||||||
|
AUTO_SHIFT_ENABLE = YES
|
||||||
|
|
||||||
|
If no `rules.mk` exists, you can create one.
|
||||||
|
|
||||||
|
Then compile and install your new firmware with Auto Key enabled! That's it!
|
||||||
|
|
||||||
|
## Configuring Auto Shift
|
||||||
|
|
||||||
|
If desired, there is some configuration that can be done to change the
|
||||||
|
behavior of Auto Shift. This is done by setting various variables the
|
||||||
|
`config.h` file located in your keymap folder.
|
||||||
|
|
||||||
|
If no `config.h` file exists, you can create one. A sample is
|
||||||
|
|
||||||
|
#ifndef CONFIG_USER_H
|
||||||
|
#define CONFIG_USER_H
|
||||||
|
|
||||||
|
#include "../../config.h"
|
||||||
|
|
||||||
|
#define AUTO_SHIFT_TIMEOUT 150
|
||||||
|
#define NO_AUTO_SHIFT_SPECIAL
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
### AUTO_SHIFT_TIMEOUT (value in ms)
|
||||||
|
|
||||||
|
This controls how long you have to hold a key before you get the shifted state.
|
||||||
|
Obviously, this is different for everyone. For the common person a setting of
|
||||||
|
135 to 150 works great but one should start with a value of at least 175, which
|
||||||
|
is the default value. Then work down from there. The idea is to have as short
|
||||||
|
of a time required to get the shifted state without having false positives.
|
||||||
|
|
||||||
|
Play with this value until things are perfect. Many find that all will work well
|
||||||
|
at a given value, but one or two keys will still emit the shifted state on
|
||||||
|
occassion. This is simply due to habit and holding some keys a little longer
|
||||||
|
than others. Once you find this value, work on tapping your problem keys a little
|
||||||
|
quicker than normal and you will be set.
|
||||||
|
|
||||||
|
{% hint style='info' %}
|
||||||
|
Auto Shift has three special keys that can help you get this value right very
|
||||||
|
quick. See "Auto Shift Setup" for more details!
|
||||||
|
{% endhint %}
|
||||||
|
|
||||||
|
### NO_AUTO_SHIFT_SPECIAL (simple define)
|
||||||
|
|
||||||
|
Do not Auto Shift special keys, which include -_, =+, [{, ]}, ;:, '", ,<, .>,
|
||||||
|
and /?
|
||||||
|
|
||||||
|
### NO_AUTO_SHIFT_NUMERIC (simple define)
|
||||||
|
|
||||||
|
Do not Auto Shift numeric keys, zero through nine.
|
||||||
|
|
||||||
|
### NO_AUTO_SHIFT_ALPHA (simple define)
|
||||||
|
|
||||||
|
Do not Auto Shift alpha characters, which include A through Z.
|
||||||
|
|
||||||
|
## Using Auto Shift Setup
|
||||||
|
|
||||||
|
This will enable you to define three keys temporailiy to increase, decrease and report your `AUTO_SHIFT_TIMEOUT`.
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
Map three keys temporarily in your keymap:
|
||||||
|
|
||||||
|
| Key Name | Description |
|
||||||
|
|----------|-----------------------------------------------------|
|
||||||
|
| KC_ASDN | Lower the Auto Shift timeout variable (down) |
|
||||||
|
| KC_ASUP | Raise the Auto Shift timeout variable (up) |
|
||||||
|
| KC_ASRP | Report your current Auto Shift timeout value |
|
||||||
|
|
||||||
|
Compile and upload your new firmware.
|
||||||
|
|
||||||
|
### Use
|
||||||
|
|
||||||
|
It is important to note that during these tests, you should be typing
|
||||||
|
completely normal and with no intention of shifted keys.
|
||||||
|
|
||||||
|
1. Type multiple sentences of alphabetical letters.
|
||||||
|
2. Observe any upper case letters.
|
||||||
|
3. If there are none, press the key you have mapped to `KC_ASDN` to decrease
|
||||||
|
time Auto Shift timeout value and go back to step 1.
|
||||||
|
4. If there are some upper case letters, decide if you need to work on tapping
|
||||||
|
those keys with less down time, or if you need to increase the timeout.
|
||||||
|
5. If you decide to increase the timeout, press the key you have mapped to
|
||||||
|
`KC_ASUP` and go back to step 1.
|
||||||
|
6. Once you are happy with your results, press the key you have mapped to
|
||||||
|
`KC_ASRP`. The keyboard will type by itself the value of your
|
||||||
|
`AUTO_SHIFT_TIMEOUT`.
|
||||||
|
7. Update `AUTO_SHIFT_TIMEOUT` in your `config.h` with the value reported.
|
||||||
|
8. Remove `AUTO_SHIFT_SETUP` from your `config.h`.
|
||||||
|
9. Remove the key bindings `KC_ASDN`, `KC_ASUP` and `KC_ASRP`.
|
||||||
|
10. Compile and upload your new firmware.
|
||||||
|
|
||||||
|
#### An example run
|
||||||
|
|
||||||
|
\'\'\'
|
||||||
|
hello world. my name is john doe. i am a computer programmer playing with
|
||||||
|
keyboards right now.
|
||||||
|
|
||||||
|
[PRESS KC_ASDN quite a few times]
|
||||||
|
|
||||||
|
heLLo woRLd. mY nAMe is JOHn dOE. i AM A compUTeR proGRaMMER PlAYiNG witH
|
||||||
|
KEYboArDS RiGHT NOw.
|
||||||
|
|
||||||
|
[PRESS KC_ASUP a few times]
|
||||||
|
|
||||||
|
hello world. my name is john Doe. i am a computer programmer play with
|
||||||
|
keyboarDs right now.
|
||||||
|
|
||||||
|
[PRESS KC_ASRP]
|
||||||
|
|
||||||
|
115
|
||||||
|
\'\'\'
|
||||||
|
|
||||||
|
The keyboard typed `115` which represents your current `AUTO_SHIFT_TIMEOUT`
|
||||||
|
value. You are now set! Practice on the *D* key a little bit that showed up
|
||||||
|
in the testing and you'll be golden.
|
|
@ -147,6 +147,7 @@ The `process_record()` function itself is deceptively simple, but hidden within
|
||||||
* [`bool process_unicode(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicode.c#L22)
|
* [`bool process_unicode(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicode.c#L22)
|
||||||
* [`bool process_ucis(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_ucis.c#L91)
|
* [`bool process_ucis(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_ucis.c#L91)
|
||||||
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_printer.c#L77)
|
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_printer.c#L77)
|
||||||
|
* [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_auto_shift.c#L47)
|
||||||
* [`bool process_unicode_map(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicodemap.c#L47)
|
* [`bool process_unicode_map(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/master/quantum/process_keycode/process_unicodemap.c#L47)
|
||||||
* [Identify and process quantum specific keycodes](https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum.c#L211)
|
* [Identify and process quantum specific keycodes](https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum.c#L211)
|
||||||
|
|
||||||
|
|
168
quantum/process_keycode/process_auto_shift.c
Normal file
168
quantum/process_keycode/process_auto_shift.c
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
/* Copyright 2017 Jeremy Cowgar
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef AUTO_SHIFT_ENABLE
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "process_auto_shift.h"
|
||||||
|
|
||||||
|
#define TAP(key) \
|
||||||
|
register_code(key); \
|
||||||
|
unregister_code(key)
|
||||||
|
|
||||||
|
#define TAP_WITH_MOD(mod, key) \
|
||||||
|
register_code(mod); \
|
||||||
|
register_code(key); \
|
||||||
|
unregister_code(key); \
|
||||||
|
unregister_code(mod)
|
||||||
|
|
||||||
|
uint16_t autoshift_time = 0;
|
||||||
|
uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
|
||||||
|
uint16_t autoshift_lastkey = KC_NO;
|
||||||
|
|
||||||
|
void autoshift_timer_report(void) {
|
||||||
|
char display[8];
|
||||||
|
|
||||||
|
snprintf(display, 8, "\n%d\n", autoshift_timeout);
|
||||||
|
|
||||||
|
send_string((const char *)display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void autoshift_on(uint16_t keycode) {
|
||||||
|
autoshift_time = timer_read();
|
||||||
|
autoshift_lastkey = keycode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void autoshift_flush(void) {
|
||||||
|
if (autoshift_lastkey != KC_NO) {
|
||||||
|
uint16_t elapsed = timer_elapsed(autoshift_time);
|
||||||
|
|
||||||
|
if (elapsed > autoshift_timeout) {
|
||||||
|
register_code(KC_LSFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
register_code(autoshift_lastkey);
|
||||||
|
unregister_code(autoshift_lastkey);
|
||||||
|
|
||||||
|
if (elapsed > autoshift_timeout) {
|
||||||
|
unregister_code(KC_LSFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
autoshift_time = 0;
|
||||||
|
autoshift_lastkey = KC_NO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
|
||||||
|
static uint8_t any_mod_pressed;
|
||||||
|
|
||||||
|
if (record->event.pressed) {
|
||||||
|
switch (keycode) {
|
||||||
|
case KC_ASUP:
|
||||||
|
autoshift_timeout += 5;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case KC_ASDN:
|
||||||
|
autoshift_timeout -= 5;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case KC_ASRP:
|
||||||
|
autoshift_timer_report();
|
||||||
|
return false;
|
||||||
|
|
||||||
|
#ifndef NO_AUTO_SHIFT_ALPHA
|
||||||
|
case KC_A:
|
||||||
|
case KC_B:
|
||||||
|
case KC_C:
|
||||||
|
case KC_D:
|
||||||
|
case KC_E:
|
||||||
|
case KC_F:
|
||||||
|
case KC_G:
|
||||||
|
case KC_H:
|
||||||
|
case KC_I:
|
||||||
|
case KC_J:
|
||||||
|
case KC_K:
|
||||||
|
case KC_L:
|
||||||
|
case KC_M:
|
||||||
|
case KC_N:
|
||||||
|
case KC_O:
|
||||||
|
case KC_P:
|
||||||
|
case KC_Q:
|
||||||
|
case KC_R:
|
||||||
|
case KC_S:
|
||||||
|
case KC_T:
|
||||||
|
case KC_U:
|
||||||
|
case KC_V:
|
||||||
|
case KC_W:
|
||||||
|
case KC_X:
|
||||||
|
case KC_Y:
|
||||||
|
case KC_Z:
|
||||||
|
#endif
|
||||||
|
#ifndef NO_AUTO_SHIFT_NUMERIC
|
||||||
|
case KC_1:
|
||||||
|
case KC_2:
|
||||||
|
case KC_3:
|
||||||
|
case KC_4:
|
||||||
|
case KC_5:
|
||||||
|
case KC_6:
|
||||||
|
case KC_7:
|
||||||
|
case KC_8:
|
||||||
|
case KC_9:
|
||||||
|
case KC_0:
|
||||||
|
#endif
|
||||||
|
#ifndef NO_AUTO_SHIFT_SPECIAL
|
||||||
|
case KC_TILD:
|
||||||
|
case KC_MINUS:
|
||||||
|
case KC_EQL:
|
||||||
|
case KC_TAB:
|
||||||
|
case KC_LBRC:
|
||||||
|
case KC_RBRC:
|
||||||
|
case KC_BSLS:
|
||||||
|
case KC_SCLN:
|
||||||
|
case KC_QUOT:
|
||||||
|
case KC_COMM:
|
||||||
|
case KC_DOT:
|
||||||
|
case KC_SLSH:
|
||||||
|
#endif
|
||||||
|
autoshift_flush();
|
||||||
|
|
||||||
|
any_mod_pressed = get_mods() & (
|
||||||
|
MOD_BIT(KC_LGUI)|MOD_BIT(KC_RGUI)|
|
||||||
|
MOD_BIT(KC_LALT)|MOD_BIT(KC_RALT)|
|
||||||
|
MOD_BIT(KC_LCTL)|MOD_BIT(KC_RCTL)|
|
||||||
|
MOD_BIT(KC_LSFT)|MOD_BIT(KC_RSFT)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (any_mod_pressed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
autoshift_on(keycode);
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
autoshift_flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
autoshift_flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
28
quantum/process_keycode/process_auto_shift.h
Normal file
28
quantum/process_keycode/process_auto_shift.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* Copyright 2017 Jeremy Cowgar
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PROCESS_AUTO_SHIFT_H
|
||||||
|
#define PROCESS_AUTO_SHIFT_H
|
||||||
|
|
||||||
|
#include "quantum.h"
|
||||||
|
|
||||||
|
#ifndef AUTO_SHIFT_TIMEOUT
|
||||||
|
#define AUTO_SHIFT_TIMEOUT 175
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool process_auto_shift(uint16_t keycode, keyrecord_t *record);
|
||||||
|
|
||||||
|
#endif
|
|
@ -235,6 +235,9 @@ bool process_record_quantum(keyrecord_t *record) {
|
||||||
#ifdef PRINTING_ENABLE
|
#ifdef PRINTING_ENABLE
|
||||||
process_printer(keycode, record) &&
|
process_printer(keycode, record) &&
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef AUTO_SHIFT_ENABLE
|
||||||
|
process_auto_shift(keycode, record) &&
|
||||||
|
#endif
|
||||||
#ifdef UNICODEMAP_ENABLE
|
#ifdef UNICODEMAP_ENABLE
|
||||||
process_unicode_map(keycode, record) &&
|
process_unicode_map(keycode, record) &&
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,6 +95,10 @@ extern uint32_t default_layer_state;
|
||||||
#include "process_printer.h"
|
#include "process_printer.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef AUTO_SHIFT_ENABLE
|
||||||
|
#include "process_auto_shift.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef COMBO_ENABLE
|
#ifdef COMBO_ENABLE
|
||||||
#include "process_combo.h"
|
#include "process_combo.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -121,6 +121,11 @@ enum quantum_keycodes {
|
||||||
KC_LEAD,
|
KC_LEAD,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Auto Shift setup
|
||||||
|
KC_ASUP,
|
||||||
|
KC_ASDN,
|
||||||
|
KC_ASRP,
|
||||||
|
|
||||||
// Audio on/off/toggle
|
// Audio on/off/toggle
|
||||||
AU_ON,
|
AU_ON,
|
||||||
AU_OFF,
|
AU_OFF,
|
||||||
|
|
Loading…
Reference in a new issue