diff options
Diffstat (limited to 'quantum/process_keycode/process_steno.c')
| -rw-r--r-- | quantum/process_keycode/process_steno.c | 208 |
1 files changed, 97 insertions, 111 deletions
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c index 50a1ef2fc..e0b33ec86 100644 --- a/quantum/process_keycode/process_steno.c +++ b/quantum/process_keycode/process_steno.c | |||
| @@ -58,150 +58,136 @@ | |||
| 58 | #define GEMINI_STATE_SIZE 6 | 58 | #define GEMINI_STATE_SIZE 6 |
| 59 | #define MAX_STATE_SIZE GEMINI_STATE_SIZE | 59 | #define MAX_STATE_SIZE GEMINI_STATE_SIZE |
| 60 | 60 | ||
| 61 | static uint8_t state[MAX_STATE_SIZE] = {0}; | 61 | static uint8_t state[MAX_STATE_SIZE] = {0}; |
| 62 | static uint8_t chord[MAX_STATE_SIZE] = {0}; | 62 | static uint8_t chord[MAX_STATE_SIZE] = {0}; |
| 63 | static int8_t pressed = 0; | 63 | static int8_t pressed = 0; |
| 64 | static steno_mode_t mode; | 64 | static steno_mode_t mode; |
| 65 | 65 | ||
| 66 | static const uint8_t boltmap[64] PROGMEM = { | 66 | static const uint8_t boltmap[64] PROGMEM = {TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L, TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL, TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R, TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R}; |
| 67 | TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, | ||
| 68 | TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L, | ||
| 69 | TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL, | ||
| 70 | TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R, | ||
| 71 | TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R, | ||
| 72 | TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R | ||
| 73 | }; | ||
| 74 | 67 | ||
| 75 | static void steno_clear_state(void) { | 68 | static void steno_clear_state(void) { |
| 76 | memset(state, 0, sizeof(state)); | 69 | memset(state, 0, sizeof(state)); |
| 77 | memset(chord, 0, sizeof(chord)); | 70 | memset(chord, 0, sizeof(chord)); |
| 78 | } | 71 | } |
| 79 | 72 | ||
| 80 | static void send_steno_state(uint8_t size, bool send_empty) { | 73 | static void send_steno_state(uint8_t size, bool send_empty) { |
| 81 | for (uint8_t i = 0; i < size; ++i) { | 74 | for (uint8_t i = 0; i < size; ++i) { |
| 82 | if (chord[i] || send_empty) { | 75 | if (chord[i] || send_empty) { |
| 83 | virtser_send(chord[i]); | 76 | virtser_send(chord[i]); |
| 77 | } | ||
| 84 | } | 78 | } |
| 85 | } | ||
| 86 | } | 79 | } |
| 87 | 80 | ||
| 88 | void steno_init() { | 81 | void steno_init() { |
| 89 | if (!eeconfig_is_enabled()) { | 82 | if (!eeconfig_is_enabled()) { |
| 90 | eeconfig_init(); | 83 | eeconfig_init(); |
| 91 | } | 84 | } |
| 92 | mode = eeprom_read_byte(EECONFIG_STENOMODE); | 85 | mode = eeprom_read_byte(EECONFIG_STENOMODE); |
| 93 | } | 86 | } |
| 94 | 87 | ||
| 95 | void steno_set_mode(steno_mode_t new_mode) { | 88 | void steno_set_mode(steno_mode_t new_mode) { |
| 96 | steno_clear_state(); | 89 | steno_clear_state(); |
| 97 | mode = new_mode; | 90 | mode = new_mode; |
| 98 | eeprom_update_byte(EECONFIG_STENOMODE, mode); | 91 | eeprom_update_byte(EECONFIG_STENOMODE, mode); |
| 99 | } | 92 | } |
| 100 | 93 | ||
| 101 | /* override to intercept chords right before they get sent. | 94 | /* override to intercept chords right before they get sent. |
| 102 | * return zero to suppress normal sending behavior. | 95 | * return zero to suppress normal sending behavior. |
| 103 | */ | 96 | */ |
| 104 | __attribute__ ((weak)) | 97 | __attribute__((weak)) bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { return true; } |
| 105 | bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]) { return true; } | ||
| 106 | 98 | ||
| 107 | __attribute__ ((weak)) | 99 | __attribute__((weak)) bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed) { return true; } |
| 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 | 100 | ||
| 110 | __attribute__ ((weak)) | 101 | __attribute__((weak)) bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } |
| 111 | bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; } | ||
| 112 | 102 | ||
| 113 | static void send_steno_chord(void) { | 103 | static void send_steno_chord(void) { |
| 114 | if (send_steno_chord_user(mode, chord)) { | 104 | if (send_steno_chord_user(mode, chord)) { |
| 115 | switch(mode) { | 105 | switch (mode) { |
| 116 | case STENO_MODE_BOLT: | 106 | case STENO_MODE_BOLT: |
| 117 | send_steno_state(BOLT_STATE_SIZE, false); | 107 | send_steno_state(BOLT_STATE_SIZE, false); |
| 118 | virtser_send(0); // terminating byte | 108 | virtser_send(0); // terminating byte |
| 119 | break; | 109 | break; |
| 120 | case STENO_MODE_GEMINI: | 110 | case STENO_MODE_GEMINI: |
| 121 | chord[0] |= 0x80; // Indicate start of packet | 111 | chord[0] |= 0x80; // Indicate start of packet |
| 122 | send_steno_state(GEMINI_STATE_SIZE, true); | 112 | send_steno_state(GEMINI_STATE_SIZE, true); |
| 123 | break; | 113 | break; |
| 114 | } | ||
| 124 | } | 115 | } |
| 125 | } | 116 | steno_clear_state(); |
| 126 | steno_clear_state(); | ||
| 127 | } | 117 | } |
| 128 | 118 | ||
| 129 | uint8_t *steno_get_state(void) { | 119 | uint8_t *steno_get_state(void) { return &state[0]; } |
| 130 | return &state[0]; | ||
| 131 | } | ||
| 132 | 120 | ||
| 133 | uint8_t *steno_get_chord(void) { | 121 | uint8_t *steno_get_chord(void) { return &chord[0]; } |
| 134 | return &chord[0]; | ||
| 135 | } | ||
| 136 | 122 | ||
| 137 | static bool update_state_bolt(uint8_t key, bool press) { | 123 | static bool update_state_bolt(uint8_t key, bool press) { |
| 138 | uint8_t boltcode = pgm_read_byte(boltmap + key); | 124 | uint8_t boltcode = pgm_read_byte(boltmap + key); |
| 139 | if (press) { | 125 | if (press) { |
| 140 | state[TXB_GET_GROUP(boltcode)] |= boltcode; | 126 | state[TXB_GET_GROUP(boltcode)] |= boltcode; |
| 141 | chord[TXB_GET_GROUP(boltcode)] |= boltcode; | 127 | chord[TXB_GET_GROUP(boltcode)] |= boltcode; |
| 142 | } else { | 128 | } else { |
| 143 | state[TXB_GET_GROUP(boltcode)] &= ~boltcode; | 129 | state[TXB_GET_GROUP(boltcode)] &= ~boltcode; |
| 144 | } | 130 | } |
| 145 | return false; | 131 | return false; |
| 146 | } | 132 | } |
| 147 | 133 | ||
| 148 | static bool update_state_gemini(uint8_t key, bool press) { | 134 | static bool update_state_gemini(uint8_t key, bool press) { |
| 149 | int idx = key / 7; | 135 | int idx = key / 7; |
| 150 | uint8_t bit = 1 << (6 - (key % 7)); | 136 | uint8_t bit = 1 << (6 - (key % 7)); |
| 151 | if (press) { | 137 | if (press) { |
| 152 | state[idx] |= bit; | 138 | state[idx] |= bit; |
| 153 | chord[idx] |= bit; | 139 | chord[idx] |= bit; |
| 154 | } else { | 140 | } else { |
| 155 | state[idx] &= ~bit; | 141 | state[idx] &= ~bit; |
| 156 | } | 142 | } |
| 157 | return false; | 143 | return false; |
| 158 | } | 144 | } |
| 159 | 145 | ||
| 160 | bool process_steno(uint16_t keycode, keyrecord_t *record) { | 146 | bool process_steno(uint16_t keycode, keyrecord_t *record) { |
| 161 | switch (keycode) { | 147 | switch (keycode) { |
| 162 | case QK_STENO_BOLT: | 148 | case QK_STENO_BOLT: |
| 163 | if (!process_steno_user(keycode, record)) { | 149 | if (!process_steno_user(keycode, record)) { |
| 164 | return false; | 150 | return false; |
| 165 | } | 151 | } |
| 166 | if (IS_PRESSED(record->event)) { | 152 | if (IS_PRESSED(record->event)) { |
| 167 | steno_set_mode(STENO_MODE_BOLT); | 153 | steno_set_mode(STENO_MODE_BOLT); |
| 168 | } | 154 | } |
| 169 | return false; | 155 | return false; |
| 170 | 156 | ||
| 171 | case QK_STENO_GEMINI: | 157 | case QK_STENO_GEMINI: |
| 172 | if (!process_steno_user(keycode, record)) { | 158 | if (!process_steno_user(keycode, record)) { |
| 173 | return false; | 159 | return false; |
| 174 | } | 160 | } |
| 175 | if (IS_PRESSED(record->event)) { | 161 | if (IS_PRESSED(record->event)) { |
| 176 | steno_set_mode(STENO_MODE_GEMINI); | 162 | steno_set_mode(STENO_MODE_GEMINI); |
| 177 | } | 163 | } |
| 178 | return false; | 164 | return false; |
| 179 | 165 | ||
| 180 | case STN__MIN...STN__MAX: | 166 | case STN__MIN ... STN__MAX: |
| 181 | if (!process_steno_user(keycode, record)) { | 167 | if (!process_steno_user(keycode, record)) { |
| 182 | return false; | 168 | return false; |
| 183 | } | 169 | } |
| 184 | switch(mode) { | 170 | switch (mode) { |
| 185 | case STENO_MODE_BOLT: | 171 | case STENO_MODE_BOLT: |
| 186 | update_state_bolt(keycode - QK_STENO, IS_PRESSED(record->event)); | 172 | update_state_bolt(keycode - QK_STENO, IS_PRESSED(record->event)); |
| 187 | break; | 173 | break; |
| 188 | case STENO_MODE_GEMINI: | 174 | case STENO_MODE_GEMINI: |
| 189 | update_state_gemini(keycode - QK_STENO, IS_PRESSED(record->event)); | 175 | update_state_gemini(keycode - QK_STENO, IS_PRESSED(record->event)); |
| 190 | break; | 176 | break; |
| 191 | } | 177 | } |
| 192 | // allow postprocessing hooks | 178 | // allow postprocessing hooks |
| 193 | if (postprocess_steno_user(keycode, record, mode, chord, pressed)) { | 179 | if (postprocess_steno_user(keycode, record, mode, chord, pressed)) { |
| 194 | if (IS_PRESSED(record->event)) { | 180 | if (IS_PRESSED(record->event)) { |
| 195 | ++pressed; | 181 | ++pressed; |
| 196 | } else { | 182 | } else { |
| 197 | --pressed; | 183 | --pressed; |
| 198 | if (pressed <= 0) { | 184 | if (pressed <= 0) { |
| 199 | pressed = 0; | 185 | pressed = 0; |
| 200 | send_steno_chord(); | 186 | send_steno_chord(); |
| 201 | } | 187 | } |
| 202 | } | 188 | } |
| 203 | } | 189 | } |
| 204 | return false; | 190 | return false; |
| 205 | } | 191 | } |
| 206 | return true; | 192 | return true; |
| 207 | } | 193 | } |
