Skip to content

Commit 9ed9a89

Browse files
committed
Moves to qmk caps word and update xcase code
1 parent 4b93404 commit 9ed9a89

4 files changed

Lines changed: 137 additions & 117 deletions

File tree

kyria/qmk/casemodes.h

Lines changed: 131 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -32,130 +32,122 @@
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
5150
static enum xcase_state xcase_state = XCASE_OFF;
5251
// the keycode of the xcase delimiter
5352
static uint16_t xcase_delimiter;
5453
// the number of keys to the last delimiter
5554
static 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
}

kyria/qmk/config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@
4545
// Make sure keycodes tap duration is long enough to be registered
4646
#define TAP_CODE_DELAY 25
4747

48+
// Caps Word
49+
#define CAPS_WORD_INVERT_ON_SHIFT
50+
4851
#ifdef COMBO_ENABLE
4952
#define COMBO_TERM 100
5053
#define COMBO_STRICT_TIMER

kyria/qmk/keymap.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record)
227227
}
228228
else
229229
{
230-
enable_caps_word();
230+
caps_word_on();
231231
}
232232
}
233233
return false;
@@ -236,7 +236,7 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record)
236236
{
237237
if (get_mods() & MOD_MASK_SHIFT)
238238
{
239-
enable_caps_word();
239+
caps_word_on();
240240
}
241241

242242
if ((get_mods() & MOD_BIT(KC_LALT)) == MOD_BIT(KC_LALT))

kyria/qmk/rules.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ ENCODER_ENABLE = yes # https://docs.qmk.fm/#/feature_encoders
44
MOUSEKEY_ENABLE = no # https://docs.qmk.fm/#/feature_mouse_keys
55
OLED_ENABLE = no # https://docs.qmk.fm/#/feature_oled_driver
66
RGBLIGHT_ENABLE = yes # https://docs.qmk.fm/#/feature_rgblight
7+
CAPS_WORD_ENABLE = yes # https://docs.qmk.fm/#/feature_caps_word

0 commit comments

Comments
 (0)