Ghostty 開發日誌 003
原文由 Mitchell Hashimoto 于 發布,訂閱此部落格
哈囉!歡迎來到 Ghostty 的第三篇官方開發日誌 👻!
如果錯過了之前的開發日誌,或是想更了解 Ghostty 是什麼,請參考 本站上的 Ghostty 介紹頁面。
社群動態:公開 Discord 伺服器上線!
很高興跟大家分享,我們現在有了公開 Discord 伺服器!歡迎任何人加入,詢問關於 Ghostty 的問題、聊聊終端機模擬器、聊聊系統程式設計、GPU 程式設計等等。我們也正透過 Discord 來擴大 Beta 測試計畫,所以如果你有興趣加入 Beta,請加入 Discord 伺服器並保持一定的活躍度。
接下來,我將在 9 月 5 日的 Zig Showtime 上發表關於 Ghostty 的演講。確切的時間與連結請留意 Zig Showtime 官方網站、Twitter、Mastodon 等管道的更新。演講內容還在準備中,但大致上會快速導覽 Ghostty 的實作,並點出幾個有趣的重點。畢竟是 Zig Showtime,我會更聚焦在 Ghostty 中與 Zig 相關的部分。
鍵盤輸入處理討厭你(#282)1
我只是個用著笨笨的美規鍵盤配置的笨笨美國人。在美規鍵盤上,你按 a 就得到「a」,按 '(單引號)就得到「'」。你按 shift+a 就得到「A」。簡單,太簡單了。你正坐在謊言堆砌的王座上。
麻煩的第一個徵兆,是那些非標準但仍以英文為中心的鍵盤配置,例如 Dvorak 或 Colemak。在美規實體鍵盤上,Dvorak 使用者按 s 會期待得到「o」,而按下 ctrl+i 時,則會期待它表現得像 ctrl+c。
麻煩的第二個徵兆,是 Unicode 輸入序列。在 Mac 上,使用美規配置時,alt+a 會產生 å。最近一輪 Beta 測試加入了一位挪威使用者,他提到這點特別重要,因為他偏好使用美規配置,但會用 alt 組合來輸入挪威語單字。
麻煩的第三個徵兆,是非標準的鍵盤配置。你知道什麼是死鍵序列嗎?我原本不知道(還記得吧,我只是個笨笨的美規使用者)。在美規配置上,我們習慣所有的按鍵都是無狀態的。要輸入大寫,你就是同時按下 shift+A。同時按下。但如果是死鍵序列,你會先按 shift、放開,再按 a,然後才會看到 A(這不是真實世界存在的死鍵序列,只是用來說明死鍵序列的運作方式)。一個真實的死鍵序列,在美規國際配置上是這樣:先按 '、放開,再按 a,就會得到 á。
當一個人在鍵盤上按下按鍵時,會發生幾件事。鍵盤會送出一個實體掃描碼(physical scancode)。軟體層的鍵盤配置處理(例如在 QWERTY 實體鍵盤上使用 Dvorak 配置)會將這個掃描碼轉譯成另一個掃描碼(「i」在 Dvorak 下作用就像「c」)。修飾鍵(ctrl、alt 等)與其他按鍵(例如字母)的組合可能接著會產生一個或多個字元(例如在 macOS 上 alt+p 會產生「π」,但在美規實體鍵盤上使用 Dvorak 時,同樣的效果要按 alt+r)。
最後,並非所有的修飾鍵都會被消耗掉,而這對按鍵綁定來說很重要。舉例來說,如果你在美規配置上綁定了 ctrl+=,在挪威配置上那會是 ctrl+shift+0,你必須知道 shift+0 產生了 =,但並沒有消耗掉 ctrl,所以最終的輸入是 ctrl+=。但如果使用者同時也綁定了 ctrl+shift+0,你又該用哪一個呢?🤔
以上這些說明都非常籠統、缺乏細節。我打算另外寫一篇完整的部落格文章,專門來談鍵盤配置、輸入處理、終端機鍵盤「協定」以及作業系統層級 API 這些宛如古神恐怖般的東西,所以在這篇開發日誌中就先跳過細節。敬請期待!
Ghostty 不僅得處理這些使用情境(因為事實證明,非美規鍵盤的使用者是存在的),還必須跨平台做到這件事,因為 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 協定,而 Kovid Goyal(Kitty 的作者)則發展了 Kitty Keyboard Protocol。這些協定的核心概念很簡單,就是定義當按鍵被按下時,終端機要傳送什麼給正在執行的程式。
這些並非假設性的問題。這些協定已被 tmux、neovim 等重要程式實作,能讓你綁定比以往多上數百種快速鍵組合。
Ghostty 現在已全部實作了這些協定。
就我所知,Ghostty 是少數幾個完整實作了上述所有協定的終端機之一。我相信只有 iTerm、Foot,或許還有 WezTerm 同時實作了 xterm modified keys 和 Kitty。我認為也只有這些再加上 Kitty 本身有實作 Kitty 協定。大多數終端機(Terminal.app、Windows Terminal、Alacritty、Warp)則完全沒有實作任何鍵盤協定。2
以下是 Kitty 鍵盤協定運作的影片:
以下是 xterm modified keys 協定運作的影片:
桌面 Linux 元年(GTK)
上一批 Beta 使用者讓我們的 Linux 全職使用者人數從原本的兩、三位增加到約五、六位,也因此帶來了許多 Linux 使用體驗上的改進。
首先,GTK 單一實例模式(#247)現已啟用並獲得支援。在 GTK 環境下,Ghostty 現在以單一行程執行。第二次啟動 Ghostty 時,會在既有的 Ghostty 行程中開啟一個新視窗。這能與標準的圖形桌面環境良好整合,也讓 Ghostty 在首次啟動之後的再次啟動變得非常快速。
接下來,Ghostty 現在支援了主要(選取)剪貼簿(#266)。Linux 桌面擁有多個剪貼簿。「主要」(或稱「選取」)剪貼簿會在你選取文字時自動複製文字,通常透過滑鼠中鍵來貼上。這是與 ctrl+shift+c 和 ctrl+shift+v 所使用的剪貼簿分開的獨立剪貼簿,因此你可以同時在剪貼簿中存放多個項目。這個功能有時頗具爭議,所以別擔心,你可以透過 copy-on-select 設定來將它關閉。你可以在下方的影片中看到它的運作。請注意,我完全沒有按下任何鍵盤快速鍵;這完全是使用選取剪貼簿的效果。
Linux 現在也支援自動 shell 整合(#245)。我在開發日誌 001 中談過 shell 整合。先前,Linux 使用者必須設定一個環境變數來指向 Ghostty 的 share 目錄。現在 Linux 版應用程式會從 ghostty 執行檔的位置向上搜尋具有正確資料夾結構的 share 目錄。如果你使用標準的 FHS 目錄架構來安裝 Ghostty(也就是 Ghostty 打包時採用的標準架構),Ghostty 就會自動找到並設定好你的 shell。
還有更多改進,Ghostty 的應用程式圖示現在能正確顯示(#251)、GTK 版本能處理非美規鍵盤配置(#271)、GTK 版本支援半透明視窗背景(#264)等等。
我非常希望 Ghostty 能成為頂尖的 GTK Linux 終端機。我自己並非全時間使用 GTK,所以非常仰賴測試者提供回饋,才能讓體驗變得更好。我很高興地報告,Ghostty 在 GTK 上的體驗現在已經相當不錯了!GTK 版本目前仍落後於 macOS 版本的體驗,但我期待能讓兩者達到一致的水準!
結語
最近一輪的 Beta 測試者真的非常出色。我想感謝 @hovsater 揭露了所有明顯的鍵盤配置與對應問題,並促使我將它們一一修復。@cryptocode 則揭露了十多個與寬字元、多碼點字形(multi-codepoint grapheme)及其與選取和自動換行互動相關的邊界案例錯誤。還有許多新的測試者也為 Linux 相關的改進提供了寶貴的貢獻,值得致謝。謝謝大家!
如果你想掌握最新動態,請在 Twitter 或 Mastodon 上追蹤我(連結在頁尾)。這個部落格也有提供 RSS 訂閱。
Boo. 👻
註腳
這是參考了非常精彩的部落格文章 Text Rendering Hates You,我非常推薦一讀。↩
我非常尊敬這些終端機模擬器的作者,希望這不會被視為任何形式的攻擊。我只是想客觀陳述它們支援與不支援哪些功能。如果我有誤,煩請告知,我會立刻更正。↩
隨機一篇部落格
留言
登入後參與討論