3232 */
3333
3434#ifndef DEFAULT_XCASE_SEPARATOR
35- # define DEFAULT_XCASE_SEPARATOR KC_UNDS
35+ #define DEFAULT_XCASE_SEPARATOR KC_UNDS
3636#endif
3737
38- #define IS_OSM (keycode ) (keycode >= QK_ONE_SHOT_MOD && keycode <= QK_ONE_SHOT_MOD_MAX)
38+ #ifndef DEFAULT_DELIMITERS_TERMINATE_COUNT
39+ #define DEFAULT_DELIMITERS_TERMINATE_COUNT 2
40+ #endif
3941
40- // enum for the xcase states
41- enum xcase_state {
42- XCASE_OFF = 0 , // xcase is off
43- XCASE_ON , // xcase is actively on
44- XCASE_WAIT , // xcase is waiting for the delimiter input
42+ enum xcase_state
43+ {
44+ XCASE_OFF = 0 , // xcase is off
45+ XCASE_ON , // xcase is actively on
46+ XCASE_WAIT , // xcase is waiting for the delimiter input
4547};
4648
47- // bool to keep track of the caps word state
48- static bool caps_word_on = false;
49-
5049// enum to keep track of the xcase state
5150static enum xcase_state xcase_state = XCASE_OFF ;
5251// the keycode of the xcase delimiter
5352static uint16_t xcase_delimiter ;
5453// the number of keys to the last delimiter
5554static int8_t distance_to_last_delim = -1 ;
56-
57- // Check whether caps word is on
58- bool caps_word_enabled (void ) { return caps_word_on ; }
59-
60- // Enable caps word
61- void enable_caps_word (void ) {
62- caps_word_on = true;
63- #ifndef CAPSWORD_USE_SHIFT
64- if (!host_keyboard_led_state ().caps_lock ) {
65- tap_code (KC_CAPS );
66- }
67- #endif
68- }
69-
70- // Disable caps word
71- void disable_caps_word (void ) {
72- caps_word_on = false;
73- #ifndef CAPSWORD_USE_SHIFT
74- if (host_keyboard_led_state ().caps_lock ) {
75- tap_code (KC_CAPS );
76- }
77- #else
78- unregister_mods (MOD_LSFT );
79- #endif
80- }
81-
82- // Toggle caps word
83- void toggle_caps_word (void ) {
84- if (caps_word_on ) {
85- disable_caps_word ();
86- } else {
87- enable_caps_word ();
88- }
89- }
55+ // the number of delimiters in a row
56+ static int8_t delimiters_count = 0 ;
9057
9158// Get xcase state
92- enum xcase_state get_xcase_state (void ) { return xcase_state ; }
59+ enum xcase_state get_xcase_state (void )
60+ {
61+ return xcase_state ;
62+ }
9363
9464// Enable xcase and pickup the next keystroke as the delimiter
95- void enable_xcase (void ) { xcase_state = XCASE_WAIT ; }
65+ void enable_xcase (void )
66+ {
67+ xcase_state = XCASE_WAIT ;
68+ }
9669
9770// Enable xcase with the specified delimiter
98- void enable_xcase_with (uint16_t delimiter ) {
99- xcase_state = XCASE_ON ;
100- xcase_delimiter = delimiter ;
71+ void enable_xcase_with (uint16_t delimiter )
72+ {
73+ xcase_state = XCASE_ON ;
74+ xcase_delimiter = delimiter ;
10175 distance_to_last_delim = -1 ;
76+ delimiters_count = 0 ;
10277}
10378
10479// Disable xcase
105- void disable_xcase (void ) { xcase_state = XCASE_OFF ; }
80+ void disable_xcase (void )
81+ {
82+ xcase_state = XCASE_OFF ;
83+ }
10684
10785// Place the current xcase delimiter
108- static void place_delimiter (void ) {
109- if (IS_OSM (xcase_delimiter )) {
86+ static void place_delimiter (void )
87+ {
88+ if (IS_QK_ONE_SHOT_MOD (xcase_delimiter ))
89+ {
11090 // apparently set_oneshot_mods() is dumb and doesn't deal with handedness for you
11191 uint8_t mods = xcase_delimiter & 0x10 ? (xcase_delimiter & 0x0F ) << 4 : xcase_delimiter & 0xFF ;
112- set_oneshot_mods (mods );
113- } else {
92+ set_oneshot_mods (QK_ONE_SHOT_MOD_GET_MODS (mods ));
93+ }
94+ else
95+ {
11496 tap_code16 (xcase_delimiter );
11597 }
11698}
11799
118100// Removes a delimiter, used for double tap space exit
119- static void remove_delimiter (void ) {
120- if (IS_OSM (xcase_delimiter )) {
101+ static void remove_delimiter (void )
102+ {
103+ if (IS_QK_ONE_SHOT_MOD (xcase_delimiter ))
104+ {
121105 clear_oneshot_mods ();
122- } else {
123- tap_code (KC_BSPC );
106+ }
107+ else
108+ {
109+ for (int8_t i = 0 ; i < DEFAULT_DELIMITERS_TERMINATE_COUNT - 1 ; i ++ )
110+ {
111+ tap_code (KC_BSPC );
112+ }
124113 }
125114}
126115
127116// overrideable function to determine whether the case mode should stop
128- __attribute__((weak )) bool terminate_case_modes (uint16_t keycode , const keyrecord_t * record ) {
129- switch (keycode ) {
130- // Keycodes to ignore (don't disable caps word)
131- case KC_A ... KC_Z :
132- case KC_1 ... KC_0 :
133- case KC_MINS :
134- case KC_UNDS :
135- case KC_BSPC :
136- // Used for triggering one-shot shift
137- case KC_LSFT :
138- // If mod chording other than shift, disable the mods
139- if (record -> event .pressed &&
140- // Some mods are pressed
141- get_mods () != 0 &&
142- // Neither shift mod is pressed
143- (get_mods () & MOD_MASK_SHIFT ) == 0 ) {
144- return true;
145- }
146- break ;
147- default :
148- if (record -> event .pressed ) {
149- return true;
150- }
151- break ;
117+ __attribute__((weak )) bool terminate_case_modes (uint16_t keycode , const keyrecord_t * record )
118+ {
119+ switch (keycode )
120+ {
121+ // Keycodes to ignore (don't disable caps word)
122+ case KC_A ... KC_Z :
123+ case KC_1 ... KC_0 :
124+ case KC_MINS :
125+ case KC_UNDS :
126+ case KC_BSPC :
127+ // Used for triggering one-shot shift
128+ case KC_LSFT :
129+ // If mod chording other than shift and/or alt, disable the mods
130+ if (record -> event .pressed &&
131+ // Ctrl or Gui is pressed
132+ get_mods () & MOD_MASK_CG )
133+ {
134+ return true;
135+ }
136+ break ;
137+ default :
138+ if (record -> event .pressed )
139+ {
140+ return true;
141+ }
142+ break ;
152143 }
153144 return false;
154145}
155146
156147/* overrideable function to determine whether to use the default separator on
157148 * first keypress when waiting for the separator. */
158- __attribute__((weak )) bool use_default_xcase_separator (uint16_t keycode , const keyrecord_t * record ) {
149+ __attribute__((weak )) bool use_default_xcase_separator (uint16_t keycode , const keyrecord_t * record )
150+ {
159151 // for example:
160152 /* switch (keycode) { */
161153 /* case KC_A ... KC_Z: */
@@ -165,34 +157,49 @@ __attribute__((weak)) bool use_default_xcase_separator(uint16_t keycode, const k
165157 return false;
166158}
167159
168- bool process_case_modes (uint16_t keycode , const keyrecord_t * record ) {
169- if (caps_word_on || xcase_state ) {
170- if ((QK_MOD_TAP <= keycode && keycode <= QK_MOD_TAP_MAX ) || (QK_LAYER_TAP <= keycode && keycode <= QK_LAYER_TAP_MAX )) {
160+ bool process_case_modes (uint16_t keycode , const keyrecord_t * record )
161+ {
162+ if (xcase_state )
163+ {
164+ if ((QK_MOD_TAP <= keycode && keycode <= QK_MOD_TAP_MAX ) || (QK_LAYER_TAP <= keycode && keycode <= QK_LAYER_TAP_MAX ))
165+ {
171166 // Earlier return if this has not been considered tapped yet
172- if (record -> tap .count == 0 ) return true;
167+ if (record -> tap .count == 0 )
168+ return true;
173169 keycode = keycode & 0xFF ;
174170 }
175171
176- if (keycode >= QK_LAYER_TAP && keycode <= QK_ONE_SHOT_LAYER_MAX ) {
172+ if (keycode >= QK_LAYER_TAP && keycode <= QK_ONE_SHOT_LAYER_MAX )
173+ {
177174 // let special keys and normal modifiers go through
178175 return true;
179176 }
180177
181- if (xcase_state == XCASE_WAIT ) {
178+ if (xcase_state == XCASE_WAIT )
179+ {
182180 // grab the next input to be the delimiter
183- if (use_default_xcase_separator (keycode , record )) {
181+ if (use_default_xcase_separator (keycode , record ))
182+ {
184183 enable_xcase_with (DEFAULT_XCASE_SEPARATOR );
185- } else if (record -> event .pressed ) {
184+ }
185+ else if (record -> event .pressed )
186+ {
186187 // factor in mods
187- if (get_mods () & MOD_MASK_SHIFT ) {
188+ if (get_mods () & MOD_MASK_SHIFT )
189+ {
188190 keycode = LSFT (keycode );
189- } else if (get_mods () & MOD_BIT (KC_RALT )) {
191+ }
192+ else if (get_mods () & MOD_BIT (KC_RALT ))
193+ {
190194 keycode = RALT (keycode );
191195 }
192196 enable_xcase_with (keycode );
193197 return false;
194- } else {
195- if (IS_OSM (keycode )) {
198+ }
199+ else
200+ {
201+ if (IS_QK_ONE_SHOT_MOD (keycode ))
202+ {
196203 // this catches the OSM release if no other key was pressed
197204 set_oneshot_mods (0 );
198205 enable_xcase_with (keycode );
@@ -203,52 +210,61 @@ bool process_case_modes(uint16_t keycode, const keyrecord_t *record) {
203210 }
204211 }
205212
206- if (record -> event .pressed ) {
213+ if (record -> event .pressed )
214+ {
207215 // handle xcase mode
208- if (xcase_state == XCASE_ON ) {
216+ if (xcase_state == XCASE_ON )
217+ {
209218 // place the delimiter if space is tapped
210- if (keycode == KC_SPACE ) {
211- if (distance_to_last_delim != 0 ) {
219+ if (keycode == KC_SPACE )
220+ {
221+ delimiters_count ++ ;
222+ if (delimiters_count < DEFAULT_DELIMITERS_TERMINATE_COUNT )
223+ {
212224 place_delimiter ();
213225 distance_to_last_delim = 0 ;
214226 return false;
215227 }
228+
216229 // remove the delimiter and disable modes
217- else {
230+ else
231+ {
218232 remove_delimiter ();
219233 disable_xcase ();
220- disable_caps_word ();
234+ caps_word_off ();
221235 return true;
222236 }
223237 }
224238 // decrement distance to delimiter on back space
225- else if (keycode == KC_BSPC ) {
239+ else if (keycode == KC_BSPC )
240+ {
226241 -- distance_to_last_delim ;
242+ if (delimiters_count > 0 )
243+ {
244+ -- delimiters_count ;
245+ }
227246 }
228247 // don't increment distance to last delim if negative
229- else if (distance_to_last_delim >= 0 ) {
248+ else if (distance_to_last_delim >= 0 )
249+ {
230250 // puts back a one shot delimiter if you we're back to the delimiter pos
231- if (distance_to_last_delim == 0 && (IS_OSM (xcase_delimiter ))) {
251+ if (distance_to_last_delim == 0 && (IS_QK_ONE_SHOT_MOD (xcase_delimiter )))
252+ {
232253 place_delimiter ();
233254 }
234255 ++ distance_to_last_delim ;
256+ delimiters_count = 0 ;
235257 }
236258
237- } // end XCASE_ON
259+ } // end XCASE_ON
238260
239261 // check if the case modes have been terminated
240- if (terminate_case_modes (keycode , record )) {
241- disable_caps_word ();
262+ if (terminate_case_modes (keycode , record ))
263+ {
264+ caps_word_off ();
242265 disable_xcase ();
243266 }
244- #ifdef CAPSWORD_USE_SHIFT
245- else if (caps_word_on && keycode >= KC_A && keycode <= KC_Z ) {
246- tap_code16 (LSFT (keycode ));
247- return false;
248- }
249- #endif
250-
251- } // end if event.pressed
267+ } // end if event.pressed
252268
253269 return true;
254270 }
0 commit comments