| RFC-0096:使用者輸入架構 | |
|---|---|
| 狀態 | 已接受 |
| 區域 |
|
| 說明 | 在具有圖形使用者介面和多個執行階段的系統上,傳送使用者輸入事件 (鍵盤、滑鼠、觸控等) 的 Fuchsia 高階架構。 |
| 問題 | |
| Gerrit 變更 | |
| 作者 | |
| 審查人員 | |
| 提交日期 (年-月-日) | 2021-04-15 |
| 審查日期 (年-月-日) | 2021-05-26 |
摘要
本 RFC 說明在 Fuchsia 上,透過圖形使用者介面和多個執行階段,傳送使用者輸入事件 (鍵盤、滑鼠、觸控等) 的目標高階架構。使用者可透過各種方法/裝置 (包括鍵盤、滑鼠、觸控和按鈕) 輸入內容。本 RFC 涵蓋 Fuchsia 上的輸入事件,從驅動程式庫層級的原始資料到分派給使用者空間軟體 (例如 Flutter 應用程式) 的輸入事件。本文所述元件在發布時仍處於開發階段。
提振精神
為支援 Fuchsia 的包容性理念,Fuchsia 輸入內容必須為建構在不同執行階段之上的元件提供平台層級的支援,這些元件會使用不同的 UI 架構 (例如 Flutter、Chromium),並允許產品擁有者自訂輸入行為。在其他平台上,這些行為通常會納入特定 UI 架構的實作項目。Fuchsia 為分離式平台輸入處理作業帶來許多獨特挑戰,與特定 UI 架構的具體細節有所不同。
在 Fuchsia 程式碼中,目前有多個輸入轉送路徑 (根層級簡報者、輸入管道),但關於偏好路徑和遷移計畫的公開指引有限。這份 RFC 概述了 Fuchsia 上使用者輸入轉送的目標架構,並提供指引,說明如何擴充輸入處理功能,以因應未來的用途。
需求條件
- 安全性:Fuchsia 輸入堆疊可讓您輕鬆建構安全產品。
- 輸入事件可能包含密碼和付款資料等私密資料,以及使用者活動時間的相關資訊。所有使用者輸入事件都應視為個人識別資訊,且只能由受信任的系統元件傳送至使用者軟體。
- 如果路徑設定有誤,使用者輸入內容也可能遭到濫用,例如惡意 UI 導致使用者點選他們不打算點選的按鈕 (「點擊劫持」)。
- Fuchsia 平台應盡可能鼓勵開發人員建構安全產品,提供易於瞭解的 API 介面,並稽核使用者輸入事件在系統中的流動情形。
- 正確性:輸入事件的傳送方式符合使用者預期。
- Fuchsia 輸入系統負責解讀情境中的輸入事件,並將事件傳送至目前在系統上執行的正確目標元件。不過,「正確」的定義可能因事件和產品類型而異。
- 即使 UI 正在播放動畫或變更大小,輸入事件的傳送作業也應保持一致。
- 有時事件可能會同時傳送至多個元件 (例如鍵盤快速鍵)。
- 效能:使用者輸入速度夠快。
- 確切的延遲需求因輸入裝置和產品類型而異,但輸入傳送對延遲特別敏感,應盡量快速,讓使用者不會感覺到延遲。
- 輸入架構應避免造成不必要的延遲。特別是處理程序環境切換時,應避免不必要的封鎖呼叫。
- 可自訂性:系統應支援以 Fuchsia 平台建構的不同產品,並提供不同的使用者輸入行為。* 具體來說,產品
<0x不過,本 RFC 建議的初始實作方式,只會滿足部分最終自訂需求。(請參閱「輸入管道自訂」。)
- 有些產品需要支援鍵盤和滑鼠,有些則主要著重於透過觸控和按鈕互動。
- Fuchsia 平台應提供輸入行為的產品專屬自訂項目掛鉤 (例如,根據系統情境解讀不同的按鈕事件)。
- Fuchsia 應允許產品視需要將輸入事件對應至不同類型,例如將觸控事件重新解讀為滑鼠事件,以便與不支援觸控手勢的軟體相容。
- 擴充性:Fuchsia 可新增對新輸入模式的支援。
- 雖然輸入需求差異極大的產品可能需要變更平台,但應該可以新增對新輸入方法的支援,而不必大幅重新編寫現有的輸入堆疊。
激勵範例
這些用途並非詳盡無遺,但可讓您深入瞭解這類架構應支援的行為。
- 正確解讀觸控螢幕手勢,即使螢幕上顯示多個架構的 UI 也是如此。
- 當畫面上有多個文字方塊 (由不同架構支援) 時,請套用適當的版面配置資訊,將鍵盤輸入內容傳送至這些方塊。
- 允許按鈕組合 (例如同時按住調高音量和調低音量按鈕) 觸發恢復原廠設定,而非執行這些按鈕的正常功能。
- 在裝置進入休眠狀態或闔上時,禁止在筆電觸控螢幕上輸入內容。
- 解讀筆電觸控板手勢 (雙指撥動縮放、雙指捲動)。
背景與術語
- 人機介面裝置 (HID):可讓使用者輸入及輸出內容的裝置,例如鍵盤、滑鼠、觸控螢幕或消費者控制項 (按鈕)。這通常是指使用 USB-HID 規格的裝置。
- 輸入事件:單一使用者輸入事件,例如按鍵、滑鼠移動動作或觸控事件。處理事件時,系統可能會根據當下情境,在事件中加入註解。
- 指標事件:對應螢幕上位置的使用者輸入事件,例如觸控或滑鼠事件。指標事件是輸入事件的子集。
- 事件串流:一組相關的輸入事件,通常會在時間上緊密相連。
- 輸入處理常式:執行單一階段輸入處理的軟體。輸入處理常式會將輸入事件做為輸入內容,並發出輸入事件。這項服務可能會修改事件或與系統的其他部分通訊。
- 輸入管道演算法:這項演算法會將一系列輸入處理常式串連在一起,以處理 Fuchsia 輸入內容。這項政策可做為 Fuchsia 的輸入層。
- 輸入管道實作:輸入管道演算法的實作。實際上,這是 fuchsia.git 中的元件,負責將驅動驅動程式庫層級的使用者輸入事件,轉送至系統的其餘部分。
- Scenic:Fuchsia 圖形引擎。Scenic 也負責路由指標事件。
- 全域場景圖:由 Scenic 算繪的圖形內容樹狀結構。
- 檢視 - 場景圖中的子空間。檢視區塊通常對應螢幕上的區域,但這個區域不一定是矩形。
- ViewRef:與特定檢視畫面相關聯的事件配對。這項屬性用於在多個 Fuchsia 元件中識別檢視區塊。
架構總覽
這項設計提供 Fuchsia 上使用者輸入事件整體流程的概覽,但未涵蓋每種輸入類型的所有特定詳細資料。下方各節連結的垂直領域專屬設計,會說明許多相關細節。

系統會根據多項相互關聯的規則傳送事件,包括但不限於:
- 該事件類型的產品政策 (例如所有音量事件都會傳送至設定)
- 事件在畫面上的位置 (例如觸控或滑鼠)
- 目前焦點所在的檢視畫面 (例如文字輸入)
輸入管道是 Fuchsia 元件,負責管理這些規則和互動,並將使用者輸入事件連同處理這些事件所需的資訊,一併傳送至適當的系統服務。這個類別會實作輸入管道演算法 (一系列的鏈結輸入處理常式,每個處理常式都會執行裝置輸入處理中的離散步驟)。這個元件是 Fuchsia 輸入內容的政策層。輸入管道會透過輸入驅動程式直接從驅動程式庫程式層擷取事件,以及來自測試的合成事件和軟體產生的事件,例如虛擬鍵盤的事件。
事件在輸入管道中移動時,會從全域低階事件 (沒有語意,但包含私密資料) 逐步轉換為具有本機意義的範圍內處理資料,可供使用者軟體解讀 (手勢、字元等)。驅動程式層級的輸入事件大致可分為兩類:
- 與螢幕上特定位置對應的指標事件。
- 按鈕和切換事件。
日後可能會擴大支援範圍。USB-HID 使用量表範圍廣泛,包含多種用途,包括飛行模擬器、運動器材和虛擬實境裝置的頁面。
驅動程式層級的輸入事件可能會轉換為:
- 觸控手勢。
- 滑鼠事件 (包括捲動)。
- 文字輸入事件。
- 語意無障礙動作。
- 按鈕事件 (例如音量變更、開啟/關閉攝影機)。
通常每個事件的傳送方式如下:
Driver -> Input Pipeline -> UI System Component -> UI Framework-> UI View
- 輸入管道元件包含多個稱為「輸入處理常式」的內部階段。輸入管道會做為輸入內容的政策層,且可能因產品類型而異。(請參閱下方的「輸入管道自訂」一節)。
- UI 系統元件包括 Scenic、無障礙管理員和 IME 管理員,但隨著我們在平台中新增功能,這些元件可能會隨時間擴充。這些元件屬於 Fuchsia 平台,並位於 fuchsia.git 中。這些元件與產品無關。
- UI 系統元件負責決定哪些一或多個檢視區塊應接收事件,並將該資訊傳遞至 UI 架構執行元件以進行調度。UI 系統元件會使用 Scenic 的資訊 (通常是焦點鏈結) 判斷應由哪個檢視區塊接收事件。
- UI 系統元件也可能會消耗事件。
- 目前的使用者介面架構包括 Flutter、Chromium 和 Carnelian。我們預計在日後支援其他 UI 架構/執行階段。這些 API 可用於各種產品類型,但不屬於 Fuchsia 平台。
- UI 檢視區塊是擁有對應畫面區域 (稱為檢視區塊) 的圖像元件。(詳情請參閱下方的「檢視畫面和事件路徑」一節)。
- 媒體按鈕事件不一定會遵循這個模式。媒體按鈕的最終目的地可能是設定服務,而非 UI 檢視畫面。
在某些情況下,活動可能需要經過額外階段,才會最終傳送。 舉例來說,觸控事件可能會透過 Scenic 傳送至虛擬鍵盤元件,產生合成按鍵按下事件,然後透過輸入管道傳送。
輸入管道會將指標事件傳送至 Scenic,後者負責將事件傳送至正確的執行階段例項。這可讓 Scenic 全面瞭解畫面上物件的位置,並避免動畫期間發生競爭狀況。(請參閱下方的「路由圖形事件」一節)。
設計
輸入事件來源
輸入事件通常會透過輸入驅動程式進入系統,或是透過充當輸入裝置控制器的 Fuchsia 元件進入系統 (例如藍牙 HID 裝置的 bt-host 元件)。在許多情況下,這些事件會以人機介面裝置 (HID) 事件的形式啟動,但也有例外。驅動程式和控制器會將每個事件發出為 fuchsia.ui.input/InputReport。一般而言,輸入管道會取用並轉換輸入報表。不過,在復原模式中,這些事件會直接傳送至使用 Carnelian 實作的終端元件,不會經過任何中介處理。
測試用的輸入事件產生方式不同。(詳情請見下文的測試)。
輸入管道
輸入管道元件是 Fuchsia 系統元件。這個類別會實作輸入管道演算法。輸入管道元件的作用類似於輸入堆疊中的政策層。這個類別負責判斷特定裝置支援哪些事件類型、如何傳送輸入事件,以及管理輸入裝置。
輸入管道演算法包含:
- 繫結階段:將原始 InputReport (不含系統狀態) 串流轉換為 InputEvents 串流 (可能含有系統狀態),以便透過管道傳遞。
- 一系列 InputHandlers,可能會修改和/或取用這些 InputEvent,也可能將其分派給其他元件。
- (選用) 處理未處理 InputEvent 的備用階段。
繫結階段通常會使用裝置狀態資訊擴增 InputReport。例如:
- 包含滑鼠相對移動的 InputReport 會變成具有螢幕相對座標的 InputEvent。
- 按鍵 InputReport 串流會變成「按鍵按下」和「按鍵放開」InputEvent 串流。(驅動程式通常只會回報特定時間點按下哪些鍵,而不是分開回報按下和放開事件)。「按鍵放開」可能可從後續 InputReport 中沒有按鍵推斷出來。
理論上,Fuchsia 產品可以設定產品使用的輸入管道。不過,輸入管道不會在工作階段領域內執行。輸入管道是比工作階段更具權限的元件,且使用許多我們目前不希望向工作階段元件公開的功能。
輸入管道實作項目會提供給產品擁有者,做為 Fuchsia 平台的一部分。截至本 RFC 發布時,這些實作項目是以 Rust 編寫,而輸入處理常式是實作共用 InputHandler Rust 特徵的類別,但為了實現最佳化和擴充性,這項做法日後可能會變更。
目前平台提供兩種輸入管道實作方式:一種是專為主要依賴觸控螢幕互動的裝置最佳化,另一種則適用於配備滑鼠和鍵盤的產品。這項有限的自訂程度日後可能會擴大。(請參閱下文的「輸入管道自訂」)。
輸入處理常式
輸入處理常式 輸入處理常式是主要機制,可讓產品擁有者自訂與產品狀態相關的輸入處理作業。我們有時也會將此稱為輸入事件的產品政策。輸入處理常式可能
- 新增背景資訊來擴增事件,例如有效鍵盤配置,或滑鼠點選時按住的按鍵。
- 根據周圍的事件串流變更事件 (例如輸入平滑化、觸控板手勢)。
- 在處理常式中處理事件,或將事件傳送至 UI 系統元件公開的服務,該服務隨後會負責將事件分派至適當的 UI 檢視區塊組合。目標檢視畫面取決於 Scenic 中目前的檢視畫面焦點。(詳情請見下方的「焦點」一節)。
- 傳送 OutputReports 來控制輸入裝置狀態 (例如設定大寫鎖定 LED)。
在短期內,我們會定義 Rust 特徵 InputHandler,每個輸入處理常式都必須實作這個特徵。從長遠來看,這可能會由 FIDL 介面取代。每個處理常式都必須能夠消耗輸入事件,並輸出 (可能為空白) 輸入事件向量。
#[async_trait]
pub trait InputHandler: Send {
/// Returns a vector of InputEvents after handling `input_event`.
///
/// # Parameters
/// `input_event`: The InputEvent to be handled.
async fn handle_input_event(
&mut self,
input_event: input_device::InputEvent,
) -> Vec<input_device::InputEvent>;
}
未來以 Fuchsia 為基礎的產品可能需要的輸入處理常式範例 (部分相當奇特):
- 無障礙輸入處理常式:啟用相關無障礙功能 (例如切換導覽或使用鍵盤快速鍵的螢幕閱讀器) 時,會將事件傳送至無障礙管理工具。
- 快速鍵處理常式:判斷鍵盤事件是否與有效鍵盤快速鍵相符 (可能會呼叫其他元件)。
- 地區設定處理常式:套用目前檢視畫面有效地區設定的相關資訊。
- 指標事件分派處理常式:將觸控/滑鼠/觸控筆事件傳送至 Scenic,以便分派至檢視區塊。
- 媒體按鈕處理常式:將媒體按鈕轉送至設定服務 (或其他位置)。
- 鍵盤配置處理常式:使用目前有效的鍵盤配置註解鍵盤事件。
- TouchPad Gesture Handler:觸控板手勢,並轉送對應的滑鼠事件。
- 輸入平滑處理常式:透過平均事件來減少抖動。
- 焦點處理常式:使用目前焦點所在檢視區塊的 ViewRef 註解鍵盤事件。
- 睡眠模式處理常式:裝置處於休眠狀態時,會抑制輸入內容。
- Multitouch Waffle Iron Magic Button Handler:將觸控手勢事件解讀為媒體按鈕。
在許多情況下,輸入處理常式會將事件分派至 Fuchsia 系統服務,例如 Scenic、Accessibility Manager、IME Manager 等。在這種情況下,系統會將事件標示為「已處理」,並在管道的其餘部分傳播。(詳情請見下方的「事件串流一致性」一節)。
自訂輸入管道
指定要納入的處理常式和顯示順序,即可例項化輸入管道。因此新增處理常式、重新排序處理常式或例項化修改後的管道時,負擔非常輕。Rust 範例:
async fn input_handlers(
...
...
) -> Vec<Box<dyn InputHandler>> {
let mut handlers: Vec<Box<dyn InputHandler>> = vec![];
// Shortcut needs to go before IME.
add_shortcut_handler(&mut handlers).await;
add_ime(&mut handlers).await;
add_touch_handler(..., &mut handlers).await;
add_mouse_handler(..., &mut handlers).await;
handlers
}
2021 年,這個平台提供兩種輸入管道實作方式,每種方式都是在 fuchsia.git 中實作的元件,可運用未在 Fuchsia SDK 中發布的專屬 API。這些實作方式共用許多輸入處理常式 (執行相同的程式碼),主要差異在於支援的輸入模式。其中一種實作方式是針對主要依賴觸控螢幕互動的裝置進行最佳化,另一種則是以滑鼠和鍵盤為主的產品。產品專屬程式碼僅限於設定程式碼,用於決定要例項化的處理常式。
在短期內,可透過公開能力 (可能以 FIDL API 的形式,透過工作階段架構中介設定) 授予工作階段有限的可設定性,讓工作階段決定要啟用哪些輸入模式。這個 API 可讓您依產品設定,並在工作階段啟動時生效 (即設定產品使用者體驗時)。在正常產品運作期間,我們無意支援「即時」重新設定管道。
隨著 Fuchsia 支援的產品類別增加,輸入處理常式和不同產品設定的組合可能會擴大,因此可能需要公開一項能力,讓工作階段從各種管道設定中挑選,或直接設定應存在哪些輸入管道階段,以及這些階段的順序。部分輸入處理常式可能屬於特定產品,因此必須位於 fuchsia.git 以外的位置。
每個產品都應能使用專為特定需求量身打造的輸入管道,其中包含該產品支援的輸入行為所需的輸入處理常式。具體做法的決定超出本 RFC 的範圍。理想情況下,這類設定解決方案應利用平台提供的結構化設定機制,而非發明輸入專屬的機制,並盡可能公開滿足產品需求所需的最低設定介面。
瀏覽畫面和事件轉送
Fuchsia UI 可能會同時在畫面上顯示多個執行階段的圖像。UI 會整理成 全域場景圖,由 Scenic 擁有,其中包含構成 UI 的圖形內容,以及呈現這些內容所需的資訊。執行階段可將使用者可見的內容新增至名為「檢視區塊」的 Scenic 資源,藉此將內容提供給場景,而檢視區塊會安裝在場景圖中。通常檢視區塊會對應到螢幕上的某個區域,但這些區域不一定是矩形,而且並非所有檢視區塊都會在特定時間顯示。由於每個檢視區塊都是 Scenic 本機資源,不適合在其他元件中參照,因此我們會將稱為 ViewRef 的核心物件與每個檢視區塊建立關聯。
檢視畫面會依階層結構排列,子項檢視畫面只能影響父項檢視畫面範圍內的螢幕空間,也就是嚴格的容器模型。當檢視區塊是圖表中另一個檢視區塊的父項時,父項檢視區塊會保留對子項的特定控制權,特別是與內容放置和事件路徑相關的控制權。
查看樹狀結構
下圖說明場景圖根層級的結構。

- 與無障礙管理工具相關聯的檢視區塊,可讓無障礙管理工具攔截無障礙服務所需的輸入事件、變更焦點,以及在必要時「置於」其餘 UI 的頂端。
- 「sysUI」(系統 UI) 檢視畫面是所有其他檢視畫面的父項。這個檢視區塊通常用於實作「系統手勢」(例如在螢幕邊緣滑動來切換應用程式) 和系統鍵盤快速鍵。也用於 UI 的許多非輸入方面。
轉送圖形事件
如果使用者事件對應到特定螢幕位置 (例如觸控、滑鼠、觸控筆),輸入事件會先透過 Scenic 傳送,再分派至與每個檢視區塊相關聯的執行階段例項。這種做法的優點包括
- 場景圖形隔離:Scenic 是唯一能完整瞭解畫面上各個檢視區塊位置的元件。我們不允許其他元件在特定時間點查詢螢幕上的內容 (也稱為「命中測試」)。
- 全域一致性:Scenic 是特定檢視畫面在特定時間位於螢幕上位置的真實來源,因此讓 Scenic 傳送事件可避免問題,例如檢視畫面在輸入事件發生和傳送之間變更大小、位置或消失。如果產品在使用者與裝置互動時可能會頻繁變更,這點就特別重要。請注意,Scenic 也擁有焦點鏈,用於確保非指標事件的調度作業一致。
- 平行調度 (手勢消歧):如果檢視區塊重疊,可能會有數個檢視區塊對特定事件串流感興趣。舉例來說,產品可能想實作「系統手勢」,例如滑動手勢可關閉應用程式,但應用程式本身可能會以不同方式解讀該手勢。Scenic 負責判斷哪些檢視區塊應接收特定事件,並透過手勢消歧程序在這些檢視區塊之間進行仲裁。在這個模式中,觸控事件串流會平行分派至多個檢視區塊,然後在「手勢競技場」中解析,判斷最終要由哪個檢視區塊使用事件串流。
聚焦
為判斷目前執行的軟體應接收哪個輸入事件,我們需要檢視區塊焦點的概念。這大約是目前「有效」且可接收事件的檢視畫面。不過,實際上多個檢視區塊可能對每個事件都有興趣。
檢視區塊焦點是透過「焦點鏈」決定 (與檢視區塊樹狀結構中焦點所在的檢視區塊及其祖先對應的 ViewRef 向量)。焦點鏈由 Scenic 擁有 (因為 Scenic 管理檢視區塊),但其他元件可能會要求變更目前的焦點,例如回應無障礙動作或鍵盤快速鍵。輸入管道負責監控焦點鏈的變化,並將資訊提供給輸入處理常式,後者可能會將事件轉送至正確的用戶端元件/檢視區塊。焦點鏈的終端元素對應於目前聚焦的檢視區塊。
有些處理常式會對單一焦點檢視區塊感興趣,有些則會對整個焦點鏈感興趣。例如:
- 未觸發鍵盤快速鍵的鍵盤事件通常會傳送至目前聚焦的檢視畫面。
- 啟用螢幕閱讀器時,無障礙管理工具會使用焦點檢視畫面,判斷螢幕閱讀器目前「作用中」的項目。
- 鍵盤快速鍵管理工具會關注整個焦點鏈,其中任何一項都可能已註冊鍵盤快速鍵和相關聯的優先順序。
焦點事件會以特殊類型的 InputEvent 形式,在輸入管道中移動,並與其他輸入事件嚴格排序。
事件串流一致性
事件串流是一組相關的 InputEvent,通常會在時間上緊密相連。例如:
- 鍵盤:「a」KEY DOWN ->「a」KEY UP
- 滑鼠:HOVER -> HOVER -> BUTTON_DOWN -> BUTTON_UP
- 觸控:手指按下 -> 移動 -> 移動 -> 移動 -> 手指放開
系統必須確保管道每個階段和每個檢視區塊的事件串流一致性。也就是說,如果輸入處理常式將事件遞送至系統服務,藉此消耗事件,則應將適當的「已處理」事件傳送至後續的輸入處理常式,以便通知任何用戶端。
處理事件串流時,如果焦點發生變化,也會發生這種情況。從用戶端角度來看,每個「按下按鍵」事件都必須與對應的「放開按鍵」事件相符,如果焦點變更或輸入裝置中斷連線,則必須與「取消」事件相符。滑鼠點選和觸控事件串流也是如此。輸入管道負責將事件標示為「已處理」,並透過輸入管道傳播事件,確保串流一致性。串流取消時,系統服務會負責通知檢視區塊。
效能
可接受的延遲時間
使用者輸入內容有時效性,延遲時間 (即事件發生到 UI 回應的時間) 應盡可能縮短,但使用者對延遲的容忍度會因輸入類型而異。在某些情況下,延遲時間低至 10 毫秒時,使用者可能會覺得效能降低 (是否能完成工作),滿意度也會下降。超過 100 毫秒時,使用者體驗就會開始明顯變差,超過 300 毫秒時,使用者體驗可能就無法接受。直接操作 (例如使用觸控筆在螢幕上繪圖) 對延遲特別敏感,可能需要預測事件,才能提供可接受的使用者體驗。(如要瞭解相關背景資訊,請參閱這篇延遲論文)。
由於本 RFC 中說明的輸入系統是在比執行階段和 UI 更低的層級運作,使用者會感受到系統輸入延遲,以及處理和算繪輸入事件回應所造成的任何延遲。因此,輸入系統應盡可能加快速度,將盡可能多的「延遲預算」留給應用程式和執行階段。
此外,時間一致也很重要。即使平均事件傳送時間很短,事件時間的高度變異性仍可能導致使用者體驗變差,因此請務必查看延遲時間分布情形和平均值。
提升成效
如要縮短輸入架構的延遲時間,最好的方法是盡量減少不必要的程序環境切換。核心的每次進入和退出 (通常需要執行排程器) 都會導致事件時間發生變化。
日後我們可能會在圖形和輸入堆疊中執行多個元件 (例如 scenic 和輸入管線),做為單一程序中的個別元件,進一步減少程序躍點。如果發現 Rust 導致輸入管道產生額外延遲,我們也可能會重新考慮是否要使用 Rust 做為實作語言。
導入觸控事件的手勢消歧義 (又稱平行調度) 功能時,等待感興趣的元件回應特定事件串流,可能會導致額外延遲。為了讓這個演算法發揮效用,用戶端必須配合並及時回應輸入事件。系統需要某種機制,才能指定及強制執行用戶端延遲期望 (服務等級協議)。我們會在日後的設計中詳細說明。
國際化和輸入背景資訊
每個檢視區塊都有自己的輸入背景資訊,包括有效的輸入法 (「有效鍵盤」)。輸入內容情境與 fuchsia.intl.Profile 中的資訊不同,後者包含使用者的偏好語言代碼,會影響 UI 呈現方式。不過,使用者的地區設定可能會影響可用的輸入法/鍵盤配置。如要進一步瞭解 Fuchsia 國際化,請參閱 Fuchsia 國際化說明文件。
系統應允許不同檢視區塊使用不同的有效輸入法。舉例來說,使用者可能以某種語言撰寫電子郵件,但以另一種語言進行即時通訊。產品可能會選擇強制執行單一系統範圍的語言代碼或有效輸入法,但架構必須支援每個檢視區塊的個別輸入內容。日後可能會決定如何儲存這些設定。
除了將事件傳送至正確的檢視區塊,輸入管道 (和相關聯的系統元件,例如 IME 管理工具) 也會在解讀輸入事件時,使用該檢視區塊的輸入內容。舉例來說,輸入管道會使用事件發生時輸入環境中啟用的鍵盤配置資訊,為實體鍵盤事件加上註解。與焦點變更一樣,主動鍵盤配置的變更應視為輸入事件,並與其他事件依序處理,以免狀態變更發生競爭條件。
無障礙設定
為了讓所有使用者都能輕鬆使用 Fuchsia 裝置,Fuchsia 無障礙架構提供多項無障礙功能,可改變使用者與裝置的互動方式。具體來說,這項做法可提供以下優勢:
- 放大 UI 的部分或全部內容。
- 這款螢幕閱讀器可讓失明或低視能使用者透過與目前 UI 相對應的「語意樹」,探索及互動,不必輸入視覺資訊。
啟用其中一項或兩項功能後,無障礙管理工具必須透過輸入管道攔截輸入事件,並將其解讀為目前啟用的無障礙功能指令。這些指令可使用多種輸入模式,具體取決於裝置類型。舉例來說,工作站的螢幕閱讀器主要會使用鍵盤快速鍵操作,而觸控螢幕裝置的螢幕閱讀器則可能使用一連串的輕觸和滑動手勢。視啟用的無障礙功能而定,無障礙管理工具可能會決定只消耗部分事件 (例如放大鏡會消耗部分手勢,但允許其他手勢傳遞至 UI),或消耗所有事件 (例如螢幕閱讀器會將事件轉換為語意動作)。
無障礙管理工具會維護與每個檢視區塊的連線,以便透過語意 API fuchsia.accessibility.semantics 檢查、說明及與該檢視區塊中的 UI 元素互動。舉例來說,啟用螢幕閱讀器後「輕觸兩下」通常會傳遞至檢視區塊,做為目前所選語意節點的語意「預設動作」。
安全性考量
輸入管道和相關聯的系統元件會使用許多 SDK 中未發布的特殊權限 API。平台會要求工作階段使用輸入管道處理輸入內容,藉此限制外部軟體可用的功能。
此外,也請務必考量點擊劫持等 UI 補償攻擊。如果輸入事件遭到誤導,系統可能會在未經使用者同意的情況下授予權限 (例如將點擊動作導向惡意網站上的按鈕)。雖然很難在平台層級完全避免這種情況,但輸入架構必須確保圖形事件只會傳送至正確的 UI 元件,且產品擁有者能輕鬆瞭解輸入事件在系統中的流程。
隱私權注意事項
輸入管道的變更應經過隱私權審查,因為存取使用者輸入內容可能會讓攻擊者建立鍵盤記錄器或其他惡意軟體。除了復原模式外,輸入管道應是唯一允許使用者直接從驅動程式庫輸入事件的元件,以防止發生這種情況。
測試
測試輸入管道
應使用與支援的輸入功能 (例如觸控輸入、鍵盤快速鍵) 相對應的密封整合測試,驗證平台輸入行為,與使用這些功能的產品程式碼無關。測試應在每個支援的執行階段使用最少的圖形元件,驗證相關功能。確保功能穩定性與特定產品無關,對於開發人員建構樹狀結構外的產品至關重要。
密封測試會帶來許多挑戰,這些挑戰不在本 RFC 的範圍內。
測試其他所有項目
端對端測試會大量使用合成輸入事件,以可重現的方式模擬使用者互動,雖然大多數 UI 架構都包含某種事件插入方式 (例如 Flutter Driver),但這不足以測試涉及多個執行階段的任何情況。這表示 Fuchsia 必須提供適當的 API,才能建立虛假輸入內容。這項作業是透過 SL4F 和 Fuchsia 輸入合成程式庫完成,可透過專屬的插入 API,將事件插入輸入管道。這個 API 只能在開發人員版本中使用,絕不能用於正式版,因為這個 API 允許注入任意輸入內容。
輸入產業
支援各種不同類型的輸入裝置,會大幅增加複雜度,超出本文所述的高階架構。這些詳細資料將在後續的 RFC 中說明。主要輸入垂直包括:
- 實體鍵盤 (藍牙和 USB)
- 虛擬或螢幕小鍵盤
- 滑鼠
- 觸控
- 觸控板
說明文件
這份 RFC 的內容應連同實作詳細資料,一併新增至 Fuchsia 公開說明文件。
考慮的替代方案
本節會介紹一小部分討論過的替代方案 (數量眾多)。
將根層級的 Presenter 演變為管道
在過去,Scenic 負責傳送所有使用者輸入事件,包括沒有圖形/位置元件的鍵盤事件。目前部分產品設定會使用這項功能,但鍵盤事件已移除。根層級的 Presenter 中現有的輸入內容處理程式碼可以擴充,以處理其他用途。不過,這段程式碼缺少測試涵蓋範圍,而且需要大幅重寫,才能提供一致性和可設定性等所需屬性,並移除輸入處理和 Graphics API 之間不必要的耦合。
產品專屬 Scenic
由於輸入內容 (尤其是指標式輸入內容) 與圖像密切相關,因此其中一個探索選項是透過 Fuchsia 圖像引擎 Scenic 傳送輸入處理作業。這項架構與現狀截然不同。在這個版本中,合成器會從 Scenic 中分解出來,並以「即時模式」運作,也就是說,只要視窗管理員進行變更,合成器就必須繪製。Scenic 會成為視窗管理員,這項元件應為產品專屬,因此每個產品類別都需要不同的實作方式。輸入內容會透過這個元件轉送。
雖然這在任何單一產品中都能正常運作,但需要將個別產品的任何輸入自訂項目烘焙到圖形引擎中。這可能表示每種新產品類型都需要專門的 Scenic 實作。這種做法未來或許能帶來顯著的改善,但目前看來負擔過重,不適合現有的應用實例。