main
1// Numword layer implementation
2// Based on https://github.com/treeman/qmk_firmware/blob/master/keyboards/ferris/keymaps/treeman/layermodes.c
3// and https://www.jonashietala.se/blog/2022/09/06/the_current_t-34_keyboard_layout/#Numbers
4
5#include QMK_KEYBOARD_H
6#include "layermodes.h"
7
8static uint16_t num_word_timer;
9static bool _num_word_enabled = false;
10static uint8_t _num_word_layer = 0;
11
12void enable_num_word(uint8_t layer) {
13 _num_word_enabled = true;
14 _num_word_layer = layer;
15 layer_on(layer);
16}
17
18void disable_num_word(uint8_t layer) {
19 _num_word_enabled = false;
20 layer_off(layer);
21}
22
23bool is_num_word_enabled(void) {
24 return _num_word_enabled;
25}
26
27void process_num_word_activation(uint8_t layer, const keyrecord_t *record) {
28 if (record->event.pressed) {
29 layer_on(layer);
30 num_word_timer = timer_read();
31 } else {
32 if (timer_elapsed(num_word_timer) < TAPPING_TERM) {
33 // Tapped, enable numword
34 _num_word_enabled = true;
35 _num_word_layer = layer;
36 } else {
37 // Held, just turn off the layer
38 layer_off(layer);
39 }
40 }
41}
42
43// Returns true if numword should remain active after pressing this key
44// Note: F-keys (F1-F15) are intentionally NOT in this list, so they will
45// send from the NUMB layer and then automatically disable numword
46static bool is_num_word_key(uint16_t keycode) {
47 // Extract base keycode from layer-tap, mod-tap, etc.
48 // This handles cases like LT(NAVI,KC_BSPC) -> KC_BSPC
49 switch (keycode) {
50 case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
51 keycode = keycode & 0xFF; // Extract the base keycode
52 break;
53 case QK_MOD_TAP ... QK_MOD_TAP_MAX:
54 keycode = keycode & 0xFF; // Extract the base keycode
55 break;
56 }
57
58 switch (keycode) {
59 // Numbers
60 case KC_1 ... KC_0:
61 case KC_P1 ... KC_P0:
62 // Numpad operators
63 case KC_PAST: // *
64 case KC_PSLS: // /
65 case KC_PMNS: // -
66 case KC_PPLS: // +
67 case KC_PDOT: // .
68 case KC_PCMM: // ,
69 case KC_PEQL: // =
70 // Other operators and symbols commonly used with numbers
71 case KC_PLUS:
72 case KC_MINS:
73 case KC_EQL:
74 case KC_PERC:
75 case KC_DOT:
76 case KC_COMM:
77 case KC_COLN:
78 case KC_UNDS:
79 // Special keys
80 case KC_BSPC:
81 case KC_DEL:
82 case KC_ENT:
83 case KC_SPC:
84 case QK_REP: // Repeat key
85 case QK_AREP: // Alternate repeat key
86 // x for hexadecimal
87 case KC_X:
88 // Modifiers (so they don't disable numword)
89 case KC_LSFT ... KC_RGUI:
90 case OS_LSFT ... OS_RGUI:
91 return true;
92 default:
93 return false;
94 }
95}
96
97bool process_num_word(uint16_t keycode, const keyrecord_t *record) {
98 if (!_num_word_enabled) {
99 return true;
100 }
101
102 // Only check on key press to determine if we should disable
103 if (record->event.pressed) {
104 // Check if this key should keep numword active
105 // If not, we'll disable on the RELEASE so the key sends from the layer first
106 if (!is_num_word_key(keycode)) {
107 // Mark for disable, but don't disable yet - let the key send first
108 }
109 } else {
110 // On key release, check if we should disable numword
111 if (!is_num_word_key(keycode)) {
112 disable_num_word(_num_word_layer);
113 }
114 }
115
116 return true;
117}