# 設定ファイル仕様 > [01_project-brief.md](../01_project-brief.md) §6 の TOML 案を確定させた仕様。実装は `src/keymap.rs`(キー記法・マッチング)と `src/config.rs`(読み込み・検証)。 > マッチング優先順位の設計判断は [ADR 0004](./decisions/0004-keymap-matching-priority.md) を参照(ADR = Architecture Decision Record: 設計判断の記録)。 - 作成日: 2026-07-18 - 作成: Claude Code(AI モデル: claude-fable-5)/レビュー・承認: オーナー - 最終更新: 2026-08-03 — §6 の `cursor_color` に**白い縁**の説明を追加(v0.8 の受け入れで、実装にあって仕様に無い挙動として見つかった。[ADR 0067](../v0.8/decisions/0067-ime-cursor-color.md)) - 更新: 2026-07-31 — §2 に記号(OEM)キーを追加し、「v0.1 の制限」と §5 将来拡張から外した(v0.7・[ADR 0063](../v0.7/decisions/0063-symbol-keys.md)) - 更新履歴: 2026-07-19 — 用語「チョード」を「コマンド」に変更(英語ドキュメントの chord に対応)/§6 `[ime_indicator]` を追加(ADR 0020) > **この文書はバージョン非依存の仕様の正本である。** `docs/v0.1/` に置かれているのは初出がそのバージョンだったためで、以後の変更もここに反映する(ADR は書き換えないという規約は ADR に対するもの)。 --- ## 1. ファイル配置と全体構造 - 既定パス: `%APPDATA%\winremap\config.toml`(`--config ` で上書き可) - 文字コード: UTF-8 設定はトップレベルの全体設定と `[[keymap]]` セクションの配列で構成する。 ### トップレベル設定 | フィールド | 型 | 既定 | 意味 | |---|---|---|---| | `[macro]` の `delay_ms` | 整数(0-15) | 0 | マクロ出力(§3.5)の各ストローク間の待ち時間(ms)。一括注入のマクロを取りこぼすアプリ(WinUI 系の新しいメモ帳等)では 5〜10 を指定する([ADR 0019](./decisions/0019-macro-delay-in-config.md)・[ADR 0039](../v0.2/decisions/0039-macro-section-in-config.md))。**v0.2 でトップレベルの `macro_delay_ms` から移動した。旧キーも引き続き有効だが、両方書くと検証エラーになる** | CLI の `--macro-delay` はこの設定より優先される(実験用)。 ```toml # グローバル(全アプリ適用) [[keymap]] name = "global" # 任意。省略時は "keymap #N"(エラー表示用) application = ["*"] # 必須。"*" = 全アプリ [keymap.remap] "CapsLock" = "LCtrl" # アプリ別: メモ帳でのみ Ctrl+H → Backspace [[keymap]] name = "notepad" application = ["notepad.exe"] [keymap.remap] "C-h" = "Back" # グローバル + 除外: ターミナル以外に Emacs 風バインドを適用(ADR 0011) [[keymap]] name = "emacs" application = ["*"] exclude = ["WindowsTerminal.exe"] [keymap.remap] "C-f" = "Right" "C-t" = ["C-Right", "C-Left", "C-S-Right"] # マクロ出力(§3.5) "A-x u" = "C-z" # 2 ストロークシーケンス(§3.4) ``` ### フィールド | フィールド | 型 | 必須 | 意味 | |---|---|---|---| | `name` | 文字列 | 任意 | エラーメッセージ・ログでの識別用 | | `application` | 文字列配列 | **必須** | 適用対象の exe 名(例 `"notepad.exe"`)。`"*"` で全アプリ。**`"*"` と具体名の混在は設定エラー**(意味が曖昧になるため) | | `exclude` | 文字列配列 | 任意 | 除外する exe 名。**`application = ["*"]` のときのみ指定可**(具体名リストからの除外は「listしない」ことで表現できるため。ADR 0011) | | `remap` | テーブル | 任意 | `"入力キー" = "出力"` の対。出力は文字列(単一コマンド)または文字列配列(マクロ、§3.5)。省略時は空 | - exe 名の比較は **ASCII 大文字小文字を区別しない**(Windows のファイル名慣習)。拡張子 `.exe` まで含めた完全一致で、部分一致・glob は v0.1 では非対応 - 未知のフィールドはエラー(typo の検出のため) ## 2. キー記法 `修飾キープレフィックス*` + `キー名`。fakeymacs / Keyhac ユーザーが読める形式を踏襲する。 この「修飾キー+キー 1 個の同時押し(1 打鍵分)」を本ドキュメントでは**コマンド**と呼ぶ(英語ドキュメントでは chord)。 ### 修飾キープレフィックス(大文字小文字不問、順不同、重複はエラー) | 記法 | 意味 | |---|---| | `C-` | Ctrl(左右不問) | | `A-` | Alt(左右不問) | | `S-` | Shift(左右不問) | | `W-` | Win(左右不問) | ### キー名(大文字小文字不問) | 分類 | 記法 | VK(Virtual-Key)コード | |---|---|---| | 英字 | `a`-`z` | 0x41-0x5A | | 数字 | `0`-`9` | 0x30-0x39 | | ファンクション | `F1`-`F24` | 0x70-0x87 | | 編集 | `Back`(別名 `Backspace` / `BS`), `Tab`, `Enter`(`Return`), `Esc`(`Escape`), `Space`, `Insert`(`Ins`), `Delete`(`Del`) | 0x08, 0x09, 0x0D, 0x1B, 0x20, 0x2D, 0x2E | | 移動 | `PageUp`(`PgUp`), `PageDown`(`PgDn`), `End`, `Home`, `Left`, `Up`, `Right`, `Down` | 0x21-0x28 | | ロック | `CapsLock` | 0x14 | | 修飾キー単体 | `LShift`, `RShift`, `LCtrl`(`LControl`), `RCtrl`(`RControl`), `LAlt`, `RAlt`, `LWin`, `RWin`, `Apps`(`Menu`) | 0xA0-0xA5, 0x5B, 0x5C, 0x5D | | **記号(OEM)キー** | **そのキーに刻印されている 1 文字**(`;` `/` `-` `[` 等)。別名 `Oem1`〜`Oem8`, `Oem102`, `OemPlus`, `OemComma`, `OemMinus`, `OemPeriod` | 0xBA-0xC0, 0xDB-0xDF, 0xE2 | ### 記号(OEM)キー(v0.7 で対応。[ADR 0063](../v0.7/decisions/0063-symbol-keys.md)) OEM = Original Equipment Manufacturer。VK(Virtual-Key)コードと記号の対応が**キーボードによって違う**キー群である(`0xC0` は JP 106 で `@`、US 101 で `` ` ``)。 - **刻印の文字で書く**のが主の記法。どのキーがそれかは設定の読み込み時に Windows へ問い合わせて解決する(`VkKeyScanW` / `MapVirtualKeyW`)。**静的な表を持たない** - `Oem*` の別名は**配列に依存しない**。文字を持たないキー(`Oem8`)や、同じ文字を刻む 2 つのキー(US 配列の `\` は `Oem5` と `Oem102` の両方)を指すのに要る - **Shift が要る文字は書けない。** US 配列の `@` は `Shift`+`2` なので `S-2` と書く。暗黙に Shift を補うと `C-@` と `C-S-2` が同じルールになり、その重複が機械によって発生したりしなかったりするため(§3.1 の完全一致規則と衝突する)。エラーには書くべき綴りを添える - 解決は**読み込み時に 1 回**。キーボードを差し替えたらリロードが要る - 同じ文字を 2 つのキーが刻む場合は **VK の小さいほうに解決する** **制限**: - IME 関連キー(変換・無変換・かな)は Non-goal(ブリーフ §3.3) - **修飾キー(`LCtrl` / `LShift` 等)を入力側(LHS: Left-Hand Side、ルールの左辺)にすることはできない**(設定エラー)。フックが修飾キーをコマンド判定の状態管理に使うため。出力側(RHS: Right-Hand Side、右辺)には使える(`"CapsLock" = "LCtrl"`) ## 3. マッチングと置換の意味論 ルールは LHS(入力)に修飾キーがあるかどうかで 2 種類に分かれる。 ### 3.1 修飾キー付きルール(例 `"C-h" = "Back"`) - **完全一致**で判定する。`C-h` は「Ctrl のみが押されている状態で H」にマッチし、Ctrl+Shift+H にはマッチしない - 置換時は**修飾キー状態も RHS に合わせる**。`"C-h" = "Back"` は物理 Ctrl が押下中でも、アプリには修飾なしの Backspace が届く(sender が修飾キーを一時的に解放・復元する。[ADR 0005](./decisions/0005-modifier-lift-restore.md)) - RHS には修飾キーを付けられる(例 `"C-i" = "S-Tab"`) - **Alt / Win を含むコマンド**では、マスクキーの注入によりメニューバー / スタートメニューの誤発動を防止する([ADR 0015](./decisions/0015-menu-mask-key.md)) ### 3.2 単キールール(例 `"CapsLock" = "LCtrl"`) - **修飾キーの状態に関係なく**キーだけを置き換える(Ctrl+CapsLock 押下中でも発動する)。CapsLock→Ctrl のような「キー自体の差し替え」用途のため - 物理修飾キーには触らない。そのため **RHS に修飾キーを付けることはできない**(設定エラー。v0.1 の制限) ### 3.3 優先順位(ADR 0004) 1. **アプリ別キーマップ > グローバル(`*`)キーマップ**(定義順に関係なく) 2. 同じ分類内では**定義順**。最初にマッチしたルールで確定 3. 同一キーマップ内では**修飾キー付きルール > 単キールール**(`C-h` ルールがあるアプリで Ctrl+H を押した場合、`h` の単キールールより優先) 同一キーマップ内の判定順は「修飾キー付きルール → シーケンスのプレフィックス → 単キールール」。マッチしなかったイベントは**素通し**(変換しない)。 ### 3.4 2 ストロークシーケンス([ADR 0013](./decisions/0013-two-stroke-sequences.md)) LHS を空白区切りの 2 コマンドにすると Emacs 風プレフィックスキーになる(例 `"A-x u" = "C-z"`、`"A-x C-s" = "C-s"`)。 - 1 打鍵目(プレフィックス)は**修飾キー付きコマンド必須**(素のキーをプレフィックスにすると通常タイピングを飲み込むため設定エラー) - プレフィックスの押下は抑止され、次の非修飾キー押下で確定する。**タイムアウトはない**(Emacs と同じ) - 未定義の 2 打鍵目は**握りつぶす**(Emacs 同様。タイプミスがアプリに漏れない) - 同じコマンドを「通常ルール」と「プレフィックス」の両方に使うことはできない(設定エラー) - シーケンスは 2 ストロークまで。3 ストローク以上は設定エラー ### 3.5 マクロ出力([ADR 0012](./decisions/0012-macro-outputs.md)) RHS を文字列配列にすると、各コマンドを順に 1 回ずつタップするマクロになる(例 `"C-t" = ["C-Right", "C-Left", "C-S-Right"]`)。 - 最大 8 コマンド。全体を 1 回の `SendInput` バッチで送出し、実入力が割り込まない - 実行は**押下時に 1 回**。キーリピートでは再実行されない(押しっぱなしでマクロが連射されない) - 押下中の修飾キーは実行前に一時解除され、実行後に復元される - 単キールール(§3.2)の RHS には使えない ## 4. エラー報告 - TOML 構文エラー: toml クレートの行番号・桁付きメッセージをそのまま表示 - 意味エラー(不正なキー記法、`"*"` と具体名の混在、単キールールへの修飾 RHS、正規化後に重複するルール等): **行番号・桁番号付き**で、該当キーマップ名とともに報告する。複数のエラーは**一括で全件**報告する(1件ずつ直させない) ``` invalid configuration: line 12, column 1: in `jetbrains-terminal-fix`: unknown key name `Bcak` ``` ### エラー時の挙動([ADR 0008](./decisions/0008-reload-via-tray-menu.md)) - **起動時**にエラー: エラーを表示して終了する(設定が効いていない状態で常駐しない) - **リロード時**(トレイメニュー「Reload config」)にエラー: **直前の有効な設定を維持**し、コンソールとトレイのツールチップにエラーを表示する。設定の編集ミスでリマップは止まらない - リロードは新しいテーブルを構築してからの atomic swap で、キーイベントの取りこぼしなく切り替わる(ADR 0003) ## 5. 将来拡張(本仕様の対象外) - tap/hold、マークモード、3 ストローク以上のシーケンス - ウィンドウタイトルによるマッチ - 左右個別の修飾キープレフィックス(`LC-` 等) ## 6. IME 状態インジケーター(`[ime_indicator]`) IME がオンになった瞬間にアクティブウィンドウ中央へ半透明マークを一時表示する独立機能([ADR 0020](./decisions/0020-ime-indicator-scope.md)、設計: [08_ime-indicator-design.md](./05_ime-indicator-design.md))。**既定は無効(opt-in)**で、節ごと省略できる。 ```toml [ime_indicator] enabled = true # 既定 false duration_ms = 800 # 表示時間(ms) size = 96 # パネルの一辺(論理 px) opacity = 200 # パネル全体の不透明度 ``` | フィールド | 型 | 範囲 | 既定 | 意味 | |---|---|---|---|---| | `enabled` | 真偽値 | — | `false` | 機能の有効化 | | `duration_ms` | 整数 | 100-5000 | 800 | フェードアウト開始までの表示時間(ms) | | `size` | 整数 | 32-256 | 96 | パネルの一辺(論理 px。DPI スケール前) | | `opacity` | 整数 | 0-255 | 200 | パネル全体の不透明度(255 = 不透明) | | `trigger_keys` | 文字列配列 | キー記法(§2) | `[]` | 組み込みのトグル候補キー(変換・無変換・かな・半角/全角・IME On/Off)に**追加**する切替検知キー([ADR 0021](./decisions/0021-ime-indicator-trigger-keys.md))。例: Windows 11 IME の Ctrl+Space 切替を使う場合は `["C-Space"]`。修飾キー込みの完全一致で判定。修飾キー単体は設定エラー | | `show_app_name` | 真偽値 | — | `false` | パネルの下に対象アプリの exe 名(例 `chrome.exe`)を表示する([ADR 0024](./decisions/0024-ime-indicator-app-name.md))。ウィンドウタイトルは表示しない。名前の幅に応じてパネル幅が広がり、上限を超える分は省略記号になる | | `change_cursor_color` | 真偽値 | — | `false` | **IME がオンの間、マウスカーソルに色を付ける**([ADR 0067](../v0.8/decisions/0067-ime-cursor-color.md))。矢印とテキストの I ビームの 2 つが対象。`enabled` とは独立で、パネルを出さずにカーソルだけ使える | | `cursor_color` | 文字列 | `#rrggbb` | `#0078d4` | 上の色(既定は WinRemap のアイコンの青)。カーソルの形はそのままに**明るさに応じて着色**するので、黒い輪郭は黒のまま、白い部分がこの色になる。加えて**輪郭に白い縁を合成して足す** — 着色すると本体の明るさが下がり(`#0078d4` は白の約 37%)、**暗い背景のアプリでは見失う**ため。明るさが正反対の 2 色になるので、背景が明るくても暗くてもどちらかが必ず立つ | - `change_cursor_color` は**セッション全体のカーソルを置き換える**(`SetSystemCursor`)。WinRemap の中だけの変更ではない - **色が付いた状態で WinRemap が異常終了すると、カーソルは色が付いたまま残る。** これは仕様である — 色が付くのは IME がオンのときだけなので、**「色が付いているのにトレイに WinRemap が居ない」=異常終了**と読める([ADR 0067](../v0.8/decisions/0067-ime-cursor-color.md)) - 次に WinRemap を起動すると元に戻る。サインアウトでも戻る(カーソルはログオン時にレジストリから読み直されるため) - 全フィールド任意(`enabled = true` だけの指定も可。他は既定値) - タスクバー・デスクトップのクリックでは表示されない(シェル面は検知対象外。[ADR 0023](./decisions/0023-ime-indicator-query-target.md))。UWP アプリ(設定アプリ等)は CoreWindow 経由で照会するベストエフォート対応 - 範囲外の値・未知のフィールドは他セクションと同じく行番号付きの設定エラー(§4) - リロード時はキーマップと同じ atomic swap で切り替わる。`enabled = false` へのリロードで機能は完全に停止する - 注: テーブル形式のため、`[[keymap]]` の後に書いても TOML 構文上問題ない(`[macro]` も同様)