diff options
Diffstat (limited to 'quantum')
| -rw-r--r-- | quantum/process_keycode/process_steno.c | 136 | ||||
| -rw-r--r-- | quantum/process_keycode/process_steno.h | 4 |
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 | ||
| 60 | uint8_t state[MAX_STATE_SIZE] = {0}; | 61 | static uint8_t state[MAX_STATE_SIZE] = {0}; |
| 61 | uint8_t pressed = 0; | 62 | static uint8_t chord[MAX_STATE_SIZE] = {0}; |
| 62 | steno_mode_t mode; | 63 | static int8_t pressed = 0; |
| 64 | static steno_mode_t mode; | ||
| 63 | 65 | ||
| 64 | uint8_t boltmap[64] = { | 66 | static 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 | ||
| 73 | void steno_clear_state(void) { | 75 | static 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 | |||
| 80 | static 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 | ||
| 77 | void steno_init() { | 88 | void 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 | ||
| 90 | void 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)) |
| 105 | bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { return true; } | ||
| 106 | |||
| 107 | __attribute__ ((weak)) | ||
| 108 | bool 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)) | ||
| 111 | bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } | ||
| 112 | |||
| 113 | static 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 | ||
| 99 | bool update_state_bolt(uint8_t key) { | 129 | uint8_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 | ||
| 105 | bool send_state_bolt(void) { | 133 | uint8_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 | ||
| 111 | bool update_state_gemini(uint8_t key) { | 137 | static 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 | ||
| 116 | bool send_state_gemini(void) { | 148 | static 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 | ||
| 122 | bool process_steno(uint16_t keycode, keyrecord_t *record) { | 160 | bool 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; | |||
| 27 | bool process_steno(uint16_t keycode, keyrecord_t *record); | 27 | bool process_steno(uint16_t keycode, keyrecord_t *record); |
| 28 | void steno_init(void); | 28 | void steno_init(void); |
| 29 | void steno_set_mode(steno_mode_t mode); | 29 | void steno_set_mode(steno_mode_t mode); |
| 30 | uint8_t *steno_get_state(void); | ||
| 31 | uint8_t *steno_get_chord(void); | ||
| 30 | 32 | ||
| 31 | #endif \ No newline at end of file | 33 | #endif |
