キー拡張機能アーキテクチャ技術解説書 (Key Extension Architecture)
本書は、fjFlow のキー拡張機能(Key Extension)を構成するステートマシンエンジン、タイマー制御、および出力パイプラインの技術アーキテクチャを解説するドキュメントです。...
決定論的 4-State FSM、文字順序逆転防止、0ms即時リマップを支える内部アーキテクチャ
本書は、fjFlow のキー拡張機能(Key Extension)を構成するステートマシンエンジン、タイマー制御、および出力パイプラインの技術アーキテクチャを解説するドキュメントです。
目次
- 1. コア設計思想:判定フェーズと出力フェーズの完全分離
- 2. 決定論的 4-State FSM (状態遷移マシン) の動作モデル
- 3. 可変長シーケンスと文字数スケーリングタイマーの仕組み
- 4. 静寂バイパスによる 0ms 即時リマップの実装手順
- 5. 中間候補と最長一致のスマート共存アルゴリズム
- 6. Shiftキーによる安全なコンボキャンセル制御
- 7. 文字順序の逆転(追い越し)を物理的に防止する直列フック
1. コア設計思想:判定フェーズと出力フェーズの完全分離
キー拡張エンジンは、「判定フェーズ」 と 「出力フェーズ」 を完全に分離して設計されています。
┌────────────────────────────────────────────────────────┐
│ 1. 判定フェーズ (FSM Engine) │
│ ・純粋な物理キー打鍵イベント & タイムスタンプを受信 │
│ ・修飾ロックやレイヤーのリアルタイム変化を遮断 │
│ ・押下瞬間のレイヤースナップショット (downCond) 保持 │
│ ・完全一致 / 前方一致 / 静寂成立を決定論的に判定 │
└──────────────────────────┬─────────────────────────────┘
│ 確定 (Execute / Flush)
┌──────────────────────────▼─────────────────────────────┐
│ 2. 出力フェーズ (Output Pipeline) │
│ ・保持されたレイヤースナップショットでターゲット実行 │
│ ・修飾キーロック (Ctrl/Alt/Win/Shift) を合成適用 │
│ ・{Blind} モードによる OS アトミック送信 │
└────────────────────────────────────────────────────────┘
ユーザーがキーを打鍵した直後に修飾キー(Space 等)を離した場合でも、押下時のスナップショット(g_FsmKey1Cond)に基づいて評価されるため、レイヤーの戻りによる誤出力を100%防止します。
2. 決定論的 4-State FSM (状態遷移マシン) の動作モデル
エンジンは、以下の4状態をもつ決定論的ステートマシンによって駆動されます。
STATE_READY: 初期待機状態。保留中のキーがない状態。STATE_PENDING_DOWN: 1打目キー押下保留中(キー押下直後。長押し判定待ち、または2打目以降への接続待機)。STATE_PENDING_UP: 1打目キー解放後保留中(キーを離した後の2〜5打目待ち、または放置タイムアウト待ち)。STATE_WAIT_POST_SILENCE: 後段静寂待ち状態(シーケンス最長一致に達し、後続打鍵がないか静寂判定待機)。
stateDiagram-v2
[*] --> STATE_READY
state STATE_READY {
[*] --> Idle
}
STATE_READY --> STATE_READY : ① 通常単打 / 0ms 即時リマップ実行
STATE_READY --> STATE_READY : ② タイピング中 (前段静寂なし)<br/>通常キー出力
STATE_READY --> STATE_PENDING_DOWN : ③ 前段静寂成立 + 対象キー押下<br/>1打目キーを押下保留 (holdMs / comboMs 判定開始)
state STATE_PENDING_DOWN {
[*] --> KeyDownPending
}
STATE_PENDING_DOWN --> STATE_READY : ④ holdMs 経過 (押し続けた)<br/>長押しターゲット確定実行!
STATE_PENDING_DOWN --> STATE_PENDING_UP : ⑤ holdMs 未満で KeyUp (離した)<br/>長押しキャンセル ➔ 2打目または単打待ちへ遷移
STATE_PENDING_DOWN --> STATE_READY : ⑥ 別キー高速入力 (不一致)<br/>直ちにキャンセル ➔ 保留キーフラッシュ
state STATE_PENDING_UP {
[*] --> KeyUpPending
}
STATE_PENDING_UP --> STATE_PENDING_UP : ⑦ 前方一致あり (例: 'us' in 'usa')<br/>キー追加保留 (Timer: Nx ms)
STATE_PENDING_UP --> STATE_WAIT_POST_SILENCE : ⑧ 最長完全一致到達 (例: 'usa')<br/>後段静寂待ち (Timer: Nx ms)
STATE_PENDING_UP --> STATE_READY : ⑨ タイムアウト (手を止めた)<br/>単打 / 中間候補を実行
STATE_PENDING_UP --> STATE_READY : ⑩ コンボ不一致 / 時間切れ<br/>保留キーを順次 Raw 出力
state STATE_WAIT_POST_SILENCE {
[*] --> PostSilenceWait
}
STATE_WAIT_POST_SILENCE --> STATE_READY : ⑪ 後段静寂成立 (手を止めた)<br/>ターゲット (例: '米国') を確定実行!
STATE_WAIT_POST_SILENCE --> STATE_READY : ⑫ 後続キー高速打鍵 (例: 'usaa')<br/>後段静寂破綻!全キー Raw 出力
STATE_PENDING_DOWN --> STATE_READY : ⑬ Shift Up<br/>小文字 Raw フラッシュ
STATE_PENDING_UP --> STATE_READY : ⑬ Shift Up<br/>小文字 Raw フラッシュ
STATE_WAIT_POST_SILENCE --> STATE_READY : ⑬ Shift Up<br/>小文字 Raw フラッシュ
3. 可変長シーケンスと文字数スケーリングタイマーの仕組み
文字数 $N$ に応じてタイマー待機時間を自動調整するスケーリングアルゴリズムです。
$$\text{判定時間} = N \times x \text{ (ms)}$$
- 基本間隔 $x = 300\text{ms}$ の場合:
- 1文字: $300\text{ms}$(単打判定)
- 2文字: $600\text{ms}$(
hh,eq等の2文字コンボ) - 3〜5文字: 最大5打鍵まで各打鍵間でステップ間隔判定(直前キーから $comboMs$ 以内)
- 長いシーケンスほど入力猶予が自然に広がり、焦らず確実に入力できます。
4. 静寂バイパスによる 0ms 即時リマップの実装手順
キーを角括弧 [] で定義することで、静寂判定を完全にバイパスして即時出力する仕組みです。
- 単打
[a]: 高速タイピング中であっても、キーを押した瞬間に 0ms 完全無遅延で即座に目的のキーへ置換出力 されます。 - コンボ
[ca]/[abcde]: 最終キーを押した瞬間に、後段静寂(待機時間)を経由せず即時確定実行されます。
5. 中間候補と最長一致のスマート共存アルゴリズム
us ➔ _(2文字)、usa ➔ 米国(3文字)、usaf ➔ 米空軍(4文字)のように部分一致するコンボが同時に登録されている場合でも、最大5打鍵まで破綻なく両立して入力できる仕組みです。
u➔sと入力した時点で、完全一致_を中間候補として保持しつつ、状態を次のキー待ちで維持します。- 3打目
aが入力された場合 ➔ さらに長い一致usaに進み、米国を中間候補へ更新します。 - 4打目
fが入力された場合 ➔ 最長一致usafに進み、米空軍を出力します。 - 次のキーが来ずにタイムアウトした場合 ➔ 保持していた最新の中間候補を出力します。
- 関係ないキーが来た場合、または5打鍵を超えた場合 ➔ 保留されていたキーを順序通り生出力します。
6. Shiftキーによる安全なコンボキャンセル制御
コンボ入力を中断して生文字を出力する際の誤爆防止手順です。
- コンボ待機中に
Shiftキーを押します。 FsmOnShiftDown()が発動し、タイマーが直ちに強制停止されます(この時点では文字を出力しません)。Shiftキーを離します。FsmFlushOnShiftUp()が発動し、Shiftが離された状態で保留キー(u,s,a)が 小文字のまま安全にフラッシュ出力 されます。
7. 文字順序の逆転(追い越し)を物理的に防止する直列フック
通常タイピング時におけるキーの順序逆転(sh ➔ hs)を構造的に防止する設計です。
- マッピング対象となるすべてのキーを、通常レイヤー(L0)においても漏れなく
$keyとして網羅フック登録します。 - すべてのキー打鍵が FSM エンジンを直列に通過するため、OSネイティブ入力とフック入力の間のレースコンディションが物理的にゼロになります。