Skip to content

Add Programmer Dvorak (JIS/US) keyboard layout support - #377

Closed
tsugri wants to merge 1 commit into
azooKey:mainfrom
tsugri:feat/programmer-dvorak
Closed

tsugri wants to merge 1 commit into
azooKey:mainfrom
tsugri:feat/programmer-dvorak

Conversation

@tsugri

@tsugri tsugri commented Sep 24, 2026

Copy link
Copy Markdown

Programmer Dvorak配列を追加する対応です。

  1. OS標準(com.apple.keylayout.Romaji/com.apple.keylayout.US)を利用し、内部の変換テーブルで処理する方針とした理由について
    システムに標準で存在しないレイアウト(com.apple.keyboardlayout.Programmer Dvorak 等の外部 .keylayout ファイル)を要求するのではなく、OS標準の識別子を要求した上で内部のテーブルで変換する設計としました。理由は以下の2点です。
    getUserAction の肥大化防止と安全性の担保(カプセル化):
    現在の getUserActionは、基本的にQWERTY配列を前提とした作りになっています。もし外部の.keylayoutファイルの出力を許容してしまうと、その外部ファイル固有の状態や未知の出力仕様を前提とした分岐処理を getUserAction内に大量に追加せざるを得なくなります。
    カスタム配列が増えるたびにgetUserActionが収拾のつかない複雑な処理に陥るのを防ぎ、既存の配列処理への影響をゼロにするため、変換ロジックを内部のテーブルに閉じる方が安全だと判断しました。
    また、外部の.keylayoutファイルがアップデート等で仕様変更された際の予期せぬ動作破綻も排除できます。(外部依存リスクは避けるべき、 .keylayoutファイルは認めない方針とするべきという考えです)
    また、OS側の変換(外部レイアウト)に依存してしまうと、JIS特有の物理キーのハードウェア仕様(特定のキーでShift状態の信号が喪失する等)を回避することができません。OSからは標準のベース文字を受け取り、最終的な出力を内部のテーブルと直前フック関数で完全にコントロールすることで、ハードウェアの不条理な制約を確実に吸収できるようにしています。

  2. 既存の配列(QWERTY等)の処理への影響をゼロにする配慮
    今回追加したDVPや物理キーのフック処理は、対象の配列が選択された場合のみ有効になる方式(対象外の場合は nil を返し、元の fallthrough や標準の辞書翻訳へ流す設計)としています。これにより、既存のQWERTY等の標準処理には影響を与えない(デグレードを起こさない)安全な構造を担保しています。

  3. 物理キーへの直接介入(JIS特有のShift状態喪失の回避)について
    Programmer Dvorakは数字キーの列が記号になる等の特殊な配列ですが、macOSのJISハードウェア仕様上、特定のキー(29番キーの 0 や、94番キーの _ など)はShiftの有無に関わらず同じ信号がOSから送られてしまいます。
    そのため、switch文の直前に物理キーフック(jisZeroKeyOutput,jisUnderscoreKeyOutput)を新設し、特定の配列のみ強制的に出力を上書きする処理を追加しました。

  4. typeBackSlash 設定に対する「スワップ(入れ替え)」
    標準配列では「¥」と「\」はどちらか一方に統一されますが、今回追加した配列のように「¥」と「\」の専用キーが両方独立して存在する場合があり得ます。
    そのため、hasDistinctBackSlashAndYen というフラグを新設し、このフラグが有効な配列については、typeBackSlash 設定がONの際に文字を統一するのではなく、2つのキーの配置を入れ替える(スワップする)という新しい挙動を実装しました。

  5. DVP配列の設定を「JIS用」と「US用」の2つに分離した経緯と理由について
    設定項目を1つに統合(内部判定)せず、あえて「ProgrammerDvorak_JIS - QWERTY ⌘」と「ProgrammerDvorak_US - QWERTY ⌘」の2つの独立した設定を用意し、ユーザーに明示的に選択させる設計としました。
    【内部切り替えを見送った理由について】
    設定項目は「ProgrammerDvorak - QWERTY ⌘」の1つだけとし、プログラム内部で現在のキーボードがJISかUSかを自動判定して layoutIdentifierやkeyRemapTableを動的に切り替えるのが理想的です。
    極力設定項目は増やしたくなかったため、最初は内部切り替えの方向で実装を検討しました。
    しかし内部での動的切り替えには「パフォーマンス」と「状態の同期」の間に解決困難なジレンマがあり、デメリットが大きすぎると判断しました。
    キーボードの種別を確実にするため、キー入力イベント(打鍵)ごとにOSへ状態を問い合わせる設計にすると、クリティカルパスに重い処理が挟まり、タイピングの遅延(レイテンシ)や負荷の増大に直結してしまいます。
    負荷を避けるため「IMが有効になった瞬間」のみ判定してキャッシュする設計にした場合、
    JIS内蔵キーボードとUS外付けキーボードを繋いだマルチキーボード環境などで「ユーザーがIMを切り替えずに別の物理キーボードを叩き始めた」際に、内部の判定状態と実際のハードウェアがズレてしまい、出力が完全に破綻するリスクがあります。
    上記のような状態ズレのリスクやパフォーマンスの懸念のリスクを抱えるよりは、設定項目が2つに増えても、静的なプロファイルとして分離する方が堅牢性が高いと判断しました。

  6. Optionキー押下時における標準仕様(反転)との整合性
    macOSおよびazooKeyの標準仕様である「Optionキー押下時は、typeBackSlash 設定に対して逆の文字を出力する」という挙動を、独自配列のフック処理やスワップ処理の中にも(isOptionPressed の判定を加えることで)厳密に組み込み、システム全体の操作感の統一をしました。

  7. コメント・ドキュメント
    今後、新たなカスタム配列を追加する場合のための説明文を付けました。

以上の設計方針とした実装としております。懸念点やより良いアプローチ等がありましたらご指摘いただけますと幸いです。
マージのご検討のほど、よろしくお願いいたします。

@ensan-hcl

ensan-hcl commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

こちら、申し訳ないのですがマージしない方針としたいです 🙏

  • Programmer Dvorakなる配列に関して、信頼できる仕様文書などがない
  • 利用者が極端に少ないことが見込まれる(開発開始から2年経って初めての要望であり、相応の利用者数と想定できる)
  • azooKey-Desktopの中で独自に実装する形となる分、メンテナンスするコストが他のマイナーなレイアウトに比べても高い

フォークでご対応いただけると嬉しいです。

@tsugri

tsugri commented Sep 25, 2026

Copy link
Copy Markdown
Author

ご検討いただきありがとうございます。

信頼できる仕様文書としては、
発案者のRoland Kaufmann氏の公式サイトにある.keylayoutと、
Linux公式の定義ファイルが標準仕様に当たるかなと思います。

Programmer DvorakはLinuxで標準採用され20年近く経っていると思いますので、
利用実績と需要は一定程度あるとは思います。
MacOS標準に含まれない英字配列の中では利用者の多い方ではありますが、
全体から見れば極端に利用者が少ない部類に入るかもしれません。
事実上、MacOS標準に含まれない英字配列を含めない方針ということになるかなと思いました。
それは安全で正しい判断と思います。
というのはMacOS標準に含まれない配列をその都度対応し処理を入れるとなると、
UserAction.swiftのgetUserActionが配列特有の処理が増え複雑になりやすいからです。
その懸念がありましたので、
今回の対応内容はUS/Romajiから変換するテーブルを用いる方法を取り、
Programmer Dvorak以外の配列も追加可能なできるだけ汎用性の高い作りとし、
getUserActionもなるべく配列独自の処理を入れないで済むような配慮はしたものですが、
複雑化する事を避けられないことは実感していたところです。

おっしゃられている通りMacOS標準に含まれない配列を追加することは独自に実装する形となるためメンテナンスコストが高くなります。
マージしない方針である旨、承知しました。
改めて本対応を検討いただきありがとうございました。

@ensan-hcl

Copy link
Copy Markdown
Member

ご理解いただきありがとうございます 🙏

@ensan-hcl ensan-hcl closed this Sep 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants