Ghostty 開発ログ 003
原文は Mitchell Hashimoto により に公開されました。 このブログを購読する
こんにちは! Ghostty 👻 の3回目の公式開発ログへようこそ!
過去の開発ログを見逃した方や、Ghosttyが何なのかもっと知りたい方は、こちらのウェブサイトにあるGhosttyのページをご覧ください。
コミュニティアップデート:パブリックDiscordを開設しました!
パブリックDiscordサーバーを開設したことをお知らせできて嬉しいです!どなたでも参加歓迎です。Ghosttyについての質問、ターミナルエミュレータについての雑談、システムプログラミングやGPUプログラミングの話題など、何でもどうぞ。Discordはベータプログラムを拡大する場としても活用しています。ベータへの参加に興味がある方は、ぜひDiscordサーバーに参加して、ある程度アクティブに活動してみてください。
次に、9月5日にZig ShowtimeでGhosttyについてのトークを行う予定です。正確な時間やリンクなどの最新情報は、Zig ShowtimeのウェブサイトやX(旧Twitter)、Mastodonなどでご確認ください。トークの内容はまだ準備中ですが、Ghosttyの実装を駆け足で紹介しつつ、いくつか面白いポイントにスポットを当てる予定です。なにせZig Showtimeですので、Ghosttyの中でも特にZigに関わる部分にフォーカスしてお話しします。
キーボード入力処理はあなたを嫌っている(#282)1
私は、愚かで平凡なUS配列キーボードでタイピングする、愚かで平凡なアメリカ人に過ぎません。US配列のキーボードでは、aと打てば「a」が出て、'(アポストロフィ)を打てば「'」が出ます。shift+aと打てば「A」が出ます。簡単、簡単。あなたは嘘の玉座に座っているのです。
最初の厄介な兆候は、DvorakやColemakのような、非標準でありつつ英語中心のキーボードレイアウトです。US配列の物理キーボードでは、Dvorakユーザーはsと打てば「o」が出ることを期待し、ctrl+iを押せばctrl+cと同じ挙動になることを期待します。
二つ目の兆候はUnicodeシーケンスです。Macでは、US配列でalt+aを押すとåが入力されます。最新のベータグループに加わったノルウェー人のユーザーが、これが特に重要だと指摘してくれました。というのも、彼はUS配列を好んで使いつつ、ノルウェー語の単語を打つためにaltを使ったシーケンスを利用しているからです。
三つ目の兆候は、非標準のキーボードレイアウトです。デッドキーシーケンスとは何かご存知ですか?私は知りませんでした(なにせ愚かなUS配列ユーザーですから)。US配列では、すべてのキー入力はステートレスであることに慣れています。文字を大文字にするには、shift+Aを同時に押します。デッドキーシーケンスでは、shiftを押して離し、次にaを押すとAが表示される、といった具合です(これは実際のデッドキーシーケンスではありませんが、デッドキーシーケンスがどのように振る舞うかの例です)。実際のデッドキーシーケンスの例を挙げると、USインターナショナル配列では、'を押して離し、次にaを押すとáが入力されます。
キーボードでキーが押されると、いくつかのことが起こります。キーボードは物理スキャンコードを送信します。ソフトウェア側のキーボードレイアウト処理(たとえばQWERTYキーボードでDvorakレイアウトを使う場合)が、このスキャンコードを別のスキャンコードに変換します(Dvorakでは「i」が「c」のように振る舞います)。そして修飾キー(ctrl、altなど)と他のキー(文字キーなど)の組み合わせによって、1つ以上の文字が生成されることもあれば、されないこともあります(たとえばmacOSでalt+pを押すと「π」が生成されますが、US配列の物理キーボードでDvorakを使っている場合は同じ入力がalt+rになります)。
最後に、すべての修飾キーが消費されるわけではない、という点もキーバインドに関わってきます。たとえばUS配列でctrl+=にバインドした場合、ノルウェー配列ではそれがctrl+shift+0に相当します。shift+0で=が生成されたがctrlは消費されなかったため、最終的な入力はctrl+=であると判断しなければなりません。でも、もしユーザーが別にctrl+shift+0にもバインドしていたら、どちらを適用すべきでしょうか? 🤔
これらの説明はどれも非常に大雑把で、詳細を欠いています。キーボードレイアウト、入力処理、ターミナルのキーボード「プロトコル」、そしてOSレベルのAPIという、得体の知れない恐ろしい世界については、改めて1本のブログ記事としてじっくり書く予定ですので、今回の開発ログでは詳細は割愛します。どうぞご期待ください!
Ghosttyはこれらのユースケースに対応しなければならないだけでなく(なんとUS配列以外のキーボードユーザーも存在するのです)、さらにクロスプラットフォームでも対応しなければなりません。GhosttyはすでにmacOSとLinuxで動作しており、将来的にはWindowsでも動作することを目指しています。 😰 さて、Ghosttyは今やそれを実現しました。
視覚的にお見せできるのはデッドキーの状態処理くらいです。これは保留中の最後のデッドキーを描画するようにしました。その他の部分がすべて正しく動作するようになったことは、どうか私を信じてください。
さらに、Ghosttyはオプションとして明示的な物理キーマッピングにも対応しました。キーバインドをctrl+physical:0のように指定すると(physical:というプレフィックスに注目してください)、物理的な0キーだけがそのバインドをトリガーします。キーボードレイアウトによっては、このバインドが押せなくなる場合もあります。デフォルトでは、キーバインドは論理(変換後)キーに基づいて動作します。
Kittyキーボードプロトコルとその他(#292、#295)
キーボード入力の話にうんざりしている方は、このセクションは飛ばしてください。
キーボードのキーを文字入力にマッピングするだけでなく、キーボードイベントはエスケープシーケンスにもマッピングされる必要があります。そうすることで、ターミナル上で動作しているプログラムがどのキーが押されたかを知ることができるのです。
元々のターミナルプロトコルでは、キーボードのキーによって生成された文字をそのまま送信していました。「a」と打てば「a」が、「A」(shift+A)と打てば「A」が送られます。これには多くの制限がありました。たとえば、ターミナルプログラムはctrl-iとctrl-shift-iのような修飾キーの違いに反応できませんでした。どちらも同じデータを生成してしまうからです。
こうした欠点を解消するために、多くの追加キーボードプロトコルが開発されました。xtermはmodified keysシーケンスを、Paul Evansはfixtermsプロトコルを、そしてKittyのKovid Goyal氏はKitty Keyboard Protocolを開発しました。これらのプロトコルの要点は、キーが押されたときにターミナルが実行中のプログラムに何を送信するかを定義している、という点に尽きます。
これは仮定の話ではありません。これらのプロトコルはtmuxやneovimといった主要なプログラムで実装されており、そうでなければ不可能な何百ものキーバインドを追加で設定できるようになります。
Ghosttyは現在、これらすべてを実装しています。
私の知る限り、Ghosttyはこれらすべてを実装している数少ないターミナルの一つです。xtermのmodified keysとKittyの両方を実装しているのは、iTerm、Foot、そしておそらくWezTermだけだと思います。それらにKittyを加えたものだけが、そもそもKittyプロトコルを実装していると思います。ほとんどのターミナル(Terminal.app、Windows Terminal、Alacritty、Warp)は、キーボードプロトコルのいずれも実装していません。2
こちらはKittyキーボードプロトコルが動作している様子を示す動画です:
こちらはxtermのmodified keysプロトコルが動作している様子を示す動画です:
Linuxデスクトップの年(GTK)
直近のベータユーザー追加により、フルタイムでLinuxを使っているユーザーの数が2〜3人から5〜6人ほどに増え、それに伴いLinuxでの体験も大きく改善されました。
まず、GTKシングルインスタンスモード(#247)が有効化され、サポートされました。GTK版では、Ghosttyは単一のプロセスで動作するようになりました。2回目にGhosttyを起動しても、既存のGhosttyプロセス内に新しいウィンドウが開きます。これにより標準的なグラフィカルデスクトップ環境との親和性が高まるだけでなく、初回起動後のGhosttyの起動が超高速になります。
次に、Ghosttyがプライマリ(選択)クリップボードに対応しました(#266)。Linuxデスクトップには複数のクリップボードが存在します。「プライマリ」(または「選択」)クリップボードは、テキストを選択すると自動的にコピーされるもので、貼り付けは通常マウスの中ボタンで行います。これはctrl+shift+cやctrl+shift+vで使われるクリップボードとは別のものなので、クリップボードに複数のアイテムを保持できます。この機能は賛否が分かれることもあるのでご安心ください。copy-on-select設定で無効にできます。動作の様子は下の動画でご確認ください。キーバインドは一切押していません。これは選択クリップボードだけを使った操作です。
Linuxでも自動シェル統合に対応しました(#245)。シェル統合については開発ログ001で触れました。以前は、LinuxユーザーはGhosttyのshareディレクトリを指す環境変数を設定する必要がありました。現在、Linux版アプリケーションはghostty実行ファイルから上位に向かって、正しいフォルダ構造を持つshareディレクトリを探索します。標準的なFHSディレクトリレイアウト(Ghosttyがパッケージ化している標準的なレイアウト)でGhosttyをインストールすれば、Ghosttyが自動的にシェルを見つけて設定してくれます。
その他にも、Ghosttyのアプリアイコンが正しく表示されるようになったり(#251)、GTKアプリケーションがUS配列以外のキーボードレイアウトを処理できるようになったり(#271)、GTKアプリケーションが半透明のウィンドウ背景に対応したり(#264)など、多くの改善があります。
GhosttyをGTKベースのLinuxターミナルとして最高峰のものにしたいと強く思っています。私は普段GTKを常用しているわけではないので、この体験を素晴らしいものにするためにはテスターからのフィードバックに大きく依存しています。GhosttyのGTK版の使い心地が今とても良くなってきていることを、嬉しくご報告します!GTKアプリケーションはまだmacOS版に遅れをとっていますが、同等のレベルまで引き上げることを楽しみにしています!
おわりに
直近のベータテスターの皆さんには本当に感謝しています。@hovsaterさんには、キーボードレイアウトとマッピングに関する数々の深刻な問題を明らかにし、そのすべてを修正するよう後押ししてくれたことに感謝します。@cryptocodeさんは、幅広文字や複数コードポイントからなる書記素(グラフェム)、そしてそれらと選択やソフトラップとの相互作用に関するエッジケースで、十数件ものバグを発見してくれました。そしてLinux周りの改善に貢献してくれた、感謝に値する多くの新しいテスターの皆さんにもお礼を申し上げます。ありがとうございます!
最新情報を追いたい方は、X(旧Twitter)やMastodonで私をフォローしてください(リンクはフッターにあります)。このブログにはRSSフィードもあります。
Boo. 👻
脚注
これは素晴らしいブログ記事Text Rendering Hates Youへの参照で、強くおすすめします。 ↩
これらのターミナルエミュレータの作者の皆さんには深い敬意を抱いており、決して攻撃する意図はありません。ここでは各ターミナルがどの機能に対応している/していないかを事実として述べているだけです。もし誤りがあれば、ぜひ教えてください。すぐに修正します。 ↩
記事をランダムに読む
コメント
ログインしてコメントする