-
Notifications
You must be signed in to change notification settings - Fork 13
Expand file tree
/
Copy pathsrc.c
More file actions
686 lines (627 loc) · 19.7 KB
/
src.c
File metadata and controls
686 lines (627 loc) · 19.7 KB
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
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
// ---------------------------------------------------------------------------
// Работа с шифтом
// ---------------------------------------------------------------------------
Shift shift_should_be = 0;
Shift shift_current = 0;
uint32_t shift_timer = 0;
uint8_t shift_pressed_count = 0;
Key shift_get_key(Key key) {
switch (key) {
case KS_GRV: return KC_GRV;
case KS_TILD: return KC_GRV;
case KS_1: return KC_1;
case KS_EXCL: return KC_1;
case KS_2: return KC_2;
case KS_AT: return KC_2;
case KS_3: return KC_3;
case KS_HASH: return KC_3;
case KS_4: return KC_4;
case KS_DLR: return KC_4;
case KS_5: return KC_5;
case KS_PERC: return KC_5;
case KS_6: return KC_6;
case KS_CIRC: return KC_6;
case KS_7: return KC_7;
case KS_AMPR: return KC_7;
case KS_8: return KC_8;
case KS_ASTR: return KC_8;
case KS_9: return KC_9;
case KS_LPRN: return KC_9;
case KS_0: return KC_0;
case KS_RPRN: return KC_0;
case KS_MINS: return KC_MINS;
case KS_UNDS: return KC_MINS;
case KS_EQL: return KC_EQL;
case KS_PLUS: return KC_EQL;
case KS_Q: return KC_Q;
case KS_S_Q: return KC_Q;
case KS_W: return KC_W;
case KS_S_W: return KC_W;
case KS_E: return KC_E;
case KS_S_E: return KC_E;
case KS_R: return KC_R;
case KS_S_R: return KC_R;
case KS_T: return KC_T;
case KS_S_T: return KC_T;
case KS_Y: return KC_Y;
case KS_S_Y: return KC_Y;
case KS_U: return KC_U;
case KS_S_U: return KC_U;
case KS_I: return KC_I;
case KS_S_I: return KC_I;
case KS_O: return KC_O;
case KS_S_O: return KC_O;
case KS_P: return KC_P;
case KS_S_P: return KC_P;
case KS_LBRC: return KC_LBRC;
case KS_LCBR: return KC_LBRC;
case KS_RBRC: return KC_RBRC;
case KS_RCBR: return KC_RBRC;
case KS_A: return KC_A;
case KS_S_A: return KC_A;
case KS_S: return KC_S;
case KS_S_S: return KC_S;
case KS_D: return KC_D;
case KS_S_D: return KC_D;
case KS_F: return KC_F;
case KS_S_F: return KC_F;
case KS_G: return KC_G;
case KS_S_G: return KC_G;
case KS_H: return KC_H;
case KS_S_H: return KC_H;
case KS_J: return KC_J;
case KS_S_J: return KC_J;
case KS_K: return KC_K;
case KS_S_K: return KC_K;
case KS_L: return KC_L;
case KS_S_L: return KC_L;
case KS_SCLN: return KC_SCLN;
case KS_COLN: return KC_SCLN;
case KS_QUOT: return KC_QUOT;
case KS_DQUO: return KC_QUOT;
#ifdef LANG_USE_ANSI
case KS_BSLS: return KC_BSLS;
case KS_PIPE: return KC_BSLS;
#else
case KS_BSLS: return KC_NUHS; // ISO keyboards use another backslash code
case KS_PIPE: return KC_NUHS; // but there is no difference for OS
case KS_LT2: return KC_NUBS;
case KS_GT2: return KC_NUBS;
#endif
case KS_Z: return KC_Z;
case KS_S_Z: return KC_Z;
case KS_X: return KC_X;
case KS_S_X: return KC_X;
case KS_C: return KC_C;
case KS_S_C: return KC_C;
case KS_V: return KC_V;
case KS_S_V: return KC_V;
case KS_B: return KC_B;
case KS_S_B: return KC_B;
case KS_N: return KC_N;
case KS_S_N: return KC_N;
case KS_M: return KC_M;
case KS_S_M: return KC_M;
case KS_COMM: return KC_COMM;
case KS_LT: return KC_COMM;
case KS_DOT: return KC_DOT;
case KS_GT: return KC_DOT;
case KS_SLSH: return KC_SLSH;
case KS_QUES: return KC_SLSH;
default: return NONE_KEY;
}
}
Shift shift_get_shift(Key key) {
if (KS_GRV <= key && key <= KS_QUES) {
return (key - KS_GRV) % 2;
} else {
return NONE_SHIFT;
}
}
void shift_activate(Shift shift) {
if (shift_current != shift) {
shift_timer = timer_read();
if (shift) {
register_code(KC_LSHIFT);
} else {
unregister_code(KC_LSHIFT);
}
}
shift_current = shift;
}
void shift_activate_from_user(Shift shift) {
shift_should_be = shift;
shift_activate(shift);
}
Key shift_process(Key key, bool down) {
Shift new_shift = shift_get_shift(key);
if (down) {
if (new_shift != NONE_SHIFT) {
shift_activate(new_shift);
} else {
shift_activate(shift_should_be);
}
}
if (new_shift != NONE_SHIFT) {
if (down) {
shift_pressed_count++;
} else {
shift_pressed_count--;
}
}
return shift_get_key(key);
}
void shift_user_timer(void) {
// Нужно выключать шифт после прохождения определённого времени, потому что пользователь ожидает как будто шифт на самом деле включён
if (shift_pressed_count == 0 && shift_current != shift_should_be && timer_read() - shift_timer >= 100) {
shift_activate(shift_should_be);
shift_timer = timer_read();
}
}
// ---------------------------------------------------------------------------
// Работа с одиночным шифтом
// ---------------------------------------------------------------------------
uint8_t shift_once_disable_stage = 2;
uint8_t shift_once_layer_off = 0;
uint8_t shift_once_layer_current = 0;
uint32_t shift_once_enabled_time = 0;
bool shift_once_can_disable = true;
bool shift_once_is_enabled(void) {
return shift_once_disable_stage == 2;
}
void shift_once_use_to_next_key(uint8_t layer) {
if (shift_current == 0) {
shift_activate_from_user(true);
layer_on(layer);
shift_once_disable_stage = 2;
shift_once_layer_off = layer;
shift_once_enabled_time = timer_read();
}
}
void shift_once_process_key(uint8_t layer, bool down) {
if (down) {
shift_once_use_to_next_key(layer);
shift_once_can_disable = false;
} else {
shift_once_can_disable = true;
shift_once_enabled_time = timer_read();
}
}
void shift_once_disable(void) {
if (shift_once_disable_stage == 2) {
layer_off(shift_once_layer_off);
shift_activate_from_user(false);
shift_once_disable_stage = 0;
}
}
void shift_once_process(Key key, keyrecord_t* record) {
bool down = record->event.pressed;
if (shift_once_disable_stage == 1) {
shift_once_disable_stage = 0;
shift_activate_from_user(false);
}
if (down && key != SFT_N_O && shift_once_disable_stage == 2) {
shift_once_disable_stage = 1;
layer_off(shift_once_layer_off);
}
}
void shift_once_user_timer(void) {
if (shift_once_can_disable && shift_once_is_enabled() && timer_read() - shift_once_enabled_time >= 1000) {
shift_once_disable();
}
}
// ---------------------------------------------------------------------------
// Работа с языком
// ---------------------------------------------------------------------------
Lang lang_should_be = 0;
Lang lang_current = 0;
uint32_t lang_timer = 0;
uint8_t lang_pressed_count = 0;
Key lang_get_key(Key key) {
if (EN_GRV <= key && key <= EN_QUES) {
return (key - EN_GRV) + KS_GRV;
} else if (RU_JO <= key && key <= RU_COMM) {
return (key - RU_JO) + KS_GRV;
} else {
return NONE_KEY;
}
}
Lang lang_get_lang(Key key) {
if (EN_GRV <= key && key <= EN_QUES) {
return 0;
} else if (RU_JO <= key && key <= RU_COMM) {
return 1;
} else {
return NONE_LANG;
}
}
Key lang_calc_agnostic(Key key) {
if (lang_current == 0) {
switch (key) {
case AG_1: return EN_1;
case AG_2: return EN_2;
case AG_3: return EN_3;
case AG_4: return EN_4;
case AG_5: return EN_5;
case AG_6: return EN_6;
case AG_7: return EN_7;
case AG_8: return EN_8;
case AG_9: return EN_9;
case AG_0: return EN_0;
case AG_EXCL: return EN_EXCL;
case AG_PERC: return EN_PERC;
case AG_ASTR: return EN_ASTR;
case AG_LPRN: return EN_LPRN;
case AG_RPRN: return EN_RPRN;
case AG_MINS: return EN_MINS;
case AG_UNDS: return EN_UNDS;
case AG_EQL: return EN_EQL;
case AG_PLUS: return EN_PLUS;
case AG_SCLN: return EN_SCLN;
case AG_COLN: return EN_COLN;
case AG_DQUO: return EN_DQUO;
case AG_BSLS: return EN_BSLS;
#ifndef LANG_USE_ANSI
case AG_PIPE: return EN_PIPE;
#endif
case AG_COMM: return EN_COMM;
case AG_DOT: return EN_DOT;
case AG_SLSH: return EN_SLSH;
#ifndef LANG_USE_ANSI
case AG_S_SL: return EN_SLSH;
#endif
case AG_QUES: return EN_QUES;
default: return NONE_KEY;
}
} else {
switch (key) {
case AG_1: return RU_1;
case AG_2: return RU_2;
case AG_3: return RU_3;
case AG_4: return RU_4;
case AG_5: return RU_5;
case AG_6: return RU_6;
case AG_7: return RU_7;
case AG_8: return RU_8;
case AG_9: return RU_9;
case AG_0: return RU_0;
case AG_EXCL: return RU_EXCL;
case AG_PERC: return RU_PERC;
case AG_ASTR: return RU_ASTR;
case AG_LPRN: return RU_LPRN;
case AG_RPRN: return RU_RPRN;
case AG_MINS: return RU_MINS;
case AG_UNDS: return RU_UNDS;
case AG_EQL: return RU_EQL;
case AG_PLUS: return RU_PLUS;
case AG_SCLN: return RU_SCLN;
case AG_COLN: return RU_COLN;
case AG_DQUO: return RU_DQUO;
case AG_BSLS: return RU_BSLS;
#ifndef LANG_USE_ANSI
case AG_PIPE: return RU_PIPE;
#endif
case AG_COMM: return RU_COMM;
case AG_DOT: return RU_DOT;
#ifdef LANG_USE_ANSI
case AG_SLSH: return RU_SLSH;
#else
case AG_SLSH: return RU_SLS2;
case AG_S_SL: return RU_SLSH;
#endif
case AG_QUES: return RU_QUES;
default: return NONE_KEY;
}
}
}
uint8_t lang_get_shift_layer_number(void) {
return lang_should_be * 2 + 1;
}
void lang_synchronize(void) {
lang_timer = timer_read();
switch (lang_current_change) {
case LANG_CHANGE_CAPS: {
// Костыль, потому что при нажатии Shift+Caps включается режим Caps, а не переключение языка :facepalm:
if (shift_current == 1) {
unregister_code(KC_LSHIFT);
register_code(KC_CAPS);
unregister_code(KC_CAPS);
register_code(KC_LSHIFT);
} else {
register_code(KC_CAPS);
unregister_code(KC_CAPS);
}
} break;
case LANG_CHANGE_ALT_SHIFT: {
register_code(KC_LALT);
register_code(KC_LSHIFT);
unregister_code(KC_LSHIFT);
unregister_code(KC_LALT);
// Костыль, потому что при зажатом шифте если хочется нажать клавишу, которая переключает язык, то шифт слетает...
if (shift_current == 1) {
register_code(KC_LSHIFT);
}
} break;
case LANG_CHANGE_SHIFT_ALT: {
register_code(KC_LSHIFT);
register_code(KC_LALT);
unregister_code(KC_LALT);
unregister_code(KC_LSHIFT);
// Костыль, потому что при зажатом шифте если хочется нажать клавишу, которая переключает язык, то шифт слетает...
if (shift_current == 1) {
register_code(KC_LSHIFT);
}
} break;
case LANG_CHANGE_CTRL_SHIFT: {
register_code(KC_LCTRL);
register_code(KC_LSHIFT);
unregister_code(KC_LSHIFT);
unregister_code(KC_LCTL);
// Костыль, потому что при зажатом шифте если хочется нажать клавишу, которая переключает язык, то шифт слетает...
if (shift_current == 1) {
register_code(KC_LSHIFT);
}
} break;
case LANG_CHANGE_SHIFT_CTRL: {
register_code(KC_LSHIFT);
register_code(KC_LCTRL);
unregister_code(KC_LCTL);
unregister_code(KC_LSHIFT);
// Костыль, потому что при зажатом шифте если хочется нажать клавишу, которая переключает язык, то шифт слетает...
if (shift_current == 1) {
register_code(KC_LSHIFT);
}
} break;
case LANG_CHANGE_WIN_SPACE: {
register_code(KC_LGUI);
register_code(KC_SPACE);
unregister_code(KC_SPACE);
unregister_code(KC_LGUI);
} break;
}
}
void lang_activate(Lang lang) {
// Нужно дополнять этот код, если нужно три языка и более
if (lang_current != lang) {
lang_synchronize();
}
lang_current = lang;
}
void lang_activate_from_user(Lang lang) {
lang_should_be = lang;
lang_activate(lang);
}
void lang_activate_from_user_without_sync(Lang lang) {
lang_should_be = lang;
lang_current = lang;
}
Key lang_process(Key key, bool down) {
Key after_agnostic = lang_calc_agnostic(key);
if (after_agnostic != NONE_KEY) {
key = after_agnostic;
}
Lang new_lang = lang_get_lang(key);
if (down) {
if (new_lang != NONE_LANG) {
lang_activate(new_lang);
} else {
lang_activate(lang_should_be);
}
}
if (new_lang != NONE_LANG) {
if (down) {
lang_pressed_count++;
} else {
lang_pressed_count--;
}
}
return lang_get_key(key);
}
void lang_user_timer(void) {
// Нужно выключать язык после прохождения определённого времени, потому что пользователь ожидает как будто шифт на самом деле включён
if (lang_pressed_count == 0 && lang_current != lang_should_be && timer_read() - lang_timer >= 100) {
lang_activate(lang_should_be);
}
}
// ---------------------------------------------------------------------------
// Обработка клавиш
// ---------------------------------------------------------------------------
uint8_t lang_shift_current_shift_layer = 0;
void lang_shift_press_key(Key key, bool down) {
keyrecord_t record = {
.event = {
.key = {
.col = 0,
.row = 0,
},
.pressed = down,
.time = timer_read(),
},
};
lang_shift_process_record(key, &record);
}
void lang_shift_tap_key(Key key) {
lang_shift_press_key(key, true);
lang_shift_press_key(key, false);
shift_activate(shift_should_be);
lang_activate(lang_should_be);
}
bool lang_shift_process_custom_keycodes(Key key, keyrecord_t* record) {
bool down = record->event.pressed;
// Обрабатываем клавиши, связанные с кастомным шифтом и кастомным переключением языка
switch (key) {
case SFT_N_O:
shift_once_process_key(lang_get_shift_layer_number(), down);
return false;
case SFT_N:
if (down) {
shift_activate_from_user(true);
lang_shift_current_shift_layer = lang_get_shift_layer_number();
layer_on(lang_shift_current_shift_layer);
} else {
shift_should_be = false;
if (shift_pressed_count == 0) {
shift_activate_from_user(false);
}
layer_off(lang_shift_current_shift_layer);
}
return false;
case LA_CHNG:
if (down) {
if (lang_should_be == 0) {
lang_activate_from_user(1);
layer_on(2);
} else {
lang_activate_from_user(0);
layer_off(2);
}
}
return false;
case LA_SYNC:
if (down) {
lang_synchronize();
}
return false;
case LA_CAPS:
if (down) {
lang_current_change = LANG_CHANGE_CAPS;
}
return false;
case LA_ALSH:
if (down) {
lang_current_change = LANG_CHANGE_ALT_SHIFT;
}
return false;
case LA_SHAL:
if (down) {
lang_current_change = LANG_CHANGE_SHIFT_ALT;
}
return false;
case LA_CTSH:
if (down) {
lang_current_change = LANG_CHANGE_CTRL_SHIFT;
}
return false;
case LA_SHCT:
if (down) {
lang_current_change = LANG_CHANGE_SHIFT_CTRL;
}
return false;
case LA_WISP:
if (down) {
lang_current_change = LANG_CHANGE_WIN_SPACE;
}
return false;
case AG_3DOT:
if (record->event.pressed) {
lang_shift_tap_key(AG_DOT);
lang_shift_tap_key(AG_DOT);
lang_shift_tap_key(AG_DOT);
}
return false;
break;
case AG_CMSP:
if (record->event.pressed) {
lang_shift_tap_key(AG_COMM);
register_code(KC_SPC);
unregister_code(KC_SPC);
}
return false;
break;
case AG_SDOT:
if (record->event.pressed) {
lang_shift_tap_key(AG_DOT);
register_code(KC_SPC);
unregister_code(KC_SPC);
shift_once_use_to_next_key(lang_get_shift_layer_number());
}
return false;
break;
}
return true;
}
bool lang_shift_process_english_modifiers(Key key, keyrecord_t* record) {
static Lang lang_stack[3] = {};
static uint8_t modifiers_count = 0;
#define PROCESS(NAME, REGISTER, UNREGISTER, ACTIVATE_LANG) \
case NAME: { \
if (record->event.pressed) { \
lang_stack[modifiers_count] = lang_should_be; \
modifiers_count += 1; \
if (lang_should_be == 1) { \
layer_off(2); \
} \
if (ACTIVATE_LANG) { \
lang_activate_from_user(0); \
} else { \
lang_activate_from_user_without_sync(0); \
} \
REGISTER; \
} else { \
UNREGISTER; \
modifiers_count -= 1; \
if (ACTIVATE_LANG) { \
lang_activate_from_user(lang_stack[modifiers_count]); \
} else { \
lang_activate_from_user_without_sync(lang_stack[modifiers_count]); \
} \
if (lang_should_be == 1) { \
layer_on(2); \
} \
} \
return false; \
} break;
#define Rg(x) register_code(KC_L ## x)
#define Un(x) unregister_code(KC_L ## x)
switch (key) {
PROCESS(CTRL_0, Rg(CTRL), Un(CTRL), false);
PROCESS(ALT_0, Rg(ALT), Un(ALT), false);
PROCESS(WIN_0, Rg(GUI), Un(GUI), false);
PROCESS(CTAL_0, { Rg(CTRL); Rg(ALT); }, { Un(ALT); Un(CTRL); }, false);
PROCESS(SHAL_0, { Rg(SHIFT); Rg(ALT); }, { Un(ALT); Un(SHIFT); }, false);
PROCESS(CTSH_0, { Rg(CTRL); Rg(SHIFT); }, { Un(SHIFT); Un(CTRL); }, false);
PROCESS(MCAS_0, { Rg(CTRL); Rg(ALT); Rg(SHIFT); }, { Un(SHIFT); Un(ALT); Un(CTRL); }, false);
PROCESS(CTRL_EN, Rg(CTRL), Un(CTRL), true);
PROCESS(ALT_EN, Rg(ALT), Un(ALT), true);
PROCESS(WIN_EN, Rg(GUI), Un(GUI), true);
PROCESS(CTAL_EN, { Rg(CTRL); Rg(ALT); }, { Un(ALT); Un(CTRL); }, true);
PROCESS(SHAL_EN, { Rg(SHIFT); Rg(ALT); }, { Un(ALT); Un(SHIFT); }, true);
PROCESS(CTSH_EN, { Rg(CTRL); Rg(SHIFT); }, { Un(SHIFT); Un(CTRL); }, true);
PROCESS(MCAS_EN, { Rg(CTRL); Rg(ALT); Rg(SHIFT); }, { Un(SHIFT); Un(ALT); Un(CTRL); }, true);
}
return true;
}
bool lang_shift_process_record(Key key, keyrecord_t* record) {
// Обрабатываем Once Shift
shift_once_process(key, record);
bool down = record->event.pressed;
// Разбираемся, имеет ли эта клавиша какой-то язык, заданный в ней
Key key1 = lang_process(key, down);
Key key_to_shift = key;
if (key1 != NONE_KEY) {
key_to_shift = key1;
}
// Разбираемся, имеет ли эта клавиша шифт, засунутый в неё
// Это нужно отдельно от обработки языка, чтобы шифт мог выключаться для обычных клавиш
Key key2 = shift_process(key_to_shift, down);
if (key2 != NONE_KEY) {
if (down) {
register_code(key2);
} else {
unregister_code(key2);
}
return false;
}
if (!lang_shift_process_custom_keycodes(key, record)) {
return false;
}
if (!lang_shift_process_english_modifiers(key, record)) {
return false;
}
return true;
}
void lang_shift_user_timer(void) {
shift_user_timer();
shift_once_user_timer();
lang_user_timer();
}