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:
afiqzudinhadi 2026-06-22 20:49:01 +08:00
commit 206e5231e1
14 changed files with 445 additions and 0 deletions

View 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
View 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"

View 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;
}

View 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.

View 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;
}

View 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;
}

View 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() {
}