mirror of
				https://github.com/mfulz/qmk_firmware.git
				synced 2025-10-30 21:02:32 +01:00 
			
		
		
		
	Added Auto Shift, tap key = normal, hold key = shifted state.
This commit is contained in:
		
							parent
							
								
									87021371e6
								
							
						
					
					
						commit
						abba393f57
					
				| @ -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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Jeremy Cowgar
						Jeremy Cowgar