Skip to content

Commit

Permalink
Added Auto Shift, tap key = normal, hold key = shifted state.
Browse files Browse the repository at this point in the history
  • Loading branch information
jcowgar authored and jackhumbert committed Sep 18, 2017
1 parent 8702137 commit abba393
Show file tree
Hide file tree
Showing 8 changed files with 375 additions and 0 deletions.
5 changes: 5 additions & 0 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
161 changes: 161 additions & 0 deletions docs/feature_auto_shift.md
Original file line number Diff line number Diff line change
@@ -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.
1 change: 1 addition & 0 deletions docs/understanding_qmk.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
168 changes: 168 additions & 0 deletions quantum/process_keycode/process_auto_shift.c
Original file line number Diff line number Diff line change
@@ -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 changes: 28 additions & 0 deletions quantum/process_keycode/process_auto_shift.h
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions quantum/quantum.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit abba393

Please sign in to comment.