Initial skeleton: ZMK module structure + Javelin submodule + stub shims
Phase 1 scaffold for porting Javelin steno engine as a ZMK module. All platform shims are stubs — compiles but no steno processing yet.
This commit is contained in:
commit
206e5231e1
14 changed files with 445 additions and 0 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[submodule "javelin"]
|
||||
path = javelin
|
||||
url = https://github.com/jthlim/javelin-steno.git
|
||||
202
CMakeLists.txt
Normal file
202
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
if(CONFIG_ZMK_JAVELIN_STENO)
|
||||
|
||||
# Only compile on central side of split keyboards (or non-split)
|
||||
if((NOT CONFIG_ZMK_SPLIT) OR CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
||||
|
||||
zephyr_include_directories(javelin)
|
||||
zephyr_include_directories(include)
|
||||
|
||||
# Core engine sources
|
||||
set(JAVELIN_CORE_SRC
|
||||
javelin/asset_manager.cc
|
||||
javelin/base64.cc
|
||||
javelin/bit_field.cc
|
||||
javelin/bit.cc
|
||||
javelin/button_script_manager.cc
|
||||
javelin/button_script.cc
|
||||
javelin/clock.cc
|
||||
javelin/console_input_buffer.cc
|
||||
javelin/console.cc
|
||||
javelin/container/cyclic_queue.cc
|
||||
javelin/container/list.cc
|
||||
javelin/crc32.cc
|
||||
javelin/date_time.cc
|
||||
javelin/engine_add_translation_mode.cc
|
||||
javelin/engine_binding.cc
|
||||
javelin/engine_console_mode.cc
|
||||
javelin/engine_normal_mode.cc
|
||||
javelin/engine.cc
|
||||
javelin/flash.cc
|
||||
javelin/hash.cc
|
||||
javelin/host_layout.cc
|
||||
javelin/key_code.cc
|
||||
javelin/key_press_parser.cc
|
||||
javelin/key.cc
|
||||
javelin/mem.cc
|
||||
javelin/orthography.cc
|
||||
javelin/pattern_component.cc
|
||||
javelin/pattern.cc
|
||||
javelin/pool_allocate.cc
|
||||
javelin/random.cc
|
||||
javelin/script_byte_code.cc
|
||||
javelin/script_storage.cc
|
||||
javelin/script.cc
|
||||
javelin/segment_builder.cc
|
||||
javelin/segment.cc
|
||||
javelin/start_console_command_detector.cc
|
||||
javelin/state.cc
|
||||
javelin/steno_key_code_buffer_functions.cc
|
||||
javelin/steno_key_code_buffer.cc
|
||||
javelin/steno_key_code_emitter.cc
|
||||
javelin/steno_key_code.cc
|
||||
javelin/steno_key_state.cc
|
||||
javelin/str.cc
|
||||
javelin/stroke_history.cc
|
||||
javelin/stroke_list_parser.cc
|
||||
javelin/stroke.cc
|
||||
javelin/system.cc
|
||||
javelin/thread.cc
|
||||
javelin/timer_manager.cc
|
||||
javelin/unicode_script.cc
|
||||
javelin/unicode.cc
|
||||
javelin/utf8_pointer.cc
|
||||
javelin/word_list.cc
|
||||
javelin/wpm_tracker.cc
|
||||
javelin/writer.cc
|
||||
)
|
||||
|
||||
# Dictionary sources
|
||||
set(JAVELIN_DICT_SRC
|
||||
javelin/dictionary/cache_dictionary.cc
|
||||
javelin/dictionary/compact_map_dictionary.cc
|
||||
javelin/dictionary/debug_dictionary.cc
|
||||
javelin/dictionary/dictionary_definition.cc
|
||||
javelin/dictionary/dictionary_list.cc
|
||||
javelin/dictionary/dictionary.cc
|
||||
javelin/dictionary/emily_symbols_dictionary.cc
|
||||
javelin/dictionary/full_map_dictionary.cc
|
||||
javelin/dictionary/invalid_dictionary.cc
|
||||
javelin/dictionary/jeff_numbers_dictionary.cc
|
||||
javelin/dictionary/jeff_phrasing_dictionary_data.cc
|
||||
javelin/dictionary/jeff_phrasing_dictionary.cc
|
||||
javelin/dictionary/jeff_show_stroke_dictionary.cc
|
||||
javelin/dictionary/orthospelling_data.cc
|
||||
javelin/dictionary/orthospelling_dictionary.cc
|
||||
javelin/dictionary/reverse_auto_suffix_dictionary.cc
|
||||
javelin/dictionary/reverse_map_dictionary.cc
|
||||
javelin/dictionary/reverse_prefix_dictionary.cc
|
||||
javelin/dictionary/reverse_suffix_dictionary.cc
|
||||
javelin/dictionary/unicode_dictionary.cc
|
||||
javelin/dictionary/user_dictionary.cc
|
||||
javelin/dictionary/wrapped_dictionary.cc
|
||||
)
|
||||
|
||||
# Processor sources
|
||||
set(JAVELIN_PROC_SRC
|
||||
javelin/processor/all_up.cc
|
||||
javelin/processor/fake_processor.cc
|
||||
javelin/processor/first_up.cc
|
||||
javelin/processor/gemini.cc
|
||||
javelin/processor/jeff_modifiers.cc
|
||||
javelin/processor/paper_tape.cc
|
||||
javelin/processor/passport.cc
|
||||
javelin/processor/plover_hid.cc
|
||||
javelin/processor/procat.cc
|
||||
javelin/processor/processor_list.cc
|
||||
javelin/processor/processor.cc
|
||||
javelin/processor/repeat.cc
|
||||
javelin/processor/tx_bolt.cc
|
||||
)
|
||||
|
||||
# HAL sources (weak defaults — our shims override the critical ones)
|
||||
set(JAVELIN_HAL_SRC
|
||||
javelin/hal/ble.cc
|
||||
javelin/hal/bootloader.cc
|
||||
javelin/hal/connection.cc
|
||||
javelin/hal/display.cc
|
||||
javelin/hal/gpio.cc
|
||||
javelin/hal/infrared.cc
|
||||
javelin/hal/midi.cc
|
||||
javelin/hal/mouse.cc
|
||||
javelin/hal/power.cc
|
||||
javelin/hal/rgb.cc
|
||||
javelin/hal/rtc.cc
|
||||
javelin/hal/serial_port.cc
|
||||
javelin/hal/sound.cc
|
||||
javelin/hal/usb_status.cc
|
||||
)
|
||||
|
||||
# Font sources (needed by display/script subsystem)
|
||||
set(JAVELIN_FONT_SRC
|
||||
javelin/font/monochrome/data/default.cc
|
||||
javelin/font/monochrome/data/dos.cc
|
||||
javelin/font/monochrome/data/huge_digits.cc
|
||||
javelin/font/monochrome/data/large_digits.cc
|
||||
javelin/font/monochrome/data/large.cc
|
||||
javelin/font/monochrome/data/medium_digits.cc
|
||||
javelin/font/monochrome/data/small_digits.cc
|
||||
javelin/font/monochrome/font.cc
|
||||
)
|
||||
|
||||
# Split sources (ZMK handles split transport, but Javelin split types
|
||||
# are referenced by other code)
|
||||
set(JAVELIN_SPLIT_SRC
|
||||
javelin/split/split_console.cc
|
||||
javelin/split/split_key_state.cc
|
||||
javelin/split/split_midi.cc
|
||||
javelin/split/split_power_override.cc
|
||||
javelin/split/split_serial_buffer.cc
|
||||
javelin/split/split_usb_status.cc
|
||||
javelin/split/split_version.cc
|
||||
javelin/split/split.cc
|
||||
)
|
||||
|
||||
# Platform shims (our ZMK implementations)
|
||||
set(ZMK_SHIM_SRC
|
||||
src/platform/zmk_key_shim.cc
|
||||
src/platform/zmk_clock_shim.cc
|
||||
src/platform/zmk_flash_shim.cc
|
||||
src/platform/zmk_connection_shim.cc
|
||||
src/platform/zmk_console_shim.cc
|
||||
)
|
||||
|
||||
# ZMK behavior driver (C, not C++)
|
||||
set(ZMK_BEHAVIOR_SRC
|
||||
src/behaviors/behavior_javelin_steno.c
|
||||
)
|
||||
|
||||
# Engine initialization
|
||||
set(ZMK_INIT_SRC
|
||||
src/engine_init.cc
|
||||
)
|
||||
|
||||
# Combine all C++ sources
|
||||
set(ALL_CXX_SRC
|
||||
${JAVELIN_CORE_SRC}
|
||||
${JAVELIN_DICT_SRC}
|
||||
${JAVELIN_PROC_SRC}
|
||||
${JAVELIN_HAL_SRC}
|
||||
${JAVELIN_FONT_SRC}
|
||||
${JAVELIN_SPLIT_SRC}
|
||||
${ZMK_SHIM_SRC}
|
||||
${ZMK_INIT_SRC}
|
||||
)
|
||||
|
||||
# Set C++ compile flags for all Javelin + shim sources
|
||||
set_source_files_properties(${ALL_CXX_SRC} PROPERTIES
|
||||
COMPILE_FLAGS "-std=gnu++23 -fno-exceptions -fno-rtti -fno-threadsafe-statics"
|
||||
)
|
||||
|
||||
# Compile definitions for Javelin
|
||||
set_source_files_properties(${ALL_CXX_SRC} PROPERTIES
|
||||
COMPILE_DEFINITIONS "JAVELIN_USE_EMBEDDED_STENO=1;JAVELIN_USE_USER_DICTIONARY=1;JAVELIN_PLATFORM_ZEPHYR=1"
|
||||
)
|
||||
|
||||
target_sources(app PRIVATE
|
||||
${ALL_CXX_SRC}
|
||||
${ZMK_BEHAVIOR_SRC}
|
||||
)
|
||||
|
||||
endif() # central role check
|
||||
|
||||
endif() # CONFIG_ZMK_JAVELIN_STENO
|
||||
48
Kconfig
Normal file
48
Kconfig
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
menu "Javelin Steno Engine"
|
||||
|
||||
config ZMK_JAVELIN_STENO
|
||||
bool "Enable Javelin steno engine"
|
||||
default n
|
||||
select CPLUSPLUS
|
||||
select LIB_CPLUSPLUS
|
||||
select NEWLIB_LIBC
|
||||
|
||||
config ZMK_JAVELIN_STENO_HEAP_SIZE
|
||||
int "Heap size for Javelin engine (bytes)"
|
||||
default 32768
|
||||
depends on ZMK_JAVELIN_STENO
|
||||
|
||||
config ZMK_JAVELIN_STENO_USER_DICT
|
||||
bool "Enable user dictionary (writable flash)"
|
||||
default y
|
||||
depends on ZMK_JAVELIN_STENO
|
||||
|
||||
config ZMK_JAVELIN_STENO_USER_DICT_SIZE
|
||||
int "User dictionary flash size (bytes)"
|
||||
default 16384
|
||||
depends on ZMK_JAVELIN_STENO_USER_DICT
|
||||
|
||||
config ZMK_JAVELIN_STENO_ORTHOGRAPHY_CACHE
|
||||
bool "Enable orthography lookup cache (~32KB RAM)"
|
||||
default n
|
||||
depends on ZMK_JAVELIN_STENO
|
||||
|
||||
config ZMK_JAVELIN_STENO_CONSOLE
|
||||
bool "Enable steno console commands via USB"
|
||||
default n
|
||||
depends on ZMK_JAVELIN_STENO
|
||||
|
||||
choice ZMK_JAVELIN_STENO_TRIGGER
|
||||
prompt "Stroke trigger mode"
|
||||
default ZMK_JAVELIN_STENO_TRIGGER_ALL_UP
|
||||
depends on ZMK_JAVELIN_STENO
|
||||
|
||||
config ZMK_JAVELIN_STENO_TRIGGER_ALL_UP
|
||||
bool "All keys up (standard)"
|
||||
|
||||
config ZMK_JAVELIN_STENO_TRIGGER_FIRST_UP
|
||||
bool "First key up (faster, less forgiving)"
|
||||
|
||||
endchoice
|
||||
|
||||
endmenu
|
||||
11
dts/bindings/behaviors/zmk,behavior-javelin-steno.yaml
Normal file
11
dts/bindings/behaviors/zmk,behavior-javelin-steno.yaml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
description: |
|
||||
Javelin steno behavior — maps key positions to steno keys and feeds
|
||||
them into the on-board Javelin steno engine for chord-based text input.
|
||||
|
||||
compatible: "zmk,behavior-javelin-steno"
|
||||
|
||||
include: one_param.yaml
|
||||
|
||||
properties:
|
||||
"#binding-cells":
|
||||
const: 1
|
||||
12
include/zmk_javelin_steno/zmk_platform_shim.h
Normal file
12
include/zmk_javelin_steno/zmk_platform_shim.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void zmk_javelin_steno_init(void);
|
||||
void zmk_javelin_steno_process_key(int steno_key_index, bool is_press);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
1
javelin
Submodule
1
javelin
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 22726675b2dcf3b8b6ba1e20898f25e324b2260a
|
||||
48
src/behaviors/behavior_javelin_steno.c
Normal file
48
src/behaviors/behavior_javelin_steno.c
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
#include <zephyr/device.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
|
||||
#include <drivers/behavior.h>
|
||||
#include <zmk/behavior.h>
|
||||
#include <zmk/keymap.h>
|
||||
|
||||
#include "zmk_javelin_steno/zmk_platform_shim.h"
|
||||
|
||||
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
||||
|
||||
struct behavior_javelin_steno_config {};
|
||||
struct behavior_javelin_steno_data {};
|
||||
|
||||
static int on_keymap_binding_pressed(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int steno_key = binding->param1;
|
||||
zmk_javelin_steno_process_key(steno_key, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_keymap_binding_released(struct zmk_behavior_binding *binding,
|
||||
struct zmk_behavior_binding_event event) {
|
||||
int steno_key = binding->param1;
|
||||
zmk_javelin_steno_process_key(steno_key, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int behavior_javelin_steno_init(const struct device *dev) {
|
||||
zmk_javelin_steno_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct behavior_driver_api behavior_javelin_steno_driver_api = {
|
||||
.binding_pressed = on_keymap_binding_pressed,
|
||||
.binding_released = on_keymap_binding_released,
|
||||
.locality = BEHAVIOR_LOCALITY_CENTRAL,
|
||||
};
|
||||
|
||||
static struct behavior_javelin_steno_data behavior_javelin_steno_data;
|
||||
static struct behavior_javelin_steno_config behavior_javelin_steno_config;
|
||||
|
||||
BEHAVIOR_DT_INST_DEFINE(0, behavior_javelin_steno_init, NULL,
|
||||
&behavior_javelin_steno_data,
|
||||
&behavior_javelin_steno_config,
|
||||
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT,
|
||||
&behavior_javelin_steno_driver_api);
|
||||
38
src/engine_init.cc
Normal file
38
src/engine_init.cc
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#include "zmk_javelin_steno/zmk_platform_shim.h"
|
||||
|
||||
#include "engine.h"
|
||||
#include "processor/all_up.h"
|
||||
#include "processor/processor.h"
|
||||
#include "steno_key_state.h"
|
||||
|
||||
// Static storage for the processor pipeline.
|
||||
// Pipeline: StenoProcessor → StenoAllUp → StenoEngine
|
||||
static StenoAllUp *allUp = nullptr;
|
||||
static StenoProcessor *processor = nullptr;
|
||||
|
||||
extern "C" {
|
||||
|
||||
void zmk_javelin_steno_init(void) {
|
||||
// TODO Phase 2: Initialize with real dictionary and orthography.
|
||||
// For now this is a skeleton — engine construction requires a
|
||||
// StenoDictionaryCollection loaded from flash (Phase 3).
|
||||
//
|
||||
// Full init will look like:
|
||||
// 1. Read dictionary collection from flash partition
|
||||
// 2. Validate magic (0x3443534a = 'JSC4')
|
||||
// 3. Build dictionary list from collection
|
||||
// 4. Load compiled orthography
|
||||
// 5. Construct StenoEngine with dict + ortho
|
||||
// 6. Build processor pipeline: AllUp → Engine
|
||||
// 7. Wrap in StenoProcessor for key input
|
||||
}
|
||||
|
||||
void zmk_javelin_steno_process_key(int steno_key_index, bool is_press) {
|
||||
if (!processor) {
|
||||
return;
|
||||
}
|
||||
StenoKey key = static_cast<StenoKey>(steno_key_index);
|
||||
processor->Process(key, is_press);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
19
src/platform/zmk_clock_shim.cc
Normal file
19
src/platform/zmk_clock_shim.cc
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "clock.h"
|
||||
|
||||
// TODO Phase 2: Replace with Zephyr kernel time functions.
|
||||
// #include <zephyr/kernel.h>
|
||||
// uint32_t Clock::GetMilliseconds() { return k_uptime_get_32(); }
|
||||
// uint32_t Clock::GetMicroseconds() { return k_cyc_to_us_floor32(k_cycle_get_32()); }
|
||||
// void Clock::Sleep(uint32_t ms) { k_msleep(ms); }
|
||||
|
||||
uint32_t Clock::GetMilliseconds() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t Clock::GetMicroseconds() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Clock::Sleep(uint32_t milliseconds) {
|
||||
(void)milliseconds;
|
||||
}
|
||||
10
src/platform/zmk_connection_shim.cc
Normal file
10
src/platform/zmk_connection_shim.cc
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
#include "hal/connection.h"
|
||||
#include "hal/ble.h"
|
||||
#include "hal/usb_status.h"
|
||||
|
||||
// Connection::IsConnected and friends are already implemented in
|
||||
// hal/connection.cc using the weak Ble:: and UsbStatus:: defaults.
|
||||
// This file exists for future ZMK-specific connection status overrides.
|
||||
|
||||
// TODO Phase 2: Optionally override Ble::IsConnected() with
|
||||
// zmk_ble_active_profile_is_connected() for accurate BLE status.
|
||||
9
src/platform/zmk_console_shim.cc
Normal file
9
src/platform/zmk_console_shim.cc
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#include "console.h"
|
||||
|
||||
// ConsoleWriter::Write is the main output path for Javelin's console system.
|
||||
// For Phase 1, stub it out. Phase 4 will route to USB CDC or ZMK logging.
|
||||
|
||||
void ConsoleWriter::Write(const char *data, size_t length) {
|
||||
(void)data;
|
||||
(void)length;
|
||||
}
|
||||
19
src/platform/zmk_flash_shim.cc
Normal file
19
src/platform/zmk_flash_shim.cc
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#include "flash.h"
|
||||
|
||||
// TODO Phase 3: Replace with Zephyr flash API.
|
||||
// #include <zephyr/drivers/flash.h>
|
||||
// #include <zephyr/storage/flash_map.h>
|
||||
|
||||
Flash Flash::instance;
|
||||
|
||||
void Flash::EraseBlockInternal(const void *target, size_t size) {
|
||||
(void)target;
|
||||
(void)size;
|
||||
}
|
||||
|
||||
void Flash::WriteBlockInternal(const void *target, const void *data,
|
||||
size_t size) {
|
||||
(void)target;
|
||||
(void)data;
|
||||
(void)size;
|
||||
}
|
||||
20
src/platform/zmk_key_shim.cc
Normal file
20
src/platform/zmk_key_shim.cc
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#include "key.h"
|
||||
#include "key_code.h"
|
||||
|
||||
// TODO Phase 2: Replace stubs with ZMK HID event emission.
|
||||
// Key::Press/Release are called by Javelin's output pipeline to send
|
||||
// translated text to the host. These need to map to
|
||||
// raise_zmk_keycode_state_changed() with correct usage pages.
|
||||
|
||||
bool Key::historyEnabled = false;
|
||||
|
||||
void Key::Press(KeyCode key) {
|
||||
(void)key;
|
||||
}
|
||||
|
||||
void Key::Release(KeyCode key) {
|
||||
(void)key;
|
||||
}
|
||||
|
||||
void Key::Flush() {
|
||||
}
|
||||
5
zephyr/module.yml
Normal file
5
zephyr/module.yml
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
build:
|
||||
cmake: .
|
||||
kconfig: Kconfig
|
||||
settings:
|
||||
dts_root: .
|
||||
Loading…
Add table
Add a link
Reference in a new issue