aboutsummaryrefslogtreecommitdiff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
authorSeebs <seebs@seebs.net>2017-11-18 09:38:15 -0600
committerJack Humbert <jack.humb@gmail.com>2018-04-07 17:12:44 -0400
commitc0baf2a964b10d708281c704c0b049a1cf0f4914 (patch)
tree197350c318be03b332d1d4cd5f544d78f426fe39 /quantum/process_keycode
parent5f4c2dfd84467dc7f04e8e07c294ebfa5b4ca459 (diff)
downloadqmk_firmware-c0baf2a964b10d708281c704c0b049a1cf0f4914.tar.gz
qmk_firmware-c0baf2a964b10d708281c704c0b049a1cf0f4914.zip
Improve state/chord handling and clean up namespace
Some values that can never, ever, change were held in local variables, rather than in PROGMEM. Fixed. Change "pressed" to a signed int so the test for < 0 makes sense, and to avoid possible weird failure modes in the case where a key release comes in when pressed is already zero. (Shouldn't happen, sure, but computers are weird.) A lot of things in process_steno had external linkage for no particular reason. They've been marked static. Stuff still builds. Distinguish between currently-held keys and keys that have been held, and expose these values through a nicely-named API so other code could, say, check on the current set of steno chording in order to make displays. Also in passing fix up the "state" value having external linkage so it could clash with other people's variable declarations. The API also provides hooks for key processing and steno chord events, so you can monitor those events without having to run in matrix_scan_user and recheck the values directly. Also document these. There is no path through processing a key that doesn't end with a return false, so the nested return foo() are gone and we just return false.
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/process_steno.c136
-rw-r--r--quantum/process_keycode/process_steno.h4
2 files changed, 91 insertions, 49 deletions
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c
index 16bbf154f..3051fade9 100644
--- a/quantum/process_keycode/process_steno.c
+++ b/quantum/process_keycode/process_steno.c
@@ -18,6 +18,7 @@
18#include "eeprom.h" 18#include "eeprom.h"
19#include "keymap_steno.h" 19#include "keymap_steno.h"
20#include "virtser.h" 20#include "virtser.h"
21#include <string.h>
21 22
22// TxBolt Codes 23// TxBolt Codes
23#define TXB_NUL 0 24#define TXB_NUL 0
@@ -57,11 +58,12 @@
57#define GEMINI_STATE_SIZE 6 58#define GEMINI_STATE_SIZE 6
58#define MAX_STATE_SIZE GEMINI_STATE_SIZE 59#define MAX_STATE_SIZE GEMINI_STATE_SIZE
59 60
60uint8_t state[MAX_STATE_SIZE] = {0}; 61static uint8_t state[MAX_STATE_SIZE] = {0};
61uint8_t pressed = 0; 62static uint8_t chord[MAX_STATE_SIZE] = {0};
62steno_mode_t mode; 63static int8_t pressed = 0;
64static steno_mode_t mode;
63 65
64uint8_t boltmap[64] = { 66static const uint8_t boltmap[64] PROGMEM = {
65 TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, 67 TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM,
66 TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L, 68 TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L,
67 TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL, 69 TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL,
@@ -70,8 +72,17 @@ uint8_t boltmap[64] = {
70 TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R 72 TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R
71}; 73};
72 74
73void steno_clear_state(void) { 75static void steno_clear_state(void) {
74 __builtin_memset(state, 0, sizeof(state)); 76 memset(state, 0, sizeof(state));
77 memset(chord, 0, sizeof(chord));
78}
79
80static void send_steno_state(uint8_t size, bool send_empty) {
81 for (uint8_t i = 0; i < size; ++i) {
82 if (chord[i] || send_empty) {
83 virtser_send(chord[i]);
84 }
85 }
75} 86}
76 87
77void steno_init() { 88void steno_init() {
@@ -87,79 +98,108 @@ void steno_set_mode(steno_mode_t new_mode) {
87 eeprom_update_byte(EECONFIG_STENOMODE, mode); 98 eeprom_update_byte(EECONFIG_STENOMODE, mode);
88} 99}
89 100
90void send_steno_state(uint8_t size, bool send_empty) { 101/* override to intercept chords right before they get sent.
91 for (uint8_t i = 0; i < size; ++i) { 102 * return zero to suppress normal sending behavior.
92 if (state[i] || send_empty) { 103 */
93 virtser_send(state[i]); 104__attribute__ ((weak))
105bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { return true; }
106
107__attribute__ ((weak))
108bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed) { return true; }
109
110__attribute__ ((weak))
111bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
112
113static void send_steno_chord(void) {
114 if (send_steno_chord_user(mode, chord)) {
115 switch(mode) {
116 case STENO_MODE_BOLT:
117 send_steno_state(BOLT_STATE_SIZE, false);
118 virtser_send(0); // terminating byte
119 break;
120 case STENO_MODE_GEMINI:
121 chord[0] |= 0x80; // Indicate start of packet
122 send_steno_state(GEMINI_STATE_SIZE, true);
123 break;
94 } 124 }
95 } 125 }
96 steno_clear_state(); 126 steno_clear_state();
97} 127}
98 128
99bool update_state_bolt(uint8_t key) { 129uint8_t *steno_get_state(void) {
100 uint8_t boltcode = boltmap[key]; 130 return &state[0];
101 state[TXB_GET_GROUP(boltcode)] |= boltcode;
102 return false;
103} 131}
104 132
105bool send_state_bolt(void) { 133uint8_t *steno_get_chord(void) {
106 send_steno_state(BOLT_STATE_SIZE, false); 134 return &chord[0];
107 virtser_send(0); // terminating byte
108 return false;
109} 135}
110 136
111bool update_state_gemini(uint8_t key) { 137static bool update_state_bolt(uint8_t key, bool press) {
112 state[key / 7] |= 1 << (6 - (key % 7)); 138 uint8_t boltcode = pgm_read_byte(boltmap + key);
139 if (press) {
140 state[TXB_GET_GROUP(boltcode)] |= boltcode;
141 chord[TXB_GET_GROUP(boltcode)] |= boltcode;
142 } else {
143 state[TXB_GET_GROUP(boltcode)] &= ~boltcode;
144 }
113 return false; 145 return false;
114} 146}
115 147
116bool send_state_gemini(void) { 148static bool update_state_gemini(uint8_t key, bool press) {
117 state[0] |= 0x80; // Indicate start of packet 149 int idx = key / 7;
118 send_steno_state(GEMINI_STATE_SIZE, true); 150 uint8_t bit = 1 << (6 - (key % 7));
151 if (press) {
152 state[idx] |= bit;
153 chord[idx] |= bit;
154 } else {
155 state[idx] &= ~bit;
156 }
119 return false; 157 return false;
120} 158}
121 159
122bool process_steno(uint16_t keycode, keyrecord_t *record) { 160bool process_steno(uint16_t keycode, keyrecord_t *record) {
123 switch (keycode) { 161 switch (keycode) {
124 case QK_STENO_BOLT: 162 case QK_STENO_BOLT:
163 if (!process_steno_user(keycode, record)) {
164 return false;
165 }
125 if (IS_PRESSED(record->event)) { 166 if (IS_PRESSED(record->event)) {
126 steno_set_mode(STENO_MODE_BOLT); 167 steno_set_mode(STENO_MODE_BOLT);
127 } 168 }
128 return false; 169 return false;
129 170
130 case QK_STENO_GEMINI: 171 case QK_STENO_GEMINI:
172 if (!process_steno_user(keycode, record)) {
173 return false;
174 }
131 if (IS_PRESSED(record->event)) { 175 if (IS_PRESSED(record->event)) {
132 steno_set_mode(STENO_MODE_GEMINI); 176 steno_set_mode(STENO_MODE_GEMINI);
133 } 177 }
134 return false; 178 return false;
135 179
136 case STN__MIN...STN__MAX: 180 case STN__MIN...STN__MAX:
137 if (IS_PRESSED(record->event)) { 181 if (!process_steno_user(keycode, record)) {
138 uint8_t key = keycode - QK_STENO; 182 return false;
139 ++pressed;
140 switch(mode) {
141 case STENO_MODE_BOLT:
142 return update_state_bolt(key);
143 case STENO_MODE_GEMINI:
144 return update_state_gemini(key);
145 default:
146 return false;
147 }
148 } else {
149 --pressed;
150 if (pressed <= 0) {
151 pressed = 0;
152 switch(mode) {
153 case STENO_MODE_BOLT:
154 return send_state_bolt();
155 case STENO_MODE_GEMINI:
156 return send_state_gemini();
157 default:
158 return false;
159 }
160 }
161 } 183 }
162 184 switch(mode) {
185 case STENO_MODE_BOLT:
186 update_state_bolt(keycode - QK_STENO, IS_PRESSED(record->event));
187 case STENO_MODE_GEMINI:
188 update_state_gemini(keycode - QK_STENO, IS_PRESSED(record->event));
189 }
190 // allow postprocessing hooks
191 if (postprocess_steno_user(keycode, record, mode, chord, pressed)) {
192 if (IS_PRESSED(record->event)) {
193 ++pressed;
194 } else {
195 --pressed;
196 if (pressed <= 0) {
197 pressed = 0;
198 send_steno_chord();
199 }
200 }
201 }
202 return false;
163 } 203 }
164 return true; 204 return true;
165} 205}
diff --git a/quantum/process_keycode/process_steno.h b/quantum/process_keycode/process_steno.h
index 3bbcbeaaf..71f973122 100644
--- a/quantum/process_keycode/process_steno.h
+++ b/quantum/process_keycode/process_steno.h
@@ -27,5 +27,7 @@ typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t;
27bool process_steno(uint16_t keycode, keyrecord_t *record); 27bool process_steno(uint16_t keycode, keyrecord_t *record);
28void steno_init(void); 28void steno_init(void);
29void steno_set_mode(steno_mode_t mode); 29void steno_set_mode(steno_mode_t mode);
30uint8_t *steno_get_state(void);
31uint8_t *steno_get_chord(void);
30 32
31#endif \ No newline at end of file 33#endif