Add support for GeminiPR steno protocol.

This protocol breaks out "duplicate" keys into their own entry in the packet so that more complicated logic can be done on the software side, including support for additional languages and alternative theories.
b6_b7_audio
Joe Wasson 7 years ago committed by Jack Humbert
parent 5987f67989
commit f30f12ec81

@ -3,5 +3,5 @@ ifndef QUANTUM_DIR
endif endif
MOUSEKEY_ENABLE = no # Mouse keys(+4700) MOUSEKEY_ENABLE = no # Mouse keys(+4700)
STENO_ENABLE = yes # Enable TX Bolt protocol for Stenography, requires VIRTSER and may not work with mouse keys STENO_ENABLE = yes # Additional protocols for Stenography(+1700), requires VIRTSER
AUDIO_ENABLE = no # Audio output on port C6

@ -41,6 +41,9 @@ enum planck_keycodes {
EXT_PLV EXT_PLV
}; };
#define ST_BOLT QK_STENO_BOLT
#define ST_GEM QK_STENO_GEMINI
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Qwerty /* Qwerty
@ -166,7 +169,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[_ADJUST] = { [_ADJUST] = {
{_______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL }, {_______, RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_DEL },
{_______, _______, MU_MOD, AU_ON, AU_OFF, AG_NORM, AG_SWAP, QWERTY, COLEMAK, DVORAK, PLOVER, _______}, {_______, _______, MU_MOD, AU_ON, AU_OFF, AG_NORM, AG_SWAP, QWERTY, COLEMAK, DVORAK, PLOVER, _______},
{_______, MUV_DE, MUV_IN, MU_ON, MU_OFF, MI_ON, MI_OFF, _______, _______, _______, _______, _______}, {_______, MUV_DE, MUV_IN, MU_ON, MU_OFF, MI_ON, MI_OFF, _______, _______, _______, ST_BOLT, ST_GEM},
{_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______} {_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______}
} }

@ -18,8 +18,12 @@
#include "keymap.h" #include "keymap.h"
// List of keycodes for the steno keyboard. To prevent
// errors, this must be <= 42 total entries in order to
// support the GeminiPR protocol.
enum steno_keycodes { enum steno_keycodes {
STN_FN = QK_STENO, STN__MIN = QK_STENO,
STN_FN = STN__MIN,
STN_NUM, STN_NUM,
STN_N1 = STN_NUM, STN_N1 = STN_NUM,
STN_N2, STN_N2,
@ -65,7 +69,8 @@ enum steno_keycodes {
STN_NA, STN_NA,
STN_NB, STN_NB,
STN_NC, STN_NC,
STN_ZR STN_ZR,
STN__MAX = STN_ZR, // must be less than QK_STENO_BOLT
}; };
#endif #endif

@ -1,12 +1,8 @@
#include "process_steno.h" #include "process_steno.h"
#include "quantum_keycodes.h" #include "quantum_keycodes.h"
#include "keymap_steno.h" #include "keymap_steno.h"
#include "virtser.h" #include "virtser.h"
uint8_t state[4] = {0};
uint8_t pressed = 0;
// TxBolt Codes // TxBolt Codes
#define TXB_NUL 0 #define TXB_NUL 0
#define TXB_S_L 0b00000001 #define TXB_S_L 0b00000001
@ -41,6 +37,13 @@ uint8_t pressed = 0;
#define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6) #define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6)
#define BOLT_STATE_SIZE 4
#define GEMINI_STATE_SIZE 6
uint8_t state[MAX(BOLT_STATE_SIZE, GEMINI_STATE_SIZE)] = {0};
uint8_t pressed = 0;
steno_mode_t mode;
uint8_t boltmap[64] = { uint8_t boltmap[64] = {
TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, 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_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L,
@ -52,31 +55,97 @@ uint8_t boltmap[64] = {
#define BOLTMAP_MASK (sizeof(boltmap) - 1) #define BOLTMAP_MASK (sizeof(boltmap) - 1)
void send_steno_state(void) {
for (uint8_t i = 0; i < 4; ++i) { void steno_clear_state(void) {
if (state[i]) { memset(state, 0, sizeof(state));
}
void steno_init() {
if (!eeconfig_is_enabled()) {
eeconfig_init();
}
mode = eeprom_read_byte(EECONFIG_STENOMODE);
}
void steno_set_mode(steno_mode_t new_mode) {
steno_clear_state();
mode = new_mode;
eeprom_update_byte(EECONFIG_STENOMODE, mode);
}
void send_steno_state(uint8_t size, bool send_empty) {
for (uint8_t i = 0; i < size; ++i) {
if (state[i] || send_empty) {
virtser_send(state[i]); virtser_send(state[i]);
state[i] = 0;
} }
} }
virtser_send(0); steno_clear_state();
}
bool update_state_bolt(uint8_t key) {
uint8_t boltcode = boltmap[key];
state[TXB_GET_GROUP(boltcode)] |= boltcode;
return false;
}
bool send_state_bolt(void) {
send_steno_state(BOLT_STATE_SIZE, false);
virtser_send(0); // terminating byte
return false;
}
bool update_state_gemini(uint8_t key) {
state[key / 7] |= 1 << (6 - (key % 7));
return false;
}
bool send_state_gemini(void) {
state[0] |= 0x80; // Indicate start of packet
send_steno_state(GEMINI_STATE_SIZE, true);
return false;
} }
bool process_steno(uint16_t keycode, keyrecord_t *record) { bool process_steno(uint16_t keycode, keyrecord_t *record) {
if(keycode >= QK_STENO && keycode <= QK_STENO_MAX) { switch (keycode) {
if(IS_PRESSED(record->event)) { case QK_STENO_BOLT:
uint8_t boltcode = boltmap[keycode & BOLTMAP_MASK]; if (IS_PRESSED(record->event)) {
++pressed; steno_set_mode(STENO_MODE_BOLT);
state[TXB_GET_GROUP(boltcode)] |= boltcode;
} else {
--pressed;
if (pressed <= 0) {
pressed = 0; // protect against spurious up keys
send_steno_state();
} }
} return false;
return false;
} case QK_STENO_GEMINI:
if (IS_PRESSED(record->event)) {
steno_set_mode(STENO_MODE_GEMINI);
}
return false;
case STN__MIN...STN__MAX:
if (IS_PRESSED(record->event)) {
uint8_t key = keycode - QK_STENO;
++pressed;
switch(mode) {
case STENO_MODE_BOLT:
return update_state_bolt(key);
case STENO_MODE_GEMINI:
return update_state_gemini(key);
default:
return false;
}
} else {
--pressed;
if (pressed <= 0) {
pressed = 0;
switch(mode) {
case STENO_MODE_BOLT:
return send_state_bolt();
case STENO_MODE_GEMINI:
return send_state_gemini();
default:
return false;
}
}
}
}
return true; return true;
} }

@ -7,6 +7,10 @@
#error "must have virtser enabled to use steno" #error "must have virtser enabled to use steno"
#endif #endif
typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t;
bool process_steno(uint16_t keycode, keyrecord_t *record); bool process_steno(uint16_t keycode, keyrecord_t *record);
void steno_init(void);
void steno_set_mode(steno_mode_t mode);
#endif #endif

@ -73,6 +73,8 @@ enum quantum_keycodes {
QK_LAYER_TAP_TOGGLE_MAX = 0x58FF, QK_LAYER_TAP_TOGGLE_MAX = 0x58FF,
#ifdef STENO_ENABLE #ifdef STENO_ENABLE
QK_STENO = 0x5900, QK_STENO = 0x5900,
QK_STENO_BOLT = 0x5930,
QK_STENO_GEMINI = 0x5931,
QK_STENO_MAX = 0x593F, QK_STENO_MAX = 0x593F,
#endif #endif
QK_MOD_TAP = 0x6000, QK_MOD_TAP = 0x6000,

@ -19,6 +19,9 @@ void eeconfig_init(void)
#ifdef RGBLIGHT_ENABLE #ifdef RGBLIGHT_ENABLE
eeprom_update_dword(EECONFIG_RGBLIGHT, 0); eeprom_update_dword(EECONFIG_RGBLIGHT, 0);
#endif #endif
#ifdef STENO_ENABLE
eeprom_update_byte(EECONFIG_STENOMODE, 0);
#endif
} }
void eeconfig_enable(void) void eeconfig_enable(void)

@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define EECONFIG_AUDIO (uint8_t *)7 #define EECONFIG_AUDIO (uint8_t *)7
#define EECONFIG_RGBLIGHT (uint32_t *)8 #define EECONFIG_RGBLIGHT (uint32_t *)8
#define EECONFIG_UNICODEMODE (uint8_t *)12 #define EECONFIG_UNICODEMODE (uint8_t *)12
#define EECONFIG_STENOMODE (uint8_t *)13
/* debug bit */ /* debug bit */

@ -51,6 +51,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef RGBLIGHT_ENABLE #ifdef RGBLIGHT_ENABLE
# include "rgblight.h" # include "rgblight.h"
#endif #endif
#ifdef STENO_ENABLE
# include "process_steno.h"
#endif
#ifdef FAUXCLICKY_ENABLE #ifdef FAUXCLICKY_ENABLE
# include "fauxclicky.h" # include "fauxclicky.h"
#endif #endif
@ -139,6 +142,9 @@ void keyboard_init(void) {
#ifdef RGBLIGHT_ENABLE #ifdef RGBLIGHT_ENABLE
rgblight_init(); rgblight_init();
#endif #endif
#ifdef STENO_ENABLE
steno_init();
#endif
#ifdef FAUXCLICKY_ENABLE #ifdef FAUXCLICKY_ENABLE
fauxclicky_init(); fauxclicky_init();
#endif #endif

Loading…
Cancel
Save