mirror of
https://github.com/qmk/qmk_firmware
synced 2024-11-17 17:35:30 +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
|
||||
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)
|
||||
SRC += $(patsubst $(QUANTUM_PATH)/%,%,$(SERIAL_SRC))
|
||||
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_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_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)
|
||||
* [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
|
||||
process_printer(keycode, record) &&
|
||||
#endif
|
||||
#ifdef AUTO_SHIFT_ENABLE
|
||||
process_auto_shift(keycode, record) &&
|
||||
#endif
|
||||
#ifdef UNICODEMAP_ENABLE
|
||||
process_unicode_map(keycode, record) &&
|
||||
#endif
|
||||
|
|
|
@ -95,6 +95,10 @@ extern uint32_t default_layer_state;
|
|||
#include "process_printer.h"
|
||||
#endif
|
||||
|
||||
#ifdef AUTO_SHIFT_ENABLE
|
||||
#include "process_auto_shift.h"
|
||||
#endif
|
||||
|
||||
#ifdef COMBO_ENABLE
|
||||
#include "process_combo.h"
|
||||
#endif
|
||||
|
|
|
@ -121,6 +121,11 @@ enum quantum_keycodes {
|
|||
KC_LEAD,
|
||||
#endif
|
||||
|
||||
// Auto Shift setup
|
||||
KC_ASUP,
|
||||
KC_ASDN,
|
||||
KC_ASRP,
|
||||
|
||||
// Audio on/off/toggle
|
||||
AU_ON,
|
||||
AU_OFF,
|
||||
|
|
Loading…
Reference in a new issue