summaryrefslogtreecommitdiff
path: root/docs/feature_auto_shift.md
blob: 99b0ca3c8a3c09ae5fc16e31a3190b9f43d92ad2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
# 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. Voilà! No shift key needed!

## Why Auto Shift?

Many people suffer from various forms of RSI. A common cause is stretching your
fingers repetitively long distances. For us on the keyboard, the pinky does that
all too often when reaching for the shift key. Auto Shift looks to alleviate 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 for 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 if you
have not released the key after the `AUTO_SHIFT_TIMEOUT` period, then a shifted
version of the key is emitted. If the time is less than the `AUTO_SHIFT_TIMEOUT`
time, or you press another key, then the normal state is emitted.

If `AUTO_SHIFT_REPEAT` is defined, there is keyrepeat support. Holding the key
down will repeat the shifted key, though this can be disabled with
`AUTO_SHIFT_NO_AUTO_REPEAT`. If you want to repeat the normal key, then tap it
once then immediately (within `TAPPING_TERM`) hold it down again (this works
with the shifted value as well if auto-repeat is disabled).

There are also the `get_auto_shift_repeat` and `get_auto_shift_no_auto_repeat`
functions for more granular control. Neither will have an effect unless
`AUTO_SHIFT_REPEAT_PER_KEY` or `AUTO_SHIFT_NO_AUTO_REPEAT_PER_KEY` respectively
are defined.

## Are There Limitations to Auto Shift?

Yes, unfortunately.

1. You will have characters that are shifted when 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 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.
2. Additionally, with keyrepeat the desired shift state can get mixed up. It will
   always 'belong' to the last key pressed. For example, keyrepeating a capital
   and then tapping something lowercase (whether or not it's an Auto Shift key)
   will result in the capital's *key* still being held, but shift not.
3. Auto Shift does not apply to Tap Hold keys. For automatic shifting of Tap Hold
   keys see [Retro Shift](#retro-shift).

## 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!

## Modifiers

By default, 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.

You can re-enable Auto Shift for modifiers by adding a define to your `config.h`

```c
#define AUTO_SHIFT_MODIFIERS
```

In which case, Ctrl+A held past the `AUTO_SHIFT_TIMEOUT` will be sent as Ctrl+Shift+A


## 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

```c
#pragma once

#define AUTO_SHIFT_TIMEOUT 150
#define NO_AUTO_SHIFT_SPECIAL
```

### 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. However, 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 the shortest 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
occasion. 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.

?> Auto Shift has three special keys that can help you get this value right very quick. See "Auto Shift Setup" for more details!

For more granular control of this feature, you can add the following to your `config.h`:

```c
#define AUTO_SHIFT_TIMEOUT_PER_KEY
```

You can then add the following function to your keymap:

```c
uint16_t get_autoshift_timeout(uint16_t keycode, keyrecord_t *record) {
    switch(keycode) {
        case AUTO_SHIFT_NUMERIC:
            return 2 * get_generic_autoshift_timeout();
        case AUTO_SHIFT_SPECIAL:
            return get_generic_autoshift_timeout() + 50;
        case AUTO_SHIFT_ALPHA:
        default:
            return get_generic_autoshift_timeout();
    }
}
```

Note that you cannot override individual keys that are in one of those groups
if you are using them; trying to add a case for `KC_A` in the above example will
not compile as `AUTO_SHIFT_ALPHA` is there. A possible solution is a second switch
above to handle individual keys with no default case and only referencing the
groups in the below fallback switch.

### 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.

### Auto Shift Per Key

There are functions that allows you to determine which keys shold be autoshifted, much like the tap-hold keys.

The first of these, used to simply add a key to Auto Shift, is `get_custom_auto_shifted_key`:

```c
bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record) {
    switch(keycode) {
        case KC_DOT:
            return true;
        default:
            return false;
    }
}
```

For more granular control, there is `get_auto_shifted_key`. The default function looks like this:

```c
bool get_auto_shifted_key(uint16_t keycode, keyrecord_t *record) {
    switch (keycode) {
#    ifndef NO_AUTO_SHIFT_ALPHA
        case KC_A ... KC_Z:
#    endif
#    ifndef NO_AUTO_SHIFT_NUMERIC
        case KC_1 ... KC_0:
#    endif
#    ifndef NO_AUTO_SHIFT_SPECIAL
        case KC_TAB:
        case KC_MINUS ... KC_SLASH:
        case KC_NONUS_BACKSLASH:
#    endif
            return true;
    }
    return get_custom_auto_shifted_key(keycode, record);
}
```

This functionality is enabled by default, and does not need a define.

### AUTO_SHIFT_REPEAT (simple define)

Enables keyrepeat.

### AUTO_SHIFT_NO_AUTO_REPEAT (simple define)

Disables automatically keyrepeating when `AUTO_SHIFT_TIMEOUT` is exceeded.

## Custom Shifted Values

Especially on small keyboards, the default shifted value for many keys is not
optimal. To provide more customizability, there are two user-definable
functions, `autoshift_press/release_user`. These register or unregister the
correct value for the passed key. Below is an example adding period to Auto
Shift and making its shifted value exclamation point. Make sure to use weak
mods - setting real would make any keys following it use their shifted values
as if you were holding the key. Clearing of modifiers is handled by Auto Shift,
and the OS-sent shift value if keyrepeating multiple keys is always that of
the last key pressed (whether or not it's an Auto Shift key).

You can also have non-shifted keys for the shifted values (or even no shifted
value), just don't set a shift modifier!

```c
bool get_custom_auto_shifted_key(uint16_t keycode, keyrecord_t *record) {
    switch(keycode) {
        case KC_DOT:
            return true;
        default:
            return false;
    }
}

void autoshift_press_user(uint16_t keycode, bool shifted, keyrecord_t *record) {
    switch(keycode) {
        case KC_DOT:
            register_code16((!shifted) ? KC_DOT : KC_EXLM);
            break;
        default:
            if (shifted) {
                add_weak_mods(MOD_BIT(KC_LSFT));
            }
            // & 0xFF gets the Tap key for Tap Holds, required when using Retro Shift
            register_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode);
    }
}

void autoshift_release_user(uint16_t keycode, bool shifted, keyrecord_t *record) {
    switch(keycode) {
        case KC_DOT:
            unregister_code16((!shifted) ? KC_DOT : KC_EXLM);
            break;
        default:
            // & 0xFF gets the Tap key for Tap Holds, required when using Retro Shift
            // The IS_RETRO check isn't really necessary here, always using
            // keycode & 0xFF would be fine.
            unregister_code16((IS_RETRO(keycode)) ? keycode & 0xFF : keycode);
    }
}
```

## Retro Shift

Holding and releasing a Tap Hold key without pressing another key will ordinarily
result in only the hold. With `retro shift` enabled this action will instead
produce a shifted version of the tap keycode on release.

It does not require [Retro Tapping](tap_hold.md#retro-tapping) to be enabled, and
if both are enabled the state of `retro tapping` will only apply if the tap keycode
is not matched by Auto Shift. `RETRO_TAPPING_PER_KEY` and its corresponding
function, however, are checked before `retro shift` is applied.

To enable `retro shift`, add the following to your `config.h`:

```c
#define RETRO_SHIFT
```

If `RETRO_SHIFT` is defined to a value, hold times greater than that value will
not produce a tap on release for Mod Taps, and instead triggers the hold action.
This enables modifiers to be held for combining with mouse clicks without
generating taps on release. For example:

```c
#define RETRO_SHIFT 500
```

This value (if set) must be greater than one's `TAPPING_TERM`, as the key press
must be designated as a 'hold' by `process_tapping` before we send the modifier.
There is no such limitation in regards to `AUTO_SHIFT_TIMEOUT` for normal keys.

### Retro Shift and Tap Hold Configurations

Tap Hold Configurations work a little differently when using Retro Shift.
Referencing `TAPPING_TERM` makes little sense, as holding longer would result in
shifting one of the keys.

`IGNORE_MOD_TAP_INTERRUPT` changes *only* rolling from a mod tap (releasing it
first), sending both keys instead of the modifier on the second. Its effects on
nested presses are ignored.

As nested taps were changed to act as though `PERMISSIVE_HOLD` is set unless only
`IGNORE_MOD_TAP_INTERRUPT` is (outside of Retro Shift), and Retro Shift ignores
`IGNORE_MOD_TAP_INTERRUPT`, `PERMISSIVE_HOLD` has no effect on Mod Taps.

Nested taps will *always* act as though the `TAPPING_TERM` was exceeded for both
Mod and Layer Tap keys.

## Using Auto Shift Setup

This will enable you to define three keys temporarily 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        |
| KC_ASON  | Turns on the Auto Shift Function                    |
| KC_ASOFF | Turns off the Auto Shift Function                   |
| KC_ASTG  | Toggles the state of the Auto Shift feature         |

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. Add `AUTO_SHIFT_NO_SETUP` to 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 playing 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.