mirror of
https://github.com/qmk/qmk_firmware.git
synced 2026-09-07 10:53:17 +02:00
Initial rework of steno feature (#26273)
This commit is contained in:
@@ -102,23 +102,25 @@ STENO_PROTOCOL ?= all
|
||||
ifeq ($(strip $(STENO_ENABLE)), yes)
|
||||
ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol)
|
||||
else
|
||||
OPT_DEFS += -DSTENO_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), all)
|
||||
override STENO_PROTOCOL := $(filter-out all,$(VALID_STENO_PROTOCOL_TYPES))
|
||||
OPT_DEFS += -DSTENO_ENABLE_ALL
|
||||
endif
|
||||
|
||||
OPT_DEFS += -DNUM_STENO_PROTOCOLS=$(words $(sort $(STENO_PROTOCOL)))
|
||||
|
||||
# for each supported protocol -> add deps
|
||||
ifneq ($(filter $(STENO_PROTOCOL),geminipr),)
|
||||
OPT_DEFS += -DSTENO_ENABLE_GEMINI
|
||||
SRC += $(QUANTUM_DIR)/steno/steno_gemini.c
|
||||
VIRTSER_ENABLE ?= yes
|
||||
endif
|
||||
ifneq ($(filter $(STENO_PROTOCOL),txbolt),)
|
||||
OPT_DEFS += -DSTENO_ENABLE_BOLT
|
||||
SRC += $(QUANTUM_DIR)/steno/steno_bolt.c
|
||||
VIRTSER_ENABLE ?= yes
|
||||
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), geminipr)
|
||||
OPT_DEFS += -DSTENO_ENABLE_GEMINI
|
||||
endif
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), txbolt)
|
||||
OPT_DEFS += -DSTENO_ENABLE_BOLT
|
||||
endif
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), all)
|
||||
OPT_DEFS += -DSTENO_ENABLE_ALL
|
||||
OPT_DEFS += -DSTENO_ENABLE_GEMINI
|
||||
OPT_DEFS += -DSTENO_ENABLE_BOLT
|
||||
endif
|
||||
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_steno.c
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ GENERIC_FEATURES = \
|
||||
SEND_STRING \
|
||||
SEQUENCER \
|
||||
SPACE_CADET \
|
||||
STENO \
|
||||
SWAP_HANDS \
|
||||
TAP_DANCE \
|
||||
TRI_LAYER \
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"ranges": {
|
||||
"0x74C0/0x003F": "!delete!", // Old QK_STENO
|
||||
"0x74C0/0x005F": {
|
||||
"define": "QK_STENO"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,609 @@
|
||||
{
|
||||
"keycodes": {
|
||||
"!reset!":0,
|
||||
|
||||
"0x74C0": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_FUNCTION",
|
||||
"aliases": [
|
||||
"ST_FN"
|
||||
]
|
||||
},
|
||||
"0x74C1": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N1",
|
||||
"aliases": [
|
||||
"ST_N1",
|
||||
"ST_NUM"
|
||||
]
|
||||
},
|
||||
"0x74C2": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N2",
|
||||
"aliases": [
|
||||
"ST_N2"
|
||||
]
|
||||
},
|
||||
"0x74C3": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N3",
|
||||
"aliases": [
|
||||
"ST_N3"
|
||||
]
|
||||
},
|
||||
"0x74C4": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N4",
|
||||
"aliases": [
|
||||
"ST_N4"
|
||||
]
|
||||
},
|
||||
"0x74C5": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N5",
|
||||
"aliases": [
|
||||
"ST_N5"
|
||||
]
|
||||
},
|
||||
"0x74C6": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N6",
|
||||
"aliases": [
|
||||
"ST_N6"
|
||||
]
|
||||
},
|
||||
"0x74C7": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_S1",
|
||||
"aliases": [
|
||||
"ST_S1",
|
||||
"ST_SL"
|
||||
]
|
||||
},
|
||||
"0x74C8": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_S2",
|
||||
"aliases": [
|
||||
"ST_S2"
|
||||
]
|
||||
},
|
||||
"0x74C9": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_TL",
|
||||
"aliases": [
|
||||
"ST_TL"
|
||||
]
|
||||
},
|
||||
"0x74CA": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_KL",
|
||||
"aliases": [
|
||||
"ST_KL"
|
||||
]
|
||||
},
|
||||
"0x74CB": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_PL",
|
||||
"aliases": [
|
||||
"ST_PL"
|
||||
]
|
||||
},
|
||||
"0x74CC": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_WL",
|
||||
"aliases": [
|
||||
"ST_WL"
|
||||
]
|
||||
},
|
||||
"0x74CD": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_HL",
|
||||
"aliases": [
|
||||
"ST_HL"
|
||||
]
|
||||
},
|
||||
"0x74CE": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_RL",
|
||||
"aliases": [
|
||||
"ST_RL"
|
||||
]
|
||||
},
|
||||
"0x74CF": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_A",
|
||||
"aliases": [
|
||||
"ST_A"
|
||||
]
|
||||
},
|
||||
"0x74D0": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_O",
|
||||
"aliases": [
|
||||
"ST_O"
|
||||
]
|
||||
},
|
||||
"0x74D1": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_ST1",
|
||||
"aliases": [
|
||||
"ST_ST1",
|
||||
"ST_STR"
|
||||
]
|
||||
},
|
||||
"0x74D2": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_ST2",
|
||||
"aliases": [
|
||||
"ST_ST2"
|
||||
]
|
||||
},
|
||||
"0x74D3": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_RESET1",
|
||||
"aliases": [
|
||||
"ST_RE1",
|
||||
"ST_RES1"
|
||||
]
|
||||
},
|
||||
"0x74D4": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_RESET2",
|
||||
"aliases": [
|
||||
"ST_RE2",
|
||||
"ST_RES2"
|
||||
]
|
||||
},
|
||||
"0x74D5": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_POWER",
|
||||
"aliases": [
|
||||
"ST_PWR"
|
||||
]
|
||||
},
|
||||
"0x74D6": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_ST3",
|
||||
"aliases": [
|
||||
"ST_ST3"
|
||||
]
|
||||
},
|
||||
"0x74D7": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_ST4",
|
||||
"aliases": [
|
||||
"ST_ST4"
|
||||
]
|
||||
},
|
||||
"0x74D8": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_E",
|
||||
"aliases": [
|
||||
"ST_E"
|
||||
]
|
||||
},
|
||||
"0x74D9": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_U",
|
||||
"aliases": [
|
||||
"ST_U"
|
||||
]
|
||||
},
|
||||
"0x74DA": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_FR",
|
||||
"aliases": [
|
||||
"ST_FR"
|
||||
]
|
||||
},
|
||||
"0x74DB": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_RR",
|
||||
"aliases": [
|
||||
"ST_RR"
|
||||
]
|
||||
},
|
||||
"0x74DC": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_PR",
|
||||
"aliases": [
|
||||
"ST_PR"
|
||||
]
|
||||
},
|
||||
"0x74DD": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_BR",
|
||||
"aliases": [
|
||||
"ST_BR"
|
||||
]
|
||||
},
|
||||
"0x74DE": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_LR",
|
||||
"aliases": [
|
||||
"ST_LR"
|
||||
]
|
||||
},
|
||||
"0x74DF": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_GR",
|
||||
"aliases": [
|
||||
"ST_GR"
|
||||
]
|
||||
},
|
||||
"0x74E0": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_TR",
|
||||
"aliases": [
|
||||
"ST_TR"
|
||||
]
|
||||
},
|
||||
"0x74E1": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_SR",
|
||||
"aliases": [
|
||||
"ST_SR"
|
||||
]
|
||||
},
|
||||
"0x74E2": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_DR",
|
||||
"aliases": [
|
||||
"ST_DR"
|
||||
]
|
||||
},
|
||||
"0x74E3": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N7",
|
||||
"aliases": [
|
||||
"ST_N7"
|
||||
]
|
||||
},
|
||||
"0x74E4": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N8",
|
||||
"aliases": [
|
||||
"ST_N8"
|
||||
]
|
||||
},
|
||||
"0x74E5": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_N9",
|
||||
"aliases": [
|
||||
"ST_N9"
|
||||
]
|
||||
},
|
||||
"0x74E6": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_NA",
|
||||
"aliases": [
|
||||
"ST_NA"
|
||||
]
|
||||
},
|
||||
"0x74E7": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_NB",
|
||||
"aliases": [
|
||||
"ST_NB"
|
||||
]
|
||||
},
|
||||
"0x74E8": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_NC",
|
||||
"aliases": [
|
||||
"ST_NC"
|
||||
]
|
||||
},
|
||||
"0x74E9": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_ZR",
|
||||
"aliases": [
|
||||
"ST_ZR"
|
||||
]
|
||||
},
|
||||
"0x74EA": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X1",
|
||||
"aliases": [
|
||||
"ST_X1"
|
||||
]
|
||||
},
|
||||
"0x74EB": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X2",
|
||||
"aliases": [
|
||||
"ST_X2"
|
||||
]
|
||||
},
|
||||
"0x74EC": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X3",
|
||||
"aliases": [
|
||||
"ST_X3"
|
||||
]
|
||||
},
|
||||
"0x74ED": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X4",
|
||||
"aliases": [
|
||||
"ST_X4"
|
||||
]
|
||||
},
|
||||
"0x74EE": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X5",
|
||||
"aliases": [
|
||||
"ST_X5"
|
||||
]
|
||||
},
|
||||
"0x74EF": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X6",
|
||||
"aliases": [
|
||||
"ST_X6"
|
||||
]
|
||||
},
|
||||
"0x74F0": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X7",
|
||||
"aliases": [
|
||||
"ST_X7"
|
||||
]
|
||||
},
|
||||
"0x74F1": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X8",
|
||||
"aliases": [
|
||||
"ST_X8"
|
||||
]
|
||||
},
|
||||
"0x74F2": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X9",
|
||||
"aliases": [
|
||||
"ST_X9"
|
||||
]
|
||||
},
|
||||
"0x74F3": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X10",
|
||||
"aliases": [
|
||||
"ST_X10"
|
||||
]
|
||||
},
|
||||
"0x74F4": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X11",
|
||||
"aliases": [
|
||||
"ST_X11"
|
||||
]
|
||||
},
|
||||
"0x74F5": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X12",
|
||||
"aliases": [
|
||||
"ST_X12"
|
||||
]
|
||||
},
|
||||
"0x74F6": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X13",
|
||||
"aliases": [
|
||||
"ST_X13"
|
||||
]
|
||||
},
|
||||
"0x74F7": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X14",
|
||||
"aliases": [
|
||||
"ST_X14"
|
||||
]
|
||||
},
|
||||
"0x74F8": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X15",
|
||||
"aliases": [
|
||||
"ST_X15"
|
||||
]
|
||||
},
|
||||
"0x74F9": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X16",
|
||||
"aliases": [
|
||||
"ST_X16"
|
||||
]
|
||||
},
|
||||
"0x74FA": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X17",
|
||||
"aliases": [
|
||||
"ST_X17"
|
||||
]
|
||||
},
|
||||
"0x74FB": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X18",
|
||||
"aliases": [
|
||||
"ST_X18"
|
||||
]
|
||||
},
|
||||
"0x74FC": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X19",
|
||||
"aliases": [
|
||||
"ST_X19"
|
||||
]
|
||||
},
|
||||
"0x74FD": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X20",
|
||||
"aliases": [
|
||||
"ST_X20"
|
||||
]
|
||||
},
|
||||
"0x74FE": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X21",
|
||||
"aliases": [
|
||||
"ST_X21"
|
||||
]
|
||||
},
|
||||
"0x74FF": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X22",
|
||||
"aliases": [
|
||||
"ST_X22"
|
||||
]
|
||||
},
|
||||
"0x7500": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X23",
|
||||
"aliases": [
|
||||
"ST_X23"
|
||||
]
|
||||
},
|
||||
"0x7501": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X24",
|
||||
"aliases": [
|
||||
"ST_X24"
|
||||
]
|
||||
},
|
||||
"0x7502": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X25",
|
||||
"aliases": [
|
||||
"ST_X25"
|
||||
]
|
||||
},
|
||||
"0x7503": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_X26",
|
||||
"aliases": [
|
||||
"ST_X26"
|
||||
]
|
||||
},
|
||||
// 0x7504
|
||||
// 0x7505
|
||||
// 0x7506
|
||||
// 0x7507
|
||||
// 0x7508
|
||||
// 0x7509
|
||||
// 0x750A
|
||||
"0x750B": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_S3",
|
||||
"aliases": [
|
||||
"ST_S3"
|
||||
]
|
||||
},
|
||||
"0x750C": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_TKL",
|
||||
"aliases": [
|
||||
"ST_TKL"
|
||||
]
|
||||
},
|
||||
"0x750D": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_PWL",
|
||||
"aliases": [
|
||||
"ST_PWL"
|
||||
]
|
||||
},
|
||||
"0x750E": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_HRL",
|
||||
"aliases": [
|
||||
"ST_HRL"
|
||||
]
|
||||
},
|
||||
"0x750F": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_FRR",
|
||||
"aliases": [
|
||||
"ST_FRR"
|
||||
]
|
||||
},
|
||||
"0x7510": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_PBR",
|
||||
"aliases": [
|
||||
"ST_PBR"
|
||||
]
|
||||
},
|
||||
"0x7511": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_LGR",
|
||||
"aliases": [
|
||||
"ST_LGR"
|
||||
]
|
||||
},
|
||||
"0x7512": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_TSR",
|
||||
"aliases": [
|
||||
"ST_TSR"
|
||||
]
|
||||
},
|
||||
"0x7513": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_DZR",
|
||||
"aliases": [
|
||||
"ST_DZR"
|
||||
]
|
||||
},
|
||||
"0x7514": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_AO",
|
||||
"aliases": [
|
||||
"ST_AO"
|
||||
]
|
||||
},
|
||||
"0x7515": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_EU",
|
||||
"aliases": [
|
||||
"ST_EU"
|
||||
]
|
||||
},
|
||||
// 0x7516
|
||||
// 0x7517
|
||||
// 0x7518
|
||||
// 0x7519
|
||||
// 0x751A
|
||||
// 0x751B
|
||||
"0x751C": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_MODE_BOLT",
|
||||
"label": "Steno Mode TX Bolt",
|
||||
"aliases": [
|
||||
"ST_BOLT"
|
||||
]
|
||||
},
|
||||
"0x751D": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_MODE_GEMINI",
|
||||
"label": "Steno Mode GeminiPR",
|
||||
"aliases": [
|
||||
"ST_GEMI"
|
||||
]
|
||||
},
|
||||
"0x751E": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_MODE_NEXT",
|
||||
"label": "Steno Mode Next",
|
||||
"aliases": [
|
||||
"ST_NEXT"
|
||||
]
|
||||
},
|
||||
"0x751F": {
|
||||
"group": "steno",
|
||||
"key": "QK_STENO_MODE_PREVIOUS",
|
||||
"label": "Steno Mode Previous",
|
||||
"aliases": [
|
||||
"ST_PREV"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,6 +217,9 @@
|
||||
"SPLIT_ST7565_ENABLE": {"info_key": "split.transport.sync.st7565", "value_type": "flag"},
|
||||
"SPLIT_WPM_ENABLE": {"info_key": "split.transport.sync.wpm", "value_type": "flag"},
|
||||
|
||||
// Stenography
|
||||
"STENO_COMBINEDMAP": {"info_key": "stenography.combined_map", "value_type": "flag"},
|
||||
|
||||
// Tapping
|
||||
"CHORDAL_HOLD": {"info_key": "tapping.chordal_hold", "value_type": "flag"},
|
||||
"FLOW_TAP_TERM": {"info_key": "tapping.flow_tap_term", "value_type": "int"},
|
||||
|
||||
@@ -815,6 +815,17 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"},
|
||||
"combined_map": {"type": "boolean"},
|
||||
"default": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"enum": ["geminipr", "txbolt"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": ["all", "geminipr", "txbolt"]
|
||||
|
||||
@@ -111,7 +111,7 @@ More details can be found here: https://github.com/dnaq/plover-machine-hid
|
||||
|
||||
### Switching protocols on the fly {#switching-protocols-on-the-fly}
|
||||
|
||||
If you wish to switch the serial protocol used to transfer the steno chords without having to recompile your keyboard firmware every time, you can press the `QK_STENO_BOLT` and `QK_STENO_GEMINI` keycodes in order to switch protocols on the fly.
|
||||
If you wish to switch the serial protocol used to transfer the steno chords without having to recompile your keyboard firmware every time, you can press one of the [mode keycodes](#keycode-reference-mode) in order to switch protocols on the fly.
|
||||
|
||||
To enable these special keycodes, add the following lines to your `rules.mk`:
|
||||
```make
|
||||
@@ -123,6 +123,13 @@ If you want to switch protocols programmatically, as part of a custom macro for
|
||||
|
||||
The default protocol is Gemini PR but the last protocol used is stored in non-volatile memory so QMK will remember your choice between reboots of your keyboard — assuming that your keyboard features (emulated) EEPROM.
|
||||
|
||||
To configure the default, add one of the following lines to your `config.h`:
|
||||
|
||||
```c
|
||||
#define STENO_DEFAULT_MODE STENO_MODE_GEMINI
|
||||
#define STENO_DEFAULT_MODE STENO_MODE_BOLT
|
||||
```
|
||||
|
||||
Naturally, this option takes the most amount of firmware space as it needs to compile the code for all the available stenography protocols. In most cases, compiling a single stenography protocol is sufficient.
|
||||
|
||||
The default value for `STENO_PROTOCOL` is `all`.
|
||||
@@ -143,7 +150,7 @@ To test your keymap, you can chord keys on your keyboard and either look at the
|
||||
|
||||
## Learning Stenography {#learning-stenography}
|
||||
|
||||
* [Learn Plover!](https://sites.google.com/site/learnplover/)
|
||||
* [Learn Plover!](https://opensteno.org/learn-plover/)
|
||||
* [Steno Jig](https://joshuagrams.github.io/steno-jig/)
|
||||
* More resources at the Plover [Learning Stenography](https://github.com/openstenoproject/plover/wiki/Learning-Stenography) wiki
|
||||
|
||||
@@ -161,7 +168,7 @@ This function is called when a chord is about to be sent. Mode will be one of `S
|
||||
bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
|
||||
```
|
||||
|
||||
This function is called when a keypress has come in, before it is processed. The keycode should be one of `QK_STENO_BOLT`, `QK_STENO_GEMINI`, or one of the `STN_*` key values.
|
||||
This function is called when a keypress has come in, before it is processed. The keycode should be one of `QK_STENO_MODE_BOLT`, `QK_STENO_MODE_GEMINI`, or one of the `ST_*` key values.
|
||||
|
||||
```c
|
||||
bool post_process_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys);
|
||||
@@ -171,7 +178,7 @@ This function is called after a key has been processed, but before any decision
|
||||
|
||||
If `record->event.pressed` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
|
||||
|
||||
The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[STN_E, STN_U, STN_BR, STN_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice.
|
||||
The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[ST_E, ST_U, ST_BR, ST_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice.
|
||||
|
||||
The `n_pressed_keys` argument is the number of physical keys actually being held down.
|
||||
This is not always equal to the number of bits set to 1 (aka the [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight)) in `chord` because it is possible to simultaneously press down four keys, then release three of those four keys and then press yet another key while the fourth finger is still holding down its key.
|
||||
@@ -180,67 +187,82 @@ At the end of this scenario given as an example, `chord` would have five bits se
|
||||
|
||||
## Keycode Reference {#keycode-reference}
|
||||
|
||||
### Mode {#keycode-reference-mode}
|
||||
|
||||
When more than one protocol is enabled, the following keycodes are available:
|
||||
|
||||
| Key | Aliases | Description |
|
||||
|---------------------------|---------|---------------------------------------------------------------------------|
|
||||
|`QK_STENO_MODE_BOLT` |`ST_BOLT`| Set mode to `STENO_MODE_BOLT` (when multiple protocols are enabled) |
|
||||
|`QK_STENO_MODE_GEMINI` |`ST_GEMI`| Set mode to `STENO_MODE_GEMINI` (when multiple protocols are enabled) |
|
||||
|`QK_STENO_MODE_NEXT` |`ST_NEXT`| Cycle through modes (when multiple protocols are enabled) |
|
||||
|`QK_STENO_MODE_PREVIOUS` |`ST_PREV`| Cycle through modes in reverse (when multiple protocols are enabled) |
|
||||
|
||||
### General {#keycode-reference-general}
|
||||
|
||||
::: info
|
||||
TX Bolt does not support the full set of keys. The TX Bolt implementation in QMK will map the GeminiPR keys to the nearest TX Bolt key so that one key map will work for both.
|
||||
:::
|
||||
|
||||
|GeminiPR|TX Bolt|Steno Key|
|
||||
|--------|-------|-----------|
|
||||
|`STN_N1`|`STN_NUM`|Number bar #1|
|
||||
|`STN_N2`|`STN_NUM`|Number bar #2|
|
||||
|`STN_N3`|`STN_NUM`|Number bar #3|
|
||||
|`STN_N4`|`STN_NUM`|Number bar #4|
|
||||
|`STN_N5`|`STN_NUM`|Number bar #5|
|
||||
|`STN_N6`|`STN_NUM`|Number bar #6|
|
||||
|`STN_N7`|`STN_NUM`|Number bar #7|
|
||||
|`STN_N8`|`STN_NUM`|Number bar #8|
|
||||
|`STN_N9`|`STN_NUM`|Number bar #9|
|
||||
|`STN_NA`|`STN_NUM`|Number bar #A|
|
||||
|`STN_NB`|`STN_NUM`|Number bar #B|
|
||||
|`STN_NC`|`STN_NUM`|Number bar #C|
|
||||
|`STN_S1`|`STN_SL`| `S-` upper|
|
||||
|`STN_S2`|`STN_SL`| `S-` lower|
|
||||
|`STN_TL`|`STN_TL`| `T-`|
|
||||
|`STN_KL`|`STN_KL`| `K-`|
|
||||
|`STN_PL`|`STN_PL`| `P-`|
|
||||
|`STN_WL`|`STN_WL`| `W-`|
|
||||
|`STN_HL`|`STN_HL`| `H-`|
|
||||
|`STN_RL`|`STN_RL`| `R-`|
|
||||
|`STN_A`|`STN_A`| `A` vowel|
|
||||
|`STN_O`|`STN_O`| `O` vowel|
|
||||
|`STN_ST1`|`STN_STR`| `*` upper-left |
|
||||
|`STN_ST2`|`STN_STR`| `*` lower-left|
|
||||
|`STN_ST3`|`STN_STR`| `*` upper-right|
|
||||
|`STN_ST4`|`STN_STR`| `*` lower-right|
|
||||
|`STN_E`|`STN_E`| `E` vowel|
|
||||
|`STN_U`|`STN_U`| `U` vowel|
|
||||
|`STN_FR`|`STN_FR`| `-F`|
|
||||
|`STN_RR`|`STN_RR`| `-R`|
|
||||
|`STN_PR`|`STN_PR`| `-P`|
|
||||
|`STN_BR`|`STN_BR`| `-B`|
|
||||
|`STN_LR`|`STN_LR`| `-L`|
|
||||
|`STN_GR`|`STN_GR`| `-G`|
|
||||
|`STN_TR`|`STN_TR`| `-T`|
|
||||
|`STN_SR`|`STN_SR`| `-S`|
|
||||
|`STN_DR`|`STN_DR`| `-D`|
|
||||
|`STN_ZR`|`STN_ZR`| `-Z`|
|
||||
|`STN_FN`|| (Function)|
|
||||
|`STN_RES1`||(Reset 1)|
|
||||
|`STN_RES2`||(Reset 2)|
|
||||
|`STN_PWR`||(Power)|
|
||||
| Key | GeminiPR | TX Bolt | Description |
|
||||
|---------------------|-----------|----------|-----------------|
|
||||
| `QK_STENO_N1` | `ST_N1` | `ST_NUM` | Number bar #1 |
|
||||
| `QK_STENO_N2` | `ST_N2` | `ST_NUM` | Number bar #2 |
|
||||
| `QK_STENO_N3` | `ST_N3` | `ST_NUM` | Number bar #3 |
|
||||
| `QK_STENO_N4` | `ST_N4` | `ST_NUM` | Number bar #4 |
|
||||
| `QK_STENO_N5` | `ST_N5` | `ST_NUM` | Number bar #5 |
|
||||
| `QK_STENO_N6` | `ST_N6` | `ST_NUM` | Number bar #6 |
|
||||
| `QK_STENO_N7` | `ST_N7` | `ST_NUM` | Number bar #7 |
|
||||
| `QK_STENO_N8` | `ST_N8` | `ST_NUM` | Number bar #8 |
|
||||
| `QK_STENO_N9` | `ST_N9` | `ST_NUM` | Number bar #9 |
|
||||
| `QK_STENO_NA` | `ST_NA` | `ST_NUM` | Number bar #A |
|
||||
| `QK_STENO_NB` | `ST_NB` | `ST_NUM` | Number bar #B |
|
||||
| `QK_STENO_NC` | `ST_NC` | `ST_NUM` | Number bar #C |
|
||||
| `QK_STENO_S1` | `ST_S1` | `ST_SL` | `S-` upper |
|
||||
| `QK_STENO_S2` | `ST_S2` | `ST_SL` | `S-` lower |
|
||||
| `QK_STENO_TL` | `ST_TL` | `ST_TL` | `T-` |
|
||||
| `QK_STENO_KL` | `ST_KL` | `ST_KL` | `K-` |
|
||||
| `QK_STENO_PL` | `ST_PL` | `ST_PL` | `P-` |
|
||||
| `QK_STENO_WL` | `ST_WL` | `ST_WL` | `W-` |
|
||||
| `QK_STENO_HL` | `ST_HL` | `ST_HL` | `H-` |
|
||||
| `QK_STENO_RL` | `ST_RL` | `ST_RL` | `R-` |
|
||||
| `QK_STENO_A` | `ST_A` | `ST_A` | `A` vowel |
|
||||
| `QK_STENO_O` | `ST_O` | `ST_O` | `O` vowel |
|
||||
| `QK_STENO_ST1` | `ST_ST1` | `ST_STR` | `*` upper-left |
|
||||
| `QK_STENO_ST2` | `ST_ST2` | `ST_STR` | `*` lower-left |
|
||||
| `QK_STENO_ST3` | `ST_ST3` | `ST_STR` | `*` upper-right |
|
||||
| `QK_STENO_ST4` | `ST_ST4` | `ST_STR` | `*` lower-right |
|
||||
| `QK_STENO_E` | `ST_E` | `ST_E` | `E` vowel |
|
||||
| `QK_STENO_U` | `ST_U` | `ST_U` | `U` vowel |
|
||||
| `QK_STENO_FR` | `ST_FR` | `ST_FR` | `-F` |
|
||||
| `QK_STENO_RR` | `ST_RR` | `ST_RR` | `-R` |
|
||||
| `QK_STENO_PR` | `ST_PR` | `ST_PR` | `-P` |
|
||||
| `QK_STENO_BR` | `ST_BR` | `ST_BR` | `-B` |
|
||||
| `QK_STENO_LR` | `ST_LR` | `ST_LR` | `-L` |
|
||||
| `QK_STENO_GR` | `ST_GR` | `ST_GR` | `-G` |
|
||||
| `QK_STENO_TR` | `ST_TR` | `ST_TR` | `-T` |
|
||||
| `QK_STENO_SR` | `ST_SR` | `ST_SR` | `-S` |
|
||||
| `QK_STENO_DR` | `ST_DR` | `ST_DR` | `-D` |
|
||||
| `QK_STENO_ZR` | `ST_ZR` | `ST_ZR` | `-Z` |
|
||||
| `QK_STENO_FUNCTION` | `ST_FN` | | (Function) |
|
||||
| `QK_STENO_RESET1` | `ST_RES1` | | (Reset 1) |
|
||||
| `QK_STENO_RESET2` | `ST_RES2` | | (Reset 2) |
|
||||
| `QK_STENO_POWER` | `ST_PWR` | | (Power) |
|
||||
|
||||
### Combined Map {#keycode-reference-combinedmap}
|
||||
|
||||
If you do not want to hit two keys with one finger combined keycodes can be used. These cause both keys to be reported as pressed or released. To use these keycodes define `STENO_COMBINEDMAP` in your `config.h` file.
|
||||
|
||||
|Combined key | Key1 | Key 2 |
|
||||
|---------------|--------|----------|
|
||||
|STN_S3 | STN_S1 | STN_S2 |
|
||||
|STN_TKL | STN_TL | STN_KL |
|
||||
|STN_PWL | STN_PL | STN_WL |
|
||||
|STN_HRL | STN_HL | STN_RL |
|
||||
|STN_FRR | STN_FR | STN_RR |
|
||||
|STN_PBR | STN_PR | STN_BR |
|
||||
|STN_LGR | STN_LR | STN_GR |
|
||||
|STN_TSR | STN_TR | STN_SR |
|
||||
|STN_DZR | STN_DR | STN_ZR |
|
||||
|STN_AO | STN_A | STN_O |
|
||||
|STN_EU | STN_E | STN_U |
|
||||
| Combined key | Aliases | Key 1 | Key 2 |
|
||||
|----------------|----------|---------|---------|
|
||||
| `QK_STENO_S3` | `ST_S3` | `ST_S1` | `ST_S2` |
|
||||
| `QK_STENO_TKL` | `ST_TKL` | `ST_TL` | `ST_KL` |
|
||||
| `QK_STENO_PWL` | `ST_PWL` | `ST_PL` | `ST_WL` |
|
||||
| `QK_STENO_HRL` | `ST_HRL` | `ST_HL` | `ST_RL` |
|
||||
| `QK_STENO_FRR` | `ST_FRR` | `ST_FR` | `ST_RR` |
|
||||
| `QK_STENO_PBR` | `ST_PBR` | `ST_PR` | `ST_BR` |
|
||||
| `QK_STENO_LGR` | `ST_LGR` | `ST_LR` | `ST_GR` |
|
||||
| `QK_STENO_TSR` | `ST_TSR` | `ST_TR` | `ST_SR` |
|
||||
| `QK_STENO_DZR` | `ST_DZR` | `ST_DR` | `ST_ZR` |
|
||||
| `QK_STENO_AO` | `ST_AO` | `ST_A` | `ST_O` |
|
||||
| `QK_STENO_EU` | `ST_EU` | `ST_E` | `ST_U` |
|
||||
|
||||
@@ -728,6 +728,96 @@ See also: [Mod-Tap](mod_tap)
|
||||
|`MEH_T(kc)` | |Left Control, Left Shift and Left Alt when held, `kc` when tapped |
|
||||
|`HYPR_T(kc)` | |Left Control, Left Shift, Left Alt and Left GUI when held, `kc` when tapped|
|
||||
|
||||
## Stenography {#stenography}
|
||||
|
||||
See also: [Stenography](features/stenography)
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|------------------------|-------------------|---------------------------------------------------------------------|
|
||||
|`QK_STENO_FUNCTION` |`ST_FN` |(Function) |
|
||||
|`QK_STENO_N1` |`ST_N1`, `ST_NUM` |Number bar #1 |
|
||||
|`QK_STENO_N2` |`ST_N2` |Number bar #2 |
|
||||
|`QK_STENO_N3` |`ST_N3` |Number bar #3 |
|
||||
|`QK_STENO_N4` |`ST_N4` |Number bar #4 |
|
||||
|`QK_STENO_N5` |`ST_N5` |Number bar #5 |
|
||||
|`QK_STENO_N6` |`ST_N6` |Number bar #6 |
|
||||
|`QK_STENO_S1` |`ST_S1`, `ST_SL` |`S-` upper |
|
||||
|`QK_STENO_S2` |`ST_S2` |`S-` lower |
|
||||
|`QK_STENO_TL` |`ST_TL` |`T-` |
|
||||
|`QK_STENO_KL` |`ST_KL` |`K-` |
|
||||
|`QK_STENO_PL` |`ST_PL` |`P-` |
|
||||
|`QK_STENO_WL` |`ST_WL` |`W-` |
|
||||
|`QK_STENO_HL` |`ST_HL` |`H-` |
|
||||
|`QK_STENO_RL` |`ST_RL` |`R-` |
|
||||
|`QK_STENO_A` |`ST_A` |`A` vowel |
|
||||
|`QK_STENO_O` |`ST_O` |`O` vowel |
|
||||
|`QK_STENO_ST1` |`ST_ST1`, `ST_STR` |`*` upper-left |
|
||||
|`QK_STENO_ST2` |`ST_ST2` |`*` lower-left |
|
||||
|`QK_STENO_RESET1` |`ST_RE1`, `ST_RES1`|(Reset 1) |
|
||||
|`QK_STENO_RESET2` |`ST_RE2`, `ST_RES2`|(Reset 2) |
|
||||
|`QK_STENO_POWER` |`ST_PWR` |(Power) |
|
||||
|`QK_STENO_ST3` |`ST_ST3` |`*` upper-right |
|
||||
|`QK_STENO_ST4` |`ST_ST4` |`*` lower-right |
|
||||
|`QK_STENO_E` |`ST_E` |`E` vowel |
|
||||
|`QK_STENO_U` |`ST_U` |`U` vowel |
|
||||
|`QK_STENO_FR` |`ST_FR` |`-F` |
|
||||
|`QK_STENO_RR` |`ST_RR` |`-R` |
|
||||
|`QK_STENO_PR` |`ST_PR` |`-P` |
|
||||
|`QK_STENO_BR` |`ST_BR` |`-B` |
|
||||
|`QK_STENO_LR` |`ST_LR` |`-L` |
|
||||
|`QK_STENO_GR` |`ST_GR` |`-G` |
|
||||
|`QK_STENO_TR` |`ST_TR` |`-T` |
|
||||
|`QK_STENO_SR` |`ST_SR` |`-S` |
|
||||
|`QK_STENO_DR` |`ST_DR` |`-D` |
|
||||
|`QK_STENO_N7` |`ST_N7` |Number bar #7 |
|
||||
|`QK_STENO_N8` |`ST_N8` |Number bar #8 |
|
||||
|`QK_STENO_N9` |`ST_N9` |Number bar #9 |
|
||||
|`QK_STENO_NA` |`ST_NA` |Number bar #A |
|
||||
|`QK_STENO_NB` |`ST_NB` |Number bar #B |
|
||||
|`QK_STENO_NC` |`ST_NC` |Number bar #C |
|
||||
|`QK_STENO_ZR` |`ST_ZR` |`-Z` |
|
||||
|`QK_STENO_X1` |`ST_X1` |Extra button 1 (Protocol specific) |
|
||||
|`QK_STENO_X2` |`ST_X2` |Extra button 2 (Protocol specific) |
|
||||
|`QK_STENO_X3` |`ST_X3` |Extra button 3 (Protocol specific) |
|
||||
|`QK_STENO_X4` |`ST_X4` |Extra button 4 (Protocol specific) |
|
||||
|`QK_STENO_X5` |`ST_X5` |Extra button 5 (Protocol specific) |
|
||||
|`QK_STENO_X6` |`ST_X6` |Extra button 6 (Protocol specific) |
|
||||
|`QK_STENO_X7` |`ST_X7` |Extra button 7 (Protocol specific) |
|
||||
|`QK_STENO_X8` |`ST_X8` |Extra button 8 (Protocol specific) |
|
||||
|`QK_STENO_X9` |`ST_X9` |Extra button 9 (Protocol specific) |
|
||||
|`QK_STENO_X10` |`ST_X10` |Extra button 10 (Protocol specific) |
|
||||
|`QK_STENO_X11` |`ST_X11` |Extra button 11 (Protocol specific) |
|
||||
|`QK_STENO_X12` |`ST_X12` |Extra button 12 (Protocol specific) |
|
||||
|`QK_STENO_X13` |`ST_X13` |Extra button 13 (Protocol specific) |
|
||||
|`QK_STENO_X14` |`ST_X14` |Extra button 14 (Protocol specific) |
|
||||
|`QK_STENO_X15` |`ST_X15` |Extra button 15 (Protocol specific) |
|
||||
|`QK_STENO_X16` |`ST_X16` |Extra button 16 (Protocol specific) |
|
||||
|`QK_STENO_X17` |`ST_X17` |Extra button 17 (Protocol specific) |
|
||||
|`QK_STENO_X18` |`ST_X18` |Extra button 18 (Protocol specific) |
|
||||
|`QK_STENO_X19` |`ST_X19` |Extra button 19 (Protocol specific) |
|
||||
|`QK_STENO_X20` |`ST_X20` |Extra button 20 (Protocol specific) |
|
||||
|`QK_STENO_X21` |`ST_X21` |Extra button 21 (Protocol specific) |
|
||||
|`QK_STENO_X22` |`ST_X22` |Extra button 22 (Protocol specific) |
|
||||
|`QK_STENO_X23` |`ST_X23` |Extra button 23 (Protocol specific) |
|
||||
|`QK_STENO_X24` |`ST_X24` |Extra button 24 (Protocol specific) |
|
||||
|`QK_STENO_X25` |`ST_X25` |Extra button 25 (Protocol specific) |
|
||||
|`QK_STENO_X26` |`ST_X26` |Extra button 26 (Protocol specific) |
|
||||
|`QK_STENO_S3` |`ST_S3` |Trigger `ST_S1` and `ST_S2` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_TKL` |`ST_TKL` |Trigger `ST_TL` and `ST_KL` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_PWL` |`ST_PWL` |Trigger `ST_PL` and `ST_WL` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_HRL` |`ST_HRL` |Trigger `ST_HL` and `ST_RL` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_FRR` |`ST_FRR` |Trigger `ST_FR` and `ST_RR` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_PBR` |`ST_PBR` |Trigger `ST_PR` and `ST_BR` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_LGR` |`ST_LGR` |Trigger `ST_LR` and `ST_GR` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_TSR` |`ST_TSR` |Trigger `ST_TR` and `ST_SR` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_DZR` |`ST_DZR` |Trigger `ST_DR` and `ST_ZR` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_AO` |`ST_AO` |Trigger `ST_A` and `ST_O` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_EU` |`ST_EU` |Trigger `ST_E` and `ST_U` (when *Combined Map* is enabled) |
|
||||
|`QK_STENO_MODE_BOLT` |`ST_BOLT` |Set mode to `STENO_MODE_BOLT` (when multiple protocols are enabled) |
|
||||
|`QK_STENO_MODE_GEMINI` |`ST_GEMI` |Set mode to `STENO_MODE_GEMINI` (when multiple protocols are enabled)|
|
||||
|`QK_STENO_MODE_NEXT` |`ST_NEXT` |Cycle through modes (when multiple protocols are enabled) |
|
||||
|`QK_STENO_MODE_PREVIOUS`|`ST_PREV` |Cycle through modes in reverse (when multiple protocols are enabled) |
|
||||
|
||||
## Tapping Term Keys {#tapping-term-keys}
|
||||
|
||||
See also: [Dynamic Tapping Term](tap_hold#dynamic-tapping-term)
|
||||
|
||||
@@ -866,6 +866,13 @@ Configures the [Stenography](features/stenography) feature.
|
||||
* `enabled` <Badge type="info">Boolean</Badge>
|
||||
* Enable the Stenography feature.
|
||||
* Default: `false`
|
||||
* `combined_map` <Badge type="info">Boolean</Badge>
|
||||
* Enable the Stenography Combined Map sub-feature.
|
||||
* Default: `false`
|
||||
* `default`
|
||||
* `mode` <Badge type="info">String</Badge>
|
||||
* The default mode. Must be one of `geminipr`, `txbolt`.
|
||||
* Default: `"geminipr"` when available, otherwise `"txbolt"`
|
||||
* `protocol` <Badge type="info">String</Badge>
|
||||
* The Steno protocol to use. Must be one of `all`, `geminipr`, `txbolt`.
|
||||
* Default: `"all"`
|
||||
|
||||
@@ -170,6 +170,18 @@ def generate_led_animations_config(feature, led_feature_json, config_h_lines, en
|
||||
config_h_lines.append(generate_flag(f'{enable_prefix}{animation.upper()}', led_feature_json['animations'][animation]))
|
||||
|
||||
|
||||
def generate_stenography_config(kb_info_json, config_h_lines):
|
||||
"""Generate the config.h lines for stenography."""
|
||||
if 'mode' in kb_info_json['stenography'].get('default', {}):
|
||||
mode_map = {
|
||||
'geminipr': 'STENO_MODE_GEMINI',
|
||||
'txbolt': 'STENO_MODE_BOLT',
|
||||
}
|
||||
mode = kb_info_json['stenography']['default']['mode']
|
||||
value = mode_map.get(mode, f'STENO_MODE_{mode.upper()}')
|
||||
config_h_lines.append(generate_define('STENO_DEFAULT_MODE', value))
|
||||
|
||||
|
||||
@cli.argument('filename', nargs='?', arg_only=True, type=FileType('r'), completer=FilesCompleter('.json'), help='A configurator export JSON to be compiled and flashed or a pre-compiled binary firmware file (bin/hex) to be flashed.')
|
||||
@cli.argument('-o', '--output', arg_only=True, type=normpath, help='File to write to')
|
||||
@cli.argument('-q', '--quiet', arg_only=True, action='store_true', help="Quiet mode, only output error messages")
|
||||
@@ -214,5 +226,8 @@ def generate_config_h(cli):
|
||||
if 'rgblight' in kb_info_json:
|
||||
generate_led_animations_config('rgblight', kb_info_json['rgblight'], config_h_lines, 'RGBLIGHT_EFFECT_', 'RGBLIGHT_MODE_')
|
||||
|
||||
if 'stenography' in kb_info_json:
|
||||
generate_stenography_config(kb_info_json, config_h_lines)
|
||||
|
||||
# Show the results
|
||||
dump_lines(cli.args.output, config_h_lines, cli.args.quiet)
|
||||
|
||||
+2
-1
@@ -120,7 +120,8 @@ void eeconfig_init_quantum(void) {
|
||||
#endif // UNICODE_COMMON_ENABLE
|
||||
|
||||
#ifdef STENO_ENABLE
|
||||
eeconfig_update_steno_mode(0);
|
||||
extern void eeconfig_update_steno_default(void);
|
||||
eeconfig_update_steno_default();
|
||||
#endif // STENO_ENABLE
|
||||
|
||||
#ifdef RGB_MATRIX_ENABLE
|
||||
|
||||
+2
-2
@@ -76,7 +76,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# include "process_tap_dance.h"
|
||||
#endif
|
||||
#ifdef STENO_ENABLE
|
||||
# include "process_steno.h"
|
||||
# include "steno.h"
|
||||
#endif
|
||||
#ifdef KEY_OVERRIDE_ENABLE
|
||||
# include "process_key_override.h"
|
||||
@@ -512,7 +512,7 @@ void keyboard_init(void) {
|
||||
#ifdef RGBLIGHT_ENABLE
|
||||
rgblight_init();
|
||||
#endif
|
||||
#ifdef STENO_ENABLE_ALL
|
||||
#ifdef STENO_ENABLE
|
||||
steno_init();
|
||||
#endif
|
||||
#ifdef DIP_SWITCH_ENABLE
|
||||
|
||||
+174
-7
@@ -79,7 +79,7 @@ enum qk_keycode_ranges {
|
||||
QK_AUDIO = 0x7480,
|
||||
QK_AUDIO_MAX = 0x74BF,
|
||||
QK_STENO = 0x74C0,
|
||||
QK_STENO_MAX = 0x74FF,
|
||||
QK_STENO_MAX = 0x751F,
|
||||
QK_MACRO = 0x7700,
|
||||
QK_MACRO_MAX = 0x777F,
|
||||
QK_CONNECTION = 0x7780,
|
||||
@@ -662,10 +662,89 @@ enum qk_keycode_defines {
|
||||
QK_MUSIC_MODE_NEXT = 0x7493,
|
||||
QK_AUDIO_VOICE_NEXT = 0x7494,
|
||||
QK_AUDIO_VOICE_PREVIOUS = 0x7495,
|
||||
QK_STENO_BOLT = 0x74F0,
|
||||
QK_STENO_GEMINI = 0x74F1,
|
||||
QK_STENO_COMB = 0x74F2,
|
||||
QK_STENO_COMB_MAX = 0x74FC,
|
||||
QK_STENO_FUNCTION = 0x74C0,
|
||||
QK_STENO_N1 = 0x74C1,
|
||||
QK_STENO_N2 = 0x74C2,
|
||||
QK_STENO_N3 = 0x74C3,
|
||||
QK_STENO_N4 = 0x74C4,
|
||||
QK_STENO_N5 = 0x74C5,
|
||||
QK_STENO_N6 = 0x74C6,
|
||||
QK_STENO_S1 = 0x74C7,
|
||||
QK_STENO_S2 = 0x74C8,
|
||||
QK_STENO_TL = 0x74C9,
|
||||
QK_STENO_KL = 0x74CA,
|
||||
QK_STENO_PL = 0x74CB,
|
||||
QK_STENO_WL = 0x74CC,
|
||||
QK_STENO_HL = 0x74CD,
|
||||
QK_STENO_RL = 0x74CE,
|
||||
QK_STENO_A = 0x74CF,
|
||||
QK_STENO_O = 0x74D0,
|
||||
QK_STENO_ST1 = 0x74D1,
|
||||
QK_STENO_ST2 = 0x74D2,
|
||||
QK_STENO_RESET1 = 0x74D3,
|
||||
QK_STENO_RESET2 = 0x74D4,
|
||||
QK_STENO_POWER = 0x74D5,
|
||||
QK_STENO_ST3 = 0x74D6,
|
||||
QK_STENO_ST4 = 0x74D7,
|
||||
QK_STENO_E = 0x74D8,
|
||||
QK_STENO_U = 0x74D9,
|
||||
QK_STENO_FR = 0x74DA,
|
||||
QK_STENO_RR = 0x74DB,
|
||||
QK_STENO_PR = 0x74DC,
|
||||
QK_STENO_BR = 0x74DD,
|
||||
QK_STENO_LR = 0x74DE,
|
||||
QK_STENO_GR = 0x74DF,
|
||||
QK_STENO_TR = 0x74E0,
|
||||
QK_STENO_SR = 0x74E1,
|
||||
QK_STENO_DR = 0x74E2,
|
||||
QK_STENO_N7 = 0x74E3,
|
||||
QK_STENO_N8 = 0x74E4,
|
||||
QK_STENO_N9 = 0x74E5,
|
||||
QK_STENO_NA = 0x74E6,
|
||||
QK_STENO_NB = 0x74E7,
|
||||
QK_STENO_NC = 0x74E8,
|
||||
QK_STENO_ZR = 0x74E9,
|
||||
QK_STENO_X1 = 0x74EA,
|
||||
QK_STENO_X2 = 0x74EB,
|
||||
QK_STENO_X3 = 0x74EC,
|
||||
QK_STENO_X4 = 0x74ED,
|
||||
QK_STENO_X5 = 0x74EE,
|
||||
QK_STENO_X6 = 0x74EF,
|
||||
QK_STENO_X7 = 0x74F0,
|
||||
QK_STENO_X8 = 0x74F1,
|
||||
QK_STENO_X9 = 0x74F2,
|
||||
QK_STENO_X10 = 0x74F3,
|
||||
QK_STENO_X11 = 0x74F4,
|
||||
QK_STENO_X12 = 0x74F5,
|
||||
QK_STENO_X13 = 0x74F6,
|
||||
QK_STENO_X14 = 0x74F7,
|
||||
QK_STENO_X15 = 0x74F8,
|
||||
QK_STENO_X16 = 0x74F9,
|
||||
QK_STENO_X17 = 0x74FA,
|
||||
QK_STENO_X18 = 0x74FB,
|
||||
QK_STENO_X19 = 0x74FC,
|
||||
QK_STENO_X20 = 0x74FD,
|
||||
QK_STENO_X21 = 0x74FE,
|
||||
QK_STENO_X22 = 0x74FF,
|
||||
QK_STENO_X23 = 0x7500,
|
||||
QK_STENO_X24 = 0x7501,
|
||||
QK_STENO_X25 = 0x7502,
|
||||
QK_STENO_X26 = 0x7503,
|
||||
QK_STENO_S3 = 0x750B,
|
||||
QK_STENO_TKL = 0x750C,
|
||||
QK_STENO_PWL = 0x750D,
|
||||
QK_STENO_HRL = 0x750E,
|
||||
QK_STENO_FRR = 0x750F,
|
||||
QK_STENO_PBR = 0x7510,
|
||||
QK_STENO_LGR = 0x7511,
|
||||
QK_STENO_TSR = 0x7512,
|
||||
QK_STENO_DZR = 0x7513,
|
||||
QK_STENO_AO = 0x7514,
|
||||
QK_STENO_EU = 0x7515,
|
||||
QK_STENO_MODE_BOLT = 0x751C,
|
||||
QK_STENO_MODE_GEMINI = 0x751D,
|
||||
QK_STENO_MODE_NEXT = 0x751E,
|
||||
QK_STENO_MODE_PREVIOUS = 0x751F,
|
||||
QK_MACRO_0 = 0x7700,
|
||||
QK_MACRO_1 = 0x7701,
|
||||
QK_MACRO_2 = 0x7702,
|
||||
@@ -1359,6 +1438,94 @@ enum qk_keycode_defines {
|
||||
MU_NEXT = QK_MUSIC_MODE_NEXT,
|
||||
AU_NEXT = QK_AUDIO_VOICE_NEXT,
|
||||
AU_PREV = QK_AUDIO_VOICE_PREVIOUS,
|
||||
ST_FN = QK_STENO_FUNCTION,
|
||||
ST_N1 = QK_STENO_N1,
|
||||
ST_NUM = QK_STENO_N1,
|
||||
ST_N2 = QK_STENO_N2,
|
||||
ST_N3 = QK_STENO_N3,
|
||||
ST_N4 = QK_STENO_N4,
|
||||
ST_N5 = QK_STENO_N5,
|
||||
ST_N6 = QK_STENO_N6,
|
||||
ST_S1 = QK_STENO_S1,
|
||||
ST_SL = QK_STENO_S1,
|
||||
ST_S2 = QK_STENO_S2,
|
||||
ST_TL = QK_STENO_TL,
|
||||
ST_KL = QK_STENO_KL,
|
||||
ST_PL = QK_STENO_PL,
|
||||
ST_WL = QK_STENO_WL,
|
||||
ST_HL = QK_STENO_HL,
|
||||
ST_RL = QK_STENO_RL,
|
||||
ST_A = QK_STENO_A,
|
||||
ST_O = QK_STENO_O,
|
||||
ST_ST1 = QK_STENO_ST1,
|
||||
ST_STR = QK_STENO_ST1,
|
||||
ST_ST2 = QK_STENO_ST2,
|
||||
ST_RE1 = QK_STENO_RESET1,
|
||||
ST_RES1 = QK_STENO_RESET1,
|
||||
ST_RE2 = QK_STENO_RESET2,
|
||||
ST_RES2 = QK_STENO_RESET2,
|
||||
ST_PWR = QK_STENO_POWER,
|
||||
ST_ST3 = QK_STENO_ST3,
|
||||
ST_ST4 = QK_STENO_ST4,
|
||||
ST_E = QK_STENO_E,
|
||||
ST_U = QK_STENO_U,
|
||||
ST_FR = QK_STENO_FR,
|
||||
ST_RR = QK_STENO_RR,
|
||||
ST_PR = QK_STENO_PR,
|
||||
ST_BR = QK_STENO_BR,
|
||||
ST_LR = QK_STENO_LR,
|
||||
ST_GR = QK_STENO_GR,
|
||||
ST_TR = QK_STENO_TR,
|
||||
ST_SR = QK_STENO_SR,
|
||||
ST_DR = QK_STENO_DR,
|
||||
ST_N7 = QK_STENO_N7,
|
||||
ST_N8 = QK_STENO_N8,
|
||||
ST_N9 = QK_STENO_N9,
|
||||
ST_NA = QK_STENO_NA,
|
||||
ST_NB = QK_STENO_NB,
|
||||
ST_NC = QK_STENO_NC,
|
||||
ST_ZR = QK_STENO_ZR,
|
||||
ST_X1 = QK_STENO_X1,
|
||||
ST_X2 = QK_STENO_X2,
|
||||
ST_X3 = QK_STENO_X3,
|
||||
ST_X4 = QK_STENO_X4,
|
||||
ST_X5 = QK_STENO_X5,
|
||||
ST_X6 = QK_STENO_X6,
|
||||
ST_X7 = QK_STENO_X7,
|
||||
ST_X8 = QK_STENO_X8,
|
||||
ST_X9 = QK_STENO_X9,
|
||||
ST_X10 = QK_STENO_X10,
|
||||
ST_X11 = QK_STENO_X11,
|
||||
ST_X12 = QK_STENO_X12,
|
||||
ST_X13 = QK_STENO_X13,
|
||||
ST_X14 = QK_STENO_X14,
|
||||
ST_X15 = QK_STENO_X15,
|
||||
ST_X16 = QK_STENO_X16,
|
||||
ST_X17 = QK_STENO_X17,
|
||||
ST_X18 = QK_STENO_X18,
|
||||
ST_X19 = QK_STENO_X19,
|
||||
ST_X20 = QK_STENO_X20,
|
||||
ST_X21 = QK_STENO_X21,
|
||||
ST_X22 = QK_STENO_X22,
|
||||
ST_X23 = QK_STENO_X23,
|
||||
ST_X24 = QK_STENO_X24,
|
||||
ST_X25 = QK_STENO_X25,
|
||||
ST_X26 = QK_STENO_X26,
|
||||
ST_S3 = QK_STENO_S3,
|
||||
ST_TKL = QK_STENO_TKL,
|
||||
ST_PWL = QK_STENO_PWL,
|
||||
ST_HRL = QK_STENO_HRL,
|
||||
ST_FRR = QK_STENO_FRR,
|
||||
ST_PBR = QK_STENO_PBR,
|
||||
ST_LGR = QK_STENO_LGR,
|
||||
ST_TSR = QK_STENO_TSR,
|
||||
ST_DZR = QK_STENO_DZR,
|
||||
ST_AO = QK_STENO_AO,
|
||||
ST_EU = QK_STENO_EU,
|
||||
ST_BOLT = QK_STENO_MODE_BOLT,
|
||||
ST_GEMI = QK_STENO_MODE_GEMINI,
|
||||
ST_NEXT = QK_STENO_MODE_NEXT,
|
||||
ST_PREV = QK_STENO_MODE_PREVIOUS,
|
||||
MC_0 = QK_MACRO_0,
|
||||
MC_1 = QK_MACRO_1,
|
||||
MC_2 = QK_MACRO_2,
|
||||
@@ -1583,7 +1750,7 @@ enum qk_keycode_defines {
|
||||
#define IS_JOYSTICK_KEYCODE(code) ((code) >= QK_JOYSTICK_BUTTON_0 && (code) <= QK_JOYSTICK_BUTTON_31)
|
||||
#define IS_PROGRAMMABLE_BUTTON_KEYCODE(code) ((code) >= QK_PROGRAMMABLE_BUTTON_1 && (code) <= QK_PROGRAMMABLE_BUTTON_32)
|
||||
#define IS_AUDIO_KEYCODE(code) ((code) >= QK_AUDIO_ON && (code) <= QK_AUDIO_VOICE_PREVIOUS)
|
||||
#define IS_STENO_KEYCODE(code) ((code) >= QK_STENO_BOLT && (code) <= QK_STENO_COMB_MAX)
|
||||
#define IS_STENO_KEYCODE(code) ((code) >= QK_STENO_FUNCTION && (code) <= QK_STENO_MODE_PREVIOUS)
|
||||
#define IS_MACRO_KEYCODE(code) ((code) >= QK_MACRO_0 && (code) <= QK_MACRO_31)
|
||||
#define IS_CONNECTION_KEYCODE(code) ((code) >= QK_OUTPUT_AUTO && (code) <= QK_BLUETOOTH_PROFILE5)
|
||||
#define IS_BACKLIGHT_KEYCODE(code) ((code) >= QK_BACKLIGHT_ON && (code) <= QK_BACKLIGHT_TOGGLE_BREATHING)
|
||||
@@ -1610,7 +1777,7 @@ enum qk_keycode_defines {
|
||||
#define JOYSTICK_KEYCODE_RANGE QK_JOYSTICK_BUTTON_0 ... QK_JOYSTICK_BUTTON_31
|
||||
#define PROGRAMMABLE_BUTTON_KEYCODE_RANGE QK_PROGRAMMABLE_BUTTON_1 ... QK_PROGRAMMABLE_BUTTON_32
|
||||
#define AUDIO_KEYCODE_RANGE QK_AUDIO_ON ... QK_AUDIO_VOICE_PREVIOUS
|
||||
#define STENO_KEYCODE_RANGE QK_STENO_BOLT ... QK_STENO_COMB_MAX
|
||||
#define STENO_KEYCODE_RANGE QK_STENO_FUNCTION ... QK_STENO_MODE_PREVIOUS
|
||||
#define MACRO_KEYCODE_RANGE QK_MACRO_0 ... QK_MACRO_31
|
||||
#define CONNECTION_KEYCODE_RANGE QK_OUTPUT_AUTO ... QK_BLUETOOTH_PROFILE5
|
||||
#define BACKLIGHT_KEYCODE_RANGE QK_BACKLIGHT_ON ... QK_BACKLIGHT_TOGGLE_BREATHING
|
||||
|
||||
@@ -1,29 +1,24 @@
|
||||
/* Copyright 2017, 2022 Joseph Wasson, Vladislav Kucheriavykh
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Copyright 2017, 2022 Joseph Wasson, Vladislav Kucheriavykh
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "process_steno.h"
|
||||
#include "quantum_keycodes.h"
|
||||
#include "eeconfig.h"
|
||||
#include <string.h>
|
||||
#ifdef VIRTSER_ENABLE
|
||||
# include "virtser.h"
|
||||
#include "steno.h"
|
||||
#include "progmem.h"
|
||||
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
void steno_add_key_to_chord_bolt(uint8_t chord[MAX_STROKE_SIZE], uint8_t key);
|
||||
void steno_send_chord_bolt(uint8_t chord[MAX_STROKE_SIZE]);
|
||||
#endif
|
||||
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
void steno_add_key_to_chord_gemini(uint8_t chord[MAX_STROKE_SIZE], uint8_t key);
|
||||
void steno_send_chord_gemini(uint8_t chord[MAX_STROKE_SIZE]);
|
||||
#endif
|
||||
|
||||
// All steno keys that have been pressed to form this chord,
|
||||
// stored in MAX_STROKE_SIZE groups of 8-bit arrays.
|
||||
static uint8_t chord[MAX_STROKE_SIZE] = {0};
|
||||
extern uint8_t steno_current_chord[MAX_STROKE_SIZE];
|
||||
|
||||
// The number of physical keys actually being held down.
|
||||
// This is not always equal to the number of 1 bits in `chord` because it is possible to
|
||||
// simultaneously press down four keys, then release three of those four keys and then press yet
|
||||
@@ -32,109 +27,21 @@ static uint8_t chord[MAX_STROKE_SIZE] = {0};
|
||||
// `n_pressed_keys` would be set to 2 because there are only two keys currently being pressed down.
|
||||
static int8_t n_pressed_keys = 0;
|
||||
|
||||
#ifdef STENO_ENABLE_ALL
|
||||
static steno_mode_t mode;
|
||||
#elif defined(STENO_ENABLE_GEMINI)
|
||||
static const steno_mode_t mode = STENO_MODE_GEMINI;
|
||||
#elif defined(STENO_ENABLE_BOLT)
|
||||
static const steno_mode_t mode = STENO_MODE_BOLT;
|
||||
#endif
|
||||
|
||||
static inline void steno_clear_chord(void) {
|
||||
memset(chord, 0, sizeof(chord));
|
||||
}
|
||||
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
|
||||
# ifdef VIRTSER_ENABLE
|
||||
void send_steno_chord_gemini(void) {
|
||||
// Set MSB to 1 to indicate the start of packet
|
||||
chord[0] |= 0x80;
|
||||
for (uint8_t i = 0; i < GEMINI_STROKE_SIZE; ++i) {
|
||||
virtser_send(chord[i]);
|
||||
}
|
||||
}
|
||||
# else
|
||||
# pragma message "VIRTSER_ENABLE = yes is required for Gemini PR to work properly out of the box!"
|
||||
# endif // VIRTSER_ENABLE
|
||||
|
||||
/**
|
||||
* @precondition: `key` is pressed
|
||||
*/
|
||||
bool add_gemini_key_to_chord(uint8_t key) {
|
||||
// Although each group of the packet is 8 bits long, the MSB is reserved
|
||||
// to indicate whether that byte is the first byte of the packet (MSB=1)
|
||||
// or one of the remaining five bytes of the packet (MSB=0).
|
||||
// As a consequence, only 7 out of the 8 bits are left to be used as a bit array
|
||||
// for the steno keys of that group.
|
||||
const int group_idx = key / 7;
|
||||
const int intra_group_idx = key - group_idx * 7;
|
||||
// The 0th steno key of the group has bit=0b01000000, the 1st has bit=0b00100000, etc.
|
||||
const uint8_t bit = 1 << (6 - intra_group_idx);
|
||||
chord[group_idx] |= bit;
|
||||
return false;
|
||||
}
|
||||
#endif // STENO_ENABLE_GEMINI
|
||||
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
|
||||
# define TXB_GRP0 0b00000000
|
||||
# define TXB_GRP1 0b01000000
|
||||
# define TXB_GRP2 0b10000000
|
||||
# define TXB_GRP3 0b11000000
|
||||
# define TXB_GRPMASK 0b11000000
|
||||
|
||||
# define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6)
|
||||
|
||||
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};
|
||||
|
||||
# ifdef VIRTSER_ENABLE
|
||||
static void send_steno_chord_bolt(void) {
|
||||
for (uint8_t i = 0; i < BOLT_STROKE_SIZE; ++i) {
|
||||
// TX Bolt uses variable length packets where each byte corresponds to a bit array of certain keys.
|
||||
// If a user chorded the keys of the first group with keys of the last group, for example, there
|
||||
// would be bytes of 0x00 in `chord` for the middle groups which we mustn't send.
|
||||
if (chord[i]) {
|
||||
virtser_send(chord[i]);
|
||||
}
|
||||
}
|
||||
// Sending a null packet is not always necessary, but it is simpler and more reliable
|
||||
// to unconditionally send it every time instead of keeping track of more states and
|
||||
// creating more branches in the execution of the program.
|
||||
virtser_send(0);
|
||||
}
|
||||
# else
|
||||
# pragma message "VIRTSER_ENABLE = yes is required for TX Bolt to work properly out of the box!"
|
||||
# endif // VIRTSER_ENABLE
|
||||
|
||||
/**
|
||||
* @precondition: `key` is pressed
|
||||
*/
|
||||
static bool add_bolt_key_to_chord(uint8_t key) {
|
||||
uint8_t boltcode = pgm_read_byte(boltmap + key);
|
||||
chord[TXB_GET_GROUP(boltcode)] |= boltcode;
|
||||
return false;
|
||||
}
|
||||
#endif // STENO_ENABLE_BOLT
|
||||
|
||||
#ifdef STENO_COMBINEDMAP
|
||||
/* Used to look up when pressing the middle row key to combine two consonant or vowel keys */
|
||||
static const uint16_t combinedmap_first[] PROGMEM = {STN_S1, STN_TL, STN_PL, STN_HL, STN_FR, STN_PR, STN_LR, STN_TR, STN_DR, STN_A, STN_E};
|
||||
static const uint16_t combinedmap_second[] PROGMEM = {STN_S2, STN_KL, STN_WL, STN_RL, STN_RR, STN_BR, STN_GR, STN_SR, STN_ZR, STN_O, STN_U};
|
||||
// Used to look up when pressing the middle row key to combine two consonant or vowel keys
|
||||
static const uint16_t combinedmap_first[] PROGMEM = {QK_STENO_S1, QK_STENO_TL, QK_STENO_PL, QK_STENO_HL, QK_STENO_FR, QK_STENO_PR, QK_STENO_LR, QK_STENO_TR, QK_STENO_DR, QK_STENO_A, QK_STENO_E};
|
||||
static const uint16_t combinedmap_second[] PROGMEM = {QK_STENO_S2, QK_STENO_KL, QK_STENO_WL, QK_STENO_RL, QK_STENO_RR, QK_STENO_BR, QK_STENO_GR, QK_STENO_SR, QK_STENO_ZR, QK_STENO_O, QK_STENO_U};
|
||||
|
||||
static bool process_steno_combinedmap(uint16_t keycode, keyrecord_t *record) {
|
||||
uint16_t first_keycode = pgm_read_word(&combinedmap_first[keycode - QK_STENO_S3]);
|
||||
uint16_t second_keycode = pgm_read_word(&combinedmap_second[keycode - QK_STENO_S3]);
|
||||
|
||||
bool first_result = process_steno(first_keycode, record);
|
||||
bool second_result = process_steno(second_keycode, record);
|
||||
return first_result && second_result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef STENO_ENABLE_ALL
|
||||
void steno_init(void) {
|
||||
mode = eeconfig_read_steno_mode();
|
||||
}
|
||||
|
||||
void steno_set_mode(steno_mode_t new_mode) {
|
||||
steno_clear_chord();
|
||||
mode = new_mode;
|
||||
eeconfig_update_steno_mode(mode);
|
||||
}
|
||||
#endif // STENO_ENABLE_ALL
|
||||
|
||||
/* override to intercept chords right before they get sent.
|
||||
* return zero to suppress normal sending behavior.
|
||||
*/
|
||||
@@ -150,65 +57,97 @@ __attribute__((weak)) bool process_steno_user(uint16_t keycode, keyrecord_t *rec
|
||||
return true;
|
||||
}
|
||||
|
||||
bool process_steno(uint16_t keycode, keyrecord_t *record) {
|
||||
if (keycode < QK_STENO || keycode > QK_STENO_MAX) {
|
||||
return true; // Not a steno key, pass it further along the chain
|
||||
/*
|
||||
* Clearing or sending the chord state is not necessary as we intentionally ignore whatever
|
||||
* normal keyboard keys the user may have tapped while chording steno keys.
|
||||
*/
|
||||
static void steno_add_keycode_to_chord(uint16_t keycode) {
|
||||
switch (steno_get_mode()) {
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
case STENO_MODE_BOLT:
|
||||
steno_add_key_to_chord_bolt(steno_current_chord, keycode - QK_STENO_FUNCTION);
|
||||
break;
|
||||
#endif
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
case STENO_MODE_GEMINI:
|
||||
steno_add_key_to_chord_gemini(steno_current_chord, keycode - QK_STENO_FUNCTION);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void steno_send_chord(void) {
|
||||
switch (steno_get_mode()) {
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
case STENO_MODE_BOLT:
|
||||
steno_send_chord_bolt(steno_current_chord);
|
||||
break;
|
||||
#endif
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
case STENO_MODE_GEMINI:
|
||||
steno_send_chord_gemini(steno_current_chord);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool process_steno(uint16_t keycode, keyrecord_t *record) {
|
||||
if (!IS_STENO_KEYCODE(keycode)) {
|
||||
// Clearing or sending the chord state is not necessary as we intentionally ignore whatever
|
||||
// normal keyboard keys the user may have tapped while chording steno keys.
|
||||
return true; // pass keycode further along the chain
|
||||
}
|
||||
|
||||
if (IS_NOEVENT(record->event)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!process_steno_user(keycode, record)) {
|
||||
return false; // User fully processed the steno key themselves
|
||||
}
|
||||
|
||||
switch (keycode) {
|
||||
#ifdef STENO_ENABLE_ALL
|
||||
case QK_STENO_BOLT:
|
||||
#if NUM_STENO_PROTOCOLS > 1
|
||||
case QK_STENO_MODE_NEXT:
|
||||
if (record->event.pressed) {
|
||||
steno_mode_next();
|
||||
}
|
||||
return false;
|
||||
|
||||
case QK_STENO_MODE_PREVIOUS:
|
||||
if (record->event.pressed) {
|
||||
steno_mode_previous();
|
||||
}
|
||||
return false;
|
||||
|
||||
case QK_STENO_MODE_BOLT:
|
||||
if (record->event.pressed) {
|
||||
steno_set_mode(STENO_MODE_BOLT);
|
||||
}
|
||||
return false;
|
||||
|
||||
case QK_STENO_GEMINI:
|
||||
case QK_STENO_MODE_GEMINI:
|
||||
if (record->event.pressed) {
|
||||
steno_set_mode(STENO_MODE_GEMINI);
|
||||
}
|
||||
return false;
|
||||
#endif // STENO_ENABLE_ALL
|
||||
#endif
|
||||
|
||||
#ifdef STENO_COMBINEDMAP
|
||||
case QK_STENO_COMB ... QK_STENO_COMB_MAX: {
|
||||
bool first_result = process_steno(combinedmap_first[keycode - QK_STENO_COMB], record);
|
||||
bool second_result = process_steno(combinedmap_second[keycode - QK_STENO_COMB], record);
|
||||
return first_result && second_result;
|
||||
}
|
||||
#endif // STENO_COMBINEDMAP
|
||||
case STN__MIN ... STN__MAX:
|
||||
case QK_STENO_S3 ... QK_STENO_EU:
|
||||
return process_steno_combinedmap(keycode, record);
|
||||
#endif
|
||||
|
||||
case QK_STENO_FUNCTION ... QK_STENO_ZR:
|
||||
if (record->event.pressed) {
|
||||
n_pressed_keys++;
|
||||
switch (mode) {
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
case STENO_MODE_BOLT:
|
||||
add_bolt_key_to_chord(keycode - QK_STENO);
|
||||
break;
|
||||
#endif // STENO_ENABLE_BOLT
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
case STENO_MODE_GEMINI:
|
||||
add_gemini_key_to_chord(keycode - QK_STENO);
|
||||
break;
|
||||
#endif // STENO_ENABLE_GEMINI
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (!post_process_steno_user(keycode, record, mode, chord, n_pressed_keys)) {
|
||||
steno_add_keycode_to_chord(keycode);
|
||||
if (!post_process_steno_user(keycode, record, steno_get_mode(), steno_current_chord, n_pressed_keys)) {
|
||||
return false;
|
||||
}
|
||||
} else { // is released
|
||||
n_pressed_keys--;
|
||||
if (!post_process_steno_user(keycode, record, mode, chord, n_pressed_keys)) {
|
||||
if (!post_process_steno_user(keycode, record, steno_get_mode(), steno_current_chord, n_pressed_keys)) {
|
||||
return false;
|
||||
}
|
||||
if (n_pressed_keys > 0) {
|
||||
@@ -217,27 +156,17 @@ bool process_steno(uint16_t keycode, keyrecord_t *record) {
|
||||
return false;
|
||||
}
|
||||
n_pressed_keys = 0;
|
||||
if (!send_steno_chord_user(mode, chord)) {
|
||||
if (!send_steno_chord_user(steno_get_mode(), steno_current_chord)) {
|
||||
steno_clear_chord();
|
||||
return false;
|
||||
}
|
||||
switch (mode) {
|
||||
#if defined(STENO_ENABLE_BOLT) && defined(VIRTSER_ENABLE)
|
||||
case STENO_MODE_BOLT:
|
||||
send_steno_chord_bolt();
|
||||
break;
|
||||
#endif // STENO_ENABLE_BOLT && VIRTSER_ENABLE
|
||||
#if defined(STENO_ENABLE_GEMINI) && defined(VIRTSER_ENABLE)
|
||||
case STENO_MODE_GEMINI:
|
||||
send_steno_chord_gemini();
|
||||
break;
|
||||
#endif // STENO_ENABLE_GEMINI && VIRTSER_ENABLE
|
||||
default:
|
||||
break;
|
||||
}
|
||||
steno_send_chord();
|
||||
steno_clear_chord();
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,42 +1,10 @@
|
||||
/* Copyright 2017 Joseph Wasson
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Copyright 2017 Joseph Wasson
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "action.h"
|
||||
#include "steno_keycodes.h"
|
||||
|
||||
#define BOLT_STROKE_SIZE 4
|
||||
#define GEMINI_STROKE_SIZE 6
|
||||
|
||||
#ifdef STENO_ENABLE_GEMINI
|
||||
# define MAX_STROKE_SIZE GEMINI_STROKE_SIZE
|
||||
#else
|
||||
# define MAX_STROKE_SIZE BOLT_STROKE_SIZE
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
STENO_MODE_GEMINI,
|
||||
STENO_MODE_BOLT,
|
||||
} steno_mode_t;
|
||||
|
||||
bool process_steno(uint16_t keycode, keyrecord_t *record);
|
||||
#ifdef STENO_ENABLE_ALL
|
||||
void steno_init(void);
|
||||
void steno_set_mode(steno_mode_t mode);
|
||||
#endif // STENO_ENABLE_ALL
|
||||
|
||||
@@ -100,6 +100,7 @@ extern layer_state_t layer_state;
|
||||
#endif
|
||||
|
||||
#ifdef STENO_ENABLE
|
||||
# include "steno.h"
|
||||
# include "process_steno.h"
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// Copyright 2026 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "steno.h"
|
||||
#include "eeconfig.h"
|
||||
#include "util.h"
|
||||
#include "compiler_support.h"
|
||||
|
||||
#ifndef STENO_DEFAULT_MODE
|
||||
# if defined(STENO_ENABLE_GEMINI)
|
||||
# define STENO_DEFAULT_MODE STENO_MODE_GEMINI
|
||||
# elif defined(STENO_ENABLE_BOLT)
|
||||
# define STENO_DEFAULT_MODE STENO_MODE_BOLT
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(STENO_ENABLE_GEMINI)
|
||||
STATIC_ASSERT(STENO_DEFAULT_MODE != STENO_MODE_GEMINI, "STENO_DEFAULT_MODE is set to STENO_MODE_GEMINI, but is not available. Enable the geminipr protocol or change STENO_DEFAULT_MODE to a valid mode.");
|
||||
#endif
|
||||
#if !defined(STENO_ENABLE_BOLT)
|
||||
STATIC_ASSERT(STENO_DEFAULT_MODE != STENO_MODE_BOLT, "STENO_DEFAULT_MODE is set to STENO_MODE_BOLT, but is not available. Enable the txbolt protocol or change STENO_DEFAULT_MODE to a valid mode.");
|
||||
#endif
|
||||
|
||||
static steno_mode_t mode = STENO_DEFAULT_MODE;
|
||||
|
||||
uint8_t steno_current_chord[MAX_STROKE_SIZE] = {0};
|
||||
|
||||
void steno_clear_chord(void) {
|
||||
memset(steno_current_chord, 0, sizeof(steno_current_chord));
|
||||
}
|
||||
|
||||
steno_mode_t steno_get_mode(void) {
|
||||
return mode;
|
||||
}
|
||||
|
||||
#if NUM_STENO_PROTOCOLS > 1
|
||||
|
||||
static const steno_mode_t mode_candidates[] = {
|
||||
# if defined(STENO_ENABLE_GEMINI)
|
||||
STENO_MODE_GEMINI,
|
||||
# endif
|
||||
# if defined(STENO_ENABLE_BOLT)
|
||||
STENO_MODE_BOLT,
|
||||
# endif
|
||||
};
|
||||
|
||||
# define MODE_CANDIDATES_COUNT ARRAY_SIZE(mode_candidates)
|
||||
|
||||
static inline bool is_valid_mode(steno_mode_t mode) {
|
||||
for (uint8_t i = 0; i < MODE_CANDIDATES_COUNT; i++) {
|
||||
if (mode == mode_candidates[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void steno_set_mode_noeeprom(steno_mode_t new_mode) {
|
||||
if (!is_valid_mode(new_mode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
steno_clear_chord();
|
||||
|
||||
mode = new_mode;
|
||||
}
|
||||
|
||||
void steno_set_mode(steno_mode_t new_mode) {
|
||||
steno_set_mode_noeeprom(new_mode);
|
||||
|
||||
eeconfig_update_steno_mode(mode);
|
||||
}
|
||||
|
||||
void steno_mode_next_noeeprom(void) {
|
||||
uint8_t next = 0;
|
||||
for (uint8_t i = 0; i < MODE_CANDIDATES_COUNT; i++) {
|
||||
if (mode_candidates[i] == mode) {
|
||||
next = (i == MODE_CANDIDATES_COUNT - 1) ? 0 : (i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
steno_set_mode_noeeprom(mode_candidates[next]);
|
||||
}
|
||||
|
||||
void steno_mode_next(void) {
|
||||
steno_mode_next_noeeprom();
|
||||
|
||||
eeconfig_update_steno_mode(mode);
|
||||
}
|
||||
|
||||
void steno_mode_previous_noeeprom(void) {
|
||||
uint8_t next = 0;
|
||||
for (uint8_t i = 0; i < MODE_CANDIDATES_COUNT; i++) {
|
||||
if (mode_candidates[i] == mode) {
|
||||
next = (i == 0) ? (MODE_CANDIDATES_COUNT - 1) : (i - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
steno_set_mode_noeeprom(mode_candidates[next]);
|
||||
}
|
||||
|
||||
void steno_mode_previous(void) {
|
||||
steno_mode_previous_noeeprom();
|
||||
|
||||
eeconfig_update_steno_mode(mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void eeconfig_update_steno_default(void) {
|
||||
eeconfig_update_steno_mode(STENO_DEFAULT_MODE);
|
||||
}
|
||||
|
||||
void steno_init(void) {
|
||||
#if NUM_STENO_PROTOCOLS > 1
|
||||
steno_mode_t loaded = eeconfig_read_steno_mode();
|
||||
if (is_valid_mode(loaded)) {
|
||||
mode = loaded;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
// Copyright 2026 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "steno_keycodes.h"
|
||||
|
||||
#define BOLT_STROKE_SIZE 4
|
||||
#define GEMINI_STROKE_SIZE 6
|
||||
|
||||
#if defined(STENO_ENABLE_GEMINI)
|
||||
# define MAX_STROKE_SIZE GEMINI_STROKE_SIZE
|
||||
#else
|
||||
# define MAX_STROKE_SIZE BOLT_STROKE_SIZE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \enum steno_mode_t
|
||||
*
|
||||
* An enumeration of the possible modes.
|
||||
*/
|
||||
typedef enum {
|
||||
STENO_MODE_GEMINI,
|
||||
STENO_MODE_BOLT,
|
||||
} steno_mode_t;
|
||||
|
||||
/**
|
||||
* \brief Initialize the subsystem.
|
||||
*
|
||||
* This function must be called only once, before any of the below functions can be called.
|
||||
*/
|
||||
void steno_init(void);
|
||||
|
||||
/**
|
||||
* \brief Reset configuration to defaults.
|
||||
*
|
||||
*/
|
||||
void eeconfig_update_steno_default(void);
|
||||
|
||||
/**
|
||||
* \brief Clear any currently pressed chords.
|
||||
*
|
||||
*/
|
||||
void steno_clear_chord(void);
|
||||
|
||||
/**
|
||||
* \brief Get currently configured mode.
|
||||
*
|
||||
* \return 'steno_mode_t' of the configured mode.
|
||||
*/
|
||||
steno_mode_t steno_get_mode(void);
|
||||
|
||||
#if NUM_STENO_PROTOCOLS > 1
|
||||
|
||||
/**
|
||||
* \brief Set current mode. New state is not written to EEPROM.
|
||||
*
|
||||
* \param mode The mode to configure.
|
||||
*/
|
||||
void steno_set_mode_noeeprom(steno_mode_t mode);
|
||||
|
||||
/**
|
||||
* \brief Set current mode.
|
||||
*
|
||||
* \param mode The mode to configure.
|
||||
*/
|
||||
void steno_set_mode(steno_mode_t mode);
|
||||
|
||||
/**
|
||||
* \brief Move to the next potential mode. New state is not written to EEPROM.
|
||||
*
|
||||
*/
|
||||
void steno_mode_next_noeeprom(void);
|
||||
|
||||
/**
|
||||
* \brief Move to the next potential mode.
|
||||
*
|
||||
*/
|
||||
void steno_mode_next(void);
|
||||
|
||||
/**
|
||||
* \brief Move to the previous potential mode. New state is not written to EEPROM.
|
||||
*
|
||||
*/
|
||||
void steno_mode_previous_noeeprom(void);
|
||||
|
||||
/**
|
||||
* \brief Move to the previous potential mode.
|
||||
*
|
||||
*/
|
||||
void steno_mode_previous(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,113 @@
|
||||
// Copyright 2017, 2022 Joseph Wasson, Vladislav Kucheriavykh
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "steno.h"
|
||||
#include "progmem.h"
|
||||
#ifdef VIRTSER_ENABLE
|
||||
# include "virtser.h"
|
||||
#endif
|
||||
|
||||
#define TXB_NUL 0
|
||||
#define TXB_S_L 0b00000001
|
||||
#define TXB_T_L 0b00000010
|
||||
#define TXB_K_L 0b00000100
|
||||
#define TXB_P_L 0b00001000
|
||||
#define TXB_W_L 0b00010000
|
||||
#define TXB_H_L 0b00100000
|
||||
#define TXB_R_L 0b01000001
|
||||
#define TXB_A_L 0b01000010
|
||||
#define TXB_O_L 0b01000100
|
||||
#define TXB_STR 0b01001000
|
||||
#define TXB_E_R 0b01010000
|
||||
#define TXB_U_R 0b01100000
|
||||
#define TXB_F_R 0b10000001
|
||||
#define TXB_R_R 0b10000010
|
||||
#define TXB_P_R 0b10000100
|
||||
#define TXB_B_R 0b10001000
|
||||
#define TXB_L_R 0b10010000
|
||||
#define TXB_G_R 0b10100000
|
||||
#define TXB_T_R 0b11000001
|
||||
#define TXB_S_R 0b11000010
|
||||
#define TXB_D_R 0b11000100
|
||||
#define TXB_Z_R 0b11001000
|
||||
#define TXB_NUM 0b11010000
|
||||
|
||||
#define TXB_GRP0 0b00000000
|
||||
#define TXB_GRP1 0b01000000
|
||||
#define TXB_GRP2 0b10000000
|
||||
#define TXB_GRP3 0b11000000
|
||||
#define TXB_GRPMASK 0b11000000
|
||||
|
||||
#define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6)
|
||||
|
||||
// clang-format off
|
||||
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,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
void steno_add_key_to_chord_bolt(uint8_t chord[MAX_STROKE_SIZE], uint8_t key) {
|
||||
uint8_t boltcode = pgm_read_byte(boltmap + key);
|
||||
|
||||
chord[TXB_GET_GROUP(boltcode)] |= boltcode;
|
||||
}
|
||||
|
||||
void steno_send_chord_bolt(uint8_t chord[MAX_STROKE_SIZE]) {
|
||||
#ifdef VIRTSER_ENABLE
|
||||
for (uint8_t i = 0; i < BOLT_STROKE_SIZE; ++i) {
|
||||
// TX Bolt uses variable length packets where each byte corresponds to a bit array of certain keys.
|
||||
// If a user chorded the keys of the first group with keys of the last group, for example, there
|
||||
// would be bytes of 0x00 in `chord` for the middle groups which we mustn't send.
|
||||
if (chord[i]) {
|
||||
virtser_send(chord[i]);
|
||||
}
|
||||
}
|
||||
// Sending a null packet is not always necessary, but it is simpler and more reliable
|
||||
// to unconditionally send it every time instead of keeping track of more states and
|
||||
// creating more branches in the execution of the program.
|
||||
virtser_send(0);
|
||||
#else
|
||||
# pragma message "VIRTSER_ENABLE = yes is required for TX Bolt to work properly out of the box!"
|
||||
#endif // VIRTSER_ENABLE
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// Copyright 2017, 2022 Joseph Wasson, Vladislav Kucheriavykh
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "steno.h"
|
||||
#ifdef VIRTSER_ENABLE
|
||||
# include "virtser.h"
|
||||
#endif
|
||||
|
||||
void steno_add_key_to_chord_gemini(uint8_t chord[MAX_STROKE_SIZE], uint8_t key) {
|
||||
// Although each group of the packet is 8 bits long, the MSB is reserved
|
||||
// to indicate whether that byte is the first byte of the packet (MSB=1)
|
||||
// or one of the remaining five bytes of the packet (MSB=0).
|
||||
// As a consequence, only 7 out of the 8 bits are left to be used as a bit array
|
||||
// for the steno keys of that group.
|
||||
const int group_idx = key / 7;
|
||||
const int intra_group_idx = key - group_idx * 7;
|
||||
// The 0th steno key of the group has bit=0b01000000, the 1st has bit=0b00100000, etc.
|
||||
const uint8_t bit = 1 << (6 - intra_group_idx);
|
||||
chord[group_idx] |= bit;
|
||||
}
|
||||
|
||||
void steno_send_chord_gemini(uint8_t chord[MAX_STROKE_SIZE]) {
|
||||
#ifdef VIRTSER_ENABLE
|
||||
// Set MSB to 1 to indicate the start of packet
|
||||
chord[0] |= 0x80;
|
||||
for (uint8_t i = 0; i < GEMINI_STROKE_SIZE; ++i) {
|
||||
virtser_send(chord[i]);
|
||||
}
|
||||
#else
|
||||
# pragma message "VIRTSER_ENABLE = yes is required for Gemini PR to work properly out of the box!"
|
||||
#endif // VIRTSER_ENABLE
|
||||
}
|
||||
+64
-112
@@ -1,119 +1,71 @@
|
||||
/* Copyright 2017 Joseph Wasson
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
// Copyright 2026 QMK
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "keycodes.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 {
|
||||
STN__MIN = QK_STENO,
|
||||
STN_FN = STN__MIN,
|
||||
STN_NUM,
|
||||
STN_N1 = STN_NUM,
|
||||
STN_N2,
|
||||
STN_N3,
|
||||
STN_N4,
|
||||
STN_N5,
|
||||
STN_N6,
|
||||
STN_SL,
|
||||
STN_S1 = STN_SL,
|
||||
STN_S2,
|
||||
STN_TL,
|
||||
STN_KL,
|
||||
STN_PL,
|
||||
STN_WL,
|
||||
STN_HL,
|
||||
STN_RL,
|
||||
STN_A,
|
||||
STN_O,
|
||||
STN_STR,
|
||||
STN_ST1 = STN_STR,
|
||||
STN_ST2,
|
||||
STN_RES1,
|
||||
STN_RE1 = STN_RES1,
|
||||
STN_RES2,
|
||||
STN_RE2 = STN_RES2,
|
||||
STN_PWR,
|
||||
STN_ST3,
|
||||
STN_ST4,
|
||||
STN_E,
|
||||
STN_U,
|
||||
STN_FR,
|
||||
STN_RR,
|
||||
STN_PR,
|
||||
STN_BR,
|
||||
STN_LR,
|
||||
STN_GR,
|
||||
STN_TR,
|
||||
STN_SR,
|
||||
STN_DR,
|
||||
STN_N7,
|
||||
STN_N8,
|
||||
STN_N9,
|
||||
STN_NA,
|
||||
STN_NB,
|
||||
STN_NC,
|
||||
STN_ZR,
|
||||
STN__MAX = STN_ZR, // must be less than QK_STENO_BOLT
|
||||
};
|
||||
// Deprecated steno keycodes
|
||||
#define STN_FN QK_STENO_FUNCTION
|
||||
#define STN_N1 QK_STENO_N1
|
||||
#define STN_N2 QK_STENO_N2
|
||||
#define STN_N3 QK_STENO_N3
|
||||
#define STN_N4 QK_STENO_N4
|
||||
#define STN_N5 QK_STENO_N5
|
||||
#define STN_N6 QK_STENO_N6
|
||||
#define STN_S1 QK_STENO_S1
|
||||
#define STN_S2 QK_STENO_S2
|
||||
#define STN_TL QK_STENO_TL
|
||||
#define STN_KL QK_STENO_KL
|
||||
#define STN_PL QK_STENO_PL
|
||||
#define STN_WL QK_STENO_WL
|
||||
#define STN_HL QK_STENO_HL
|
||||
#define STN_RL QK_STENO_RL
|
||||
#define STN_A QK_STENO_A
|
||||
#define STN_O QK_STENO_O
|
||||
#define STN_ST1 QK_STENO_ST1
|
||||
#define STN_ST2 QK_STENO_ST2
|
||||
#define STN_RE1 QK_STENO_RESET1
|
||||
#define STN_RE2 QK_STENO_RESET2
|
||||
#define STN_PWR QK_STENO_POWER
|
||||
#define STN_ST3 QK_STENO_ST3
|
||||
#define STN_ST4 QK_STENO_ST4
|
||||
#define STN_E QK_STENO_E
|
||||
#define STN_U QK_STENO_U
|
||||
#define STN_FR QK_STENO_FR
|
||||
#define STN_RR QK_STENO_RR
|
||||
#define STN_PR QK_STENO_PR
|
||||
#define STN_BR QK_STENO_BR
|
||||
#define STN_LR QK_STENO_LR
|
||||
#define STN_GR QK_STENO_GR
|
||||
#define STN_TR QK_STENO_TR
|
||||
#define STN_SR QK_STENO_SR
|
||||
#define STN_DR QK_STENO_DR
|
||||
#define STN_N7 QK_STENO_N7
|
||||
#define STN_N8 QK_STENO_N8
|
||||
#define STN_N9 QK_STENO_N9
|
||||
#define STN_NA QK_STENO_NA
|
||||
#define STN_NB QK_STENO_NB
|
||||
#define STN_NC QK_STENO_NC
|
||||
#define STN_ZR QK_STENO_ZR
|
||||
|
||||
#ifdef STENO_COMBINEDMAP
|
||||
enum steno_combined_keycodes {
|
||||
STN_S3 = QK_STENO_COMB,
|
||||
STN_TKL,
|
||||
STN_PWL,
|
||||
STN_HRL,
|
||||
STN_FRR,
|
||||
STN_PBR,
|
||||
STN_LGR,
|
||||
STN_TSR,
|
||||
STN_DZR,
|
||||
STN_AO,
|
||||
STN_EU,
|
||||
STN_COMB_MAX = STN_EU,
|
||||
};
|
||||
#endif
|
||||
#define STN_NUM QK_STENO_N1
|
||||
#define STN_SL QK_STENO_S1
|
||||
#define STN_STR QK_STENO_ST1
|
||||
#define STN_RES1 QK_STENO_RESET1
|
||||
#define STN_RES2 QK_STENO_RESET2
|
||||
|
||||
#ifdef STENO_ENABLE_BOLT
|
||||
// TxBolt Codes
|
||||
# define TXB_NUL 0
|
||||
# define TXB_S_L 0b00000001
|
||||
# define TXB_T_L 0b00000010
|
||||
# define TXB_K_L 0b00000100
|
||||
# define TXB_P_L 0b00001000
|
||||
# define TXB_W_L 0b00010000
|
||||
# define TXB_H_L 0b00100000
|
||||
# define TXB_R_L 0b01000001
|
||||
# define TXB_A_L 0b01000010
|
||||
# define TXB_O_L 0b01000100
|
||||
# define TXB_STR 0b01001000
|
||||
# define TXB_E_R 0b01010000
|
||||
# define TXB_U_R 0b01100000
|
||||
# define TXB_F_R 0b10000001
|
||||
# define TXB_R_R 0b10000010
|
||||
# define TXB_P_R 0b10000100
|
||||
# define TXB_B_R 0b10001000
|
||||
# define TXB_L_R 0b10010000
|
||||
# define TXB_G_R 0b10100000
|
||||
# define TXB_T_R 0b11000001
|
||||
# define TXB_S_R 0b11000010
|
||||
# define TXB_D_R 0b11000100
|
||||
# define TXB_Z_R 0b11001000
|
||||
# define TXB_NUM 0b11010000
|
||||
#endif // STENO_ENABLE_BOLT
|
||||
#define STN_S3 QK_STENO_S3
|
||||
#define STN_TKL QK_STENO_TKL
|
||||
#define STN_PWL QK_STENO_PWL
|
||||
#define STN_HRL QK_STENO_HRL
|
||||
#define STN_FRR QK_STENO_FRR
|
||||
#define STN_PBR QK_STENO_PBR
|
||||
#define STN_LGR QK_STENO_LGR
|
||||
#define STN_TSR QK_STENO_TSR
|
||||
#define STN_DZR QK_STENO_DZR
|
||||
#define STN_AO QK_STENO_AO
|
||||
#define STN_EU QK_STENO_EU
|
||||
|
||||
#define QK_STENO_BOLT QK_STENO_MODE_BOLT
|
||||
#define QK_STENO_GEMINI QK_STENO_MODE_GEMINI
|
||||
|
||||
Reference in New Issue
Block a user