RFC-0096 - 使用者輸入架構

RFC-0096:使用者輸入架構
狀態已接受
區域
  • HCI
說明

在具有圖形使用者介面和多個執行階段的系統上,在 Fuchsia 上提供使用者輸入事件 (鍵盤、滑鼠、觸控等) 的高階架構。

問題
Gerrit 變更
作者
審查人員
提交日期 (年-月-日)2021-04-15
審查日期 (年-月-日)2021-05-26

摘要

這份 RFC 說明瞭目標高階架構,可在具有圖形使用者介面和多個執行階段的系統上,在 Fuchsia 上提供使用者輸入事件 (鍵盤、滑鼠、觸控等)。使用者可透過各種方法/裝置向系統提供輸入內容,包括鍵盤、滑鼠、觸控和按鈕。這份 RFC 說明 Fuchsia 上的輸入事件如何從驅動程式庫層級原始資料,轉變為分派至使用者空間軟體 (例如 Flutter 應用程式) 的輸入事件。本文發布時,所述元件仍在開發中。

提振精神

為了支援 Fuchsia 的包容性理念,Fuchsia 輸入功能必須為使用不同 UI 架構 (例如 Flutter、Chromium) 的不同執行階段上建構的元件提供平台層級支援,並允許產品擁有者自訂輸入行為。在其他平台上,這些行為通常會整合至特定 UI 架構的實作項目中。Fuchsia 會帶來一些獨特的挑戰,需要將平台輸入處理作業與特定 UI 架構的特定內容分開。

在 Fuchsia 程式碼中,目前有許多輸入路徑 (root presenterinput pipeline),但有關偏好路徑和遷移計畫的公開指南有限。這份 RFC 概述了 Fuchsia 上用於使用者輸入路徑的目標架構,並提供有關如何擴充輸入處理功能以供日後用途的指南。

需求條件

  • 安全性:Fuchsia 輸入堆疊可讓您輕鬆建構安全的產品。
    • 輸入事件可能包含密碼和付款資料等機密資料,以及使用者活動時間的相關資訊。所有使用者輸入事件都應視為可識別個人身分的資訊,且只能由受信任的系統元件傳送至使用者端軟體。
    • 如果使用者輸入內容的路徑不正確,也可能遭到濫用,例如惡意 UI 導致使用者按下不想按的按鈕 (「點按盜用」)。
    • 盡可能提供 API 介面,讓開發人員輕鬆瞭解並稽核系統中的使用者輸入事件流程,鼓勵他們建構安全的產品。
  • 正確性:輸入事件會按照使用者預期的方式傳送。
    • Fuchsia 輸入系統負責解析內容中的輸入事件,並將事件傳送至目前在系統上執行的正確目標元件。不過,視事件和產品類型而定,「正確」的定義可能會有所不同。
    • 即使 UI 正在動畫化或變更大小,輸入事件的傳送也應保持一致。
    • 事件有時可能會同時調度至多個元件 (例如鍵盤快速鍵)。
  • 效能:使用者輸入速度足夠快。
    • 雖然確切的延遲要求會因輸入裝置和產品類型而異,但輸入內容的傳送速度對延遲特別敏感,因此應盡量加快速度,讓使用者不會感覺到延遲。
    • 輸入架構應避免引入不必要的延遲。特別是,您應小心處理程序內容切換,以免發生不必要的封鎖呼叫。
  • 可自訂性:系統應支援不同使用者輸入行為,以便在 Fuchsia 平台上建構不同的產品。* 具體來說,產品 不過,本 RFC 中提出的初始實作方式只滿足自訂功能的部分最終需求。(請參閱「輸入管道自訂」)。
    • 有些產品需要支援鍵盤和滑鼠,其他產品則主要著重於透過觸控和按鈕進行互動。
    • Fuchsia 平台應提供鉤子,以便針對特定產品自訂輸入行為 (例如,根據系統情境對按鈕事件進行不同的解讀)。
    • Fuchsia 應允許產品視需要將輸入事件對應至不同類型,例如將觸控事件重新解讀為滑鼠事件,以便與不支援觸控手勢的軟體相容。
  • 擴充性:Fuchsia 可新增對新輸入模式的支援。
    • 雖然產品的輸入需求可能會因平台而異,但您應該可以新增支援新輸入方法,而無須大幅重寫現有的輸入堆疊。

激勵示例

這些用途並非全面性,但可讓您瞭解這個架構應支援的行為類型。

  • 在螢幕上顯示多個架構的 UI 時,正確解讀觸控螢幕手勢。
  • 在螢幕上顯示多個 (由不同架構支援的) 文字方塊時,將適當的版面配置資訊套用至鍵盤輸入。
  • 除了這些按鈕的一般功能外,允許按鈕組合 (例如同時按下調高音量和調低音量按鈕) 觸發恢復原廠設定。
  • 在裝置休眠或關閉時,抑制筆電觸控螢幕的輸入。
  • 解讀筆電觸控板手勢 (雙指撥動縮放、雙指捲動)。

背景與術語

  • 人機介面裝置 (HID):可讓使用者輸入及輸出的裝置,例如鍵盤、滑鼠、觸控螢幕或消費者控制項 (按鈕)。通常是指使用 USB-HID 規格的裝置。
  • 輸入事件:單一使用者輸入事件,例如按鍵、滑鼠移動動作或觸控事件。事件在處理過程中,可能會根據目前的背景資訊加上額外註解。
  • 指標事件:與螢幕上位置相對應的使用者輸入事件,例如觸控或滑鼠事件。指標事件是輸入事件的子集。
  • 事件串流:一組通常在相近時間發生的相關輸入事件。
  • 輸入處理程序:執行單一階段輸入處理作業的軟體。輸入處理常式會將輸入事件做為輸入,並發出輸入事件。可能會修改事件或與系統的其他部分通訊。
  • 輸入管道演算法:這項演算法會將一系列輸入處理常式連結在一起,以便處理 Fuchsia 輸入內容。這會做為 Fuchsia 輸入政策層。
  • 輸入管道實作 - 輸入管道演算法的實作。實際上,這是 fuchsia.git 中的元件,負責將驅動程式庫層級的使用者輸入事件轉送至系統的其他部分。
  • Scenic - Fuchsia 圖形引擎。Scenic 也負責將指標事件轉送至目的地。
  • 全域場景圖表 – 由 Scenic 算繪的圖形內容樹狀結構。
  • View - 場景圖表中的子集區域。檢視畫面通常會對應至螢幕上的區域,但這個區域不一定是矩形。
  • ViewRef - 與特定檢視畫面相關聯的事件組合。這項屬性可用於在多個 Fuchsia 元件中識別檢視畫面。

架構總覽

這項設計可概略說明 Fuchsia 上使用者輸入事件的整體流程,但不涵蓋每種輸入類型的所有特定詳細資料。下方各節的相關連結將帶您前往特定產業的設計頁面,其中會說明許多相關細節。

由下而上:dev/class/input-report -> 輸入管道 -> {scenic 或 a11y 管理員或 IME 管理員或媒體按鈕事件監聽器} -> {Chromium 或 flutter 或 carnelian} -> {View 1 或 view 2 或 view3 或 view 4} 側邊:產品工作階段元件 -> {輸入管道或根場景元件} 根場景元件 -> scenic 中的 Scenic:輸入管道中的焦點管理器、場景圖表 (含視覺樹狀圖表示法):bind -> 指標事件處理常式 -> a11y 捷徑處理常式 -> 媒體按鈕處理常式 -> 各種其他處理常式 -> IME 處理常式 -> 備用

事件會根據多項相關聯的規則調度,包括但不限於:

  • 該事件類型的產品政策 (例如,所有音量事件都會調度至設定)
  • 事件在螢幕上的位置 (例如觸控或滑鼠)
  • 目前聚焦的檢視畫面 (例如文字輸入)

輸入管道是 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 負責將事件調度至正確的執行階段執行個體。這可讓 Scenic 在全球範圍內一致地瞭解畫面上物件的所在位置,並避免在動畫期間發生競爭狀況。(請參閱下方的「路由圖形化事件」)。

設計

輸入事件來源

輸入事件通常會透過輸入驅動程式或 Fuchsia 元件進入系統,該元件會充當輸入裝置的控制器 (例如藍牙人機介面裝置的 bt-host 元件)。在多數情況下,這些事件會以人機介面裝置 (HID) 事件開始,但也有例外情況。驅動程式和控制器會將每個事件以 fuchsia.ui.input/InputReport 的形式發出。一般來說,輸入報表會由輸入管道使用及轉換。不過,在復原模式中,這些資料會直接傳送至使用 Carnelian 實作的終端元件,而不需要任何中介處理。

測試用的輸入事件產生方式不同。(請參閱下方的測試)。

輸入管道

輸入管道元件是 Fuchsia 系統元件。實作輸入管道演算法。輸入管道元件的作用就像輸入堆疊中的政策層。它負責判斷特定裝置支援哪些事件類型,以及如何調度輸入事件,並管理輸入裝置。

輸入管道演算法包含以下項目:

  • 這個繫結階段會將原始 InputReports 串流 (不含系統狀態) 轉換為 InputEvents
  • 一系列 InputHandlers
  • (選用) 處理未處理的 InputEvents 的備用階段。

繫結階段通常會在 InputReports 中加入裝置狀態相關資訊。例如:

  • 包含相對滑鼠動作的 InputReport 會變成具有螢幕相對座標的 InputEvent。
  • 按鍵輸入報告的串流會變成「按下鍵」和「放開鍵」的輸入事件串流。(驅動程式通常只會在特定時間點回報哪些按鍵已按下,而不會分開回報按下和放開事件)。您可以從後續 InputReport 中缺少的鍵推斷「key up」。

理論上,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 建構的產品可能需要的輸入處理常式範例 (有些相當奇特):

  • 無障礙輸入處理常式:啟用相關無障礙功能 (例如使用鍵盤快速鍵的切換導覽或螢幕閱讀器) 時,會將事件傳送至 a11y 管理員。
  • Shortcut Handler:判斷鍵盤事件是否與有效的鍵盤快速鍵相符 (可能會呼叫其他元件)。
  • Locale Handler:為目前檢視畫面套用有效語言代碼的資訊。
  • 指標事件調度處理常式:將觸控/滑鼠/觸控筆事件傳送至 Scenic,以便調度至檢視畫面。
  • 媒體按鈕處理常式:將媒體按鈕轉送至設定服務 (或其他位置)。
  • 鍵盤配置處理常式:使用目前有效的鍵盤配置標記鍵盤事件。
  • TouchPad Gesture Handler:觸控板手勢和前向等效的滑鼠事件。
  • 輸入平滑處理常式:透過平均事件來減少抖動。
  • Focus Handler:使用目前聚焦檢視畫面的 ViewRef 標註鍵盤事件。
  • 睡眠模式處理常式:在裝置處於休眠狀態時,抑制輸入。
  • 多點觸控鬆餅鐵魔法按鈕處理常式:將觸控手勢事件解讀為媒體按鈕。

在許多情況下,輸入處理常式會將事件調度至 Fuchsia 系統服務,例如 Scenic、無障礙服務管理工具、IME 管理工具等等。在這種情況下,系統會將事件標示為「已處理」,並透過管道中的其餘部分傳播。(請參閱下方的「事件串流一致性」)。

輸入管道自訂

您可以指定要納入的處理程序,以及處理程序的顯示順序,藉此將輸入管道例項化。因此,新增處理常式、重新排序處理常式或建構已修改管道的做法非常輕巧。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 的圖形內容,以及呈現 UI 所需的資訊。執行階段可以將使用者可見的內容新增至名為「View」的 Scenic 資源,該資源會安裝在場景圖表中。通常,檢視區塊會對應至螢幕上的區域,但這些區域不一定是矩形,且並非所有檢視區塊都會在特定時間顯示。由於每個檢視區塊都是 Scenic 本機資源,不適合在其他元件中參照,因此我們會將稱為 ViewRef 的核心物件與每個檢視區塊建立關聯。

檢視畫面以階層方式排序,子項檢視畫面只能影響父項檢視畫面範圍內的螢幕空間,也就是嚴格的容器模型。」如果某個檢視區塊是圖表中另一個檢視區塊的父項,則父項會保留對子項的特定控制權,特別是與內容放置和事件導向相關的控制權。

檢視樹狀結構

下圖說明場景圖表根目錄的結構。

root -> accessibility view -> sysUI -> {some view, some other view, yet
another view}

  • 與無障礙管理工具相關聯的檢視畫面可讓無障礙管理工具攔截無障礙服務所需的輸入事件,並變更焦點,以及在必要時在其他 UI 上方繪製。
  • 「sysUI」(系統 UI) 檢視畫面是所有其他檢視畫面的父項。這個檢視畫面通常用於實作「系統手勢」(例如在螢幕邊緣滑動以切換應用程式) 和系統鍵盤快速鍵。也用於 UI 的許多非輸入面向。

轉送圖形事件

對於與特定螢幕位置相對應的使用者事件 (例如觸控、滑鼠、觸控筆),輸入事件會先透過 Scenic 轉送,然後再分派至與每個檢視畫面相關聯的執行階段執行個體。這種做法的優點包括:

  • 場景圖表隔離:Scenic 是唯一能完全瞭解畫面上哪個檢視畫面所在位置的元件。我們不允許其他元件在特定時間點查詢畫面上的內容 (也稱為「命中測試」)。
  • 全域一致性:Scenic 是特定檢視畫面在特定時間出現在畫面上的可靠來源,因此如果使用 Scenic 調度事件,就能避免在輸入事件發生與傳送事件之間,檢視畫面變更大小、位置或消失的問題。對於使用者與裝置互動時可能經常變更的產品而言,這一點尤其重要。請注意,Scenic 也擁有焦點鏈結,用於讓非指標事件的調度保持一致。
  • 平行調度 (手勢辨識):當檢視畫面重疊時,可能會有多個檢視畫面對特定事件串流感興趣。舉例來說,產品可能會導入「系統手勢」,例如滑動關閉應用程式,但應用程式本身可能會以不同方式解讀該手勢。Scenic 負責判斷哪些檢視區塊應接收特定事件,並透過稱為手勢辨識的程序進行調解。在這個模式中,系統會並行將觸控事件串流調度至多個檢視畫面,然後在「手勢競技場」中進行解析,以決定最終要使用哪個檢視畫面的事件串流。

焦距

為了判斷哪個目前執行中的軟體應接收特定輸入事件,我們需要使用檢視區塊焦點的概念。這大致是目前處於「活動」狀態,且可接收事件的檢視畫面。但實際上,每個事件可能都會吸引多個檢視畫面。

系統會透過焦點鏈結 (ViewRef 向量,對應焦點檢視畫面及其在檢視區塊樹狀結構中的祖系) 判斷檢視畫面焦點。焦點鏈結由 Scenic 擁有 (因為 Scenic 會管理檢視畫面),但其他元件可能會要求變更目前焦點,例如回應無障礙動作或鍵盤快速鍵。輸入管道負責監控焦點鏈結中的變更,並將資訊提供給輸入處理常式,後者可能會將事件轉送至正確的用戶端元件/檢視畫面。焦點鏈結的終端元素會對應至目前聚焦的檢視畫面。

有些處理程序會對單一聚焦檢視畫面感興趣,而其他處理程序則會對整個聚焦鏈結感興趣。例如:

  • 未觸發鍵盤快速鍵的鍵盤事件通常會傳送至目前聚焦的檢視畫面。
  • 無障礙功能管理員會使用目前聚焦的檢視畫面,判斷螢幕閱讀器目前的「活動」狀態。
  • 鍵盤快速鍵管理員會關注整個焦點鏈結,其中任何一個鏈結都可能已註冊鍵盤快速鍵和相關優先順序。

焦點事件會以特殊類型的 InputEvent 形式通過輸入管道,並與其他輸入事件嚴格排序。

事件串流一致性

事件串流是一組相關的 InputEvents,通常會在相近的時間發生。例如:

  • 鍵盤:按下「a」鍵 -> 放開「a」鍵
  • 滑鼠:懸停 -> 懸停 -> 按下按鈕 -> 放開按鈕
  • 觸控:手指按下 -> 移動 -> 移動 -> 移動 -> 手指放開

系統必須確保管道每個階段和每個檢視畫面中的事件串流一致。也就是說,如果輸入處理常規將事件導向系統服務,則應將適當的「已處理」事件傳送至後續輸入處理常規,以便通知任何用戶端。

在處理事件串流時,焦點發生變化也會發生這種情況。從用戶端的角度來看,每個「按下鍵」都必須與相應的「按下鍵」相符,如果焦點變更或輸入裝置已中斷連線,則必須與「取消」事件相符。滑鼠點擊和觸控事件串流也是如此。輸入管道負責將事件標示為「已處理」,並透過輸入管道傳播,確保串流一致性。系統服務負責在串流取消時通知觀看者。

成效

可接受的延遲時間

使用者輸入內容有時效性,延遲時間 (即從事件發生到 UI 回應的時間) 應盡可能縮短,但使用者對延遲時間的容忍度會因輸入類型而異。在某些情況下,使用者可能會遇到效能降低 (可完成工作) 和滿意度,延遲時間低至 10 毫秒。超過 100 毫秒後,使用者體驗開始明顯下降,超過 300 毫秒後可能會變得難以接受。直接操作 (例如在螢幕上使用觸控筆繪圖) 對延遲特別敏感,可能需要預測事件才能提供可接受的使用者體驗。(請參閱這份延遲論文瞭解背景資訊)。

由於本 RFC 中所述的輸入系統執行層級低於執行階段,且 UI 是建構在執行階段之上,因此使用者會遇到系統輸入延遲,以及處理和顯示輸入事件回應所需的時間所造成的延遲。因此,輸入系統應盡可能加快速度,讓應用程式和執行階段有更多「延遲預算」。

此外,時間安排也相當重要。即使平均事件提交時間很短,事件時間的變化幅度過大也可能會導致使用者體驗變差,因此請務必查看延遲時間分布情形,並計算平均值。

提升效能

如要縮短輸入架構中的延遲時間,最好的做法就是盡量減少不必要的程序內容切換。每個進入和離開核心的動作通常都需要執行排程器,因此會導致事件的時間出現變化。

日後,我們可能會嘗試在單一程序中,以獨立元件的形式執行圖形和輸入堆疊中的多個元件 (例如景觀和輸入管道),進一步減少程序跳轉。如果我們發現這會導致額外的延遲,也可能會重新考慮將 Rust 做為輸入管道的實作語言。

在觸控事件中引入手勢辨識 (也稱為平行調度) 可能會導致額外延遲,因為系統必須等待感興趣的元件回應特定事件串流。為了讓這個演算法發揮效能,用戶端必須配合,並迅速回應輸入事件。系統需要某些機制,用於指定及強制執行用戶端延遲預期值 (SLA)。我們會在日後的設計中詳述這項功能。

國際化和輸入背景資訊

每個檢視區塊都有自己的輸入背景資訊,其中包含有效的輸入方法 (「有效鍵盤」)。輸入內容與 fuchsia.intl.Profile 中的資訊不同,後者包含使用者偏好的語言代碼,並會影響 UI 呈現方式。不過,使用者的語言設定可能會影響可用的輸入法/鍵盤配置。如要進一步瞭解 Fuchsia 國際化,請參閱 Fuchsia 國際化說明文件

系統應允許不同檢視畫面採用不同的有效輸入方法。舉例來說,使用者可能會以一種語言撰寫電子郵件,同時以另一種語言進行即時通訊。產品可以選擇強制執行單一系統層級語言代碼或有效輸入方法,但架構必須支援每個檢視畫面的獨特輸入內容。具體的儲存方式可能會在日後決定。

除了將事件轉送至正確的檢視畫面,輸入管道 (以及 IME Manager 等相關系統元件) 也會在解讀輸入事件時,使用該檢視畫面的輸入內容。舉例來說,輸入管道會在實體鍵盤事件中加上註解,說明在事件發生時,輸入內容中啟用的鍵盤配置資訊。如同焦點變更,您應考量輸入事件,並依序處理其他事件,以免發生狀態變更的競爭狀態。

無障礙設定

為了讓所有使用者都能使用 Fuchsia 裝置,Fuchsia 無障礙架構提供了多項無障礙功能,可變更使用者與裝置互動的方式。具體來說,這項功能可讓您:

  • 放大鏡,可放大局部或整個 UI。
  • 螢幕閱讀器,可讓失明或低視能使用者透過與目前 UI 相對應的「語意樹狀結構」探索及互動,不必透過視覺輸入。

啟用這兩項功能中的一項或兩者時,無障礙管理員需要透過輸入管道攔截輸入事件,並將這些事件解讀為目前處於活動狀態的無障礙功能指令。視裝置類型而定,這些指令可使用多種輸入模式。舉例來說,工作站螢幕閱讀器主要會使用鍵盤快速鍵操作,而觸控螢幕裝置的螢幕閱讀器則可能會使用一系列的輕觸和滑動動作。視啟用的無障礙功能而定,無障礙管理員可能會決定只使用部分事件 (例如放大鏡,它會使用部分手勢,但允許其他手勢傳遞至 UI) 或所有事件 (例如螢幕閱讀器,它會將事件轉譯為語意動作)。

無障礙管理員會維護與每個檢視畫面的連線,讓管理員能夠透過語意 API fuchsia.accessibility.semantics 檢查、描述及與該檢視畫面中的 UI 元素互動。舉例來說,啟用螢幕閱讀器的「雙擊」動作通常會傳遞至檢視畫面,做為目前所選語意節點的語意「預設動作」。

安全性考量

輸入管道和相關系統元件會使用許多未在 SDK 中發布的特權 API。要求工作階段使用輸入管道處理輸入內容,平台就能限制外部軟體可用的功能。

另外,也請考量 UI 調解攻擊,例如點擊劫持。錯誤導向的輸入事件可用於在未經使用者同意的情況下授予權限 (例如將點擊導向至惡意網站上的按鈕)。雖然在平台層級很難完全避免這種情況,但輸入架構必須確保圖形事件只會傳送至正確的 UI 元件,讓產品擁有者能輕鬆瞭解系統中的輸入事件流程。

隱私權注意事項

輸入管線的變更應經過隱私權審查,因為攻擊者可能會利用使用者輸入內容,建立按鍵記錄程或其他惡意軟體。除了復原模式之外,輸入管道應是唯一允許使用者直接從驅動程式庫輸入事件的元件,以避免發生這種情況。

測試

測試輸入管道

平台輸入行為應透過密封整合測試驗證,對應至支援的輸入功能 (例如觸控輸入、鍵盤快捷鍵),而與使用這些功能的產品程式碼無關。測試應使用每個支援的執行階段中的最少圖形元件,驗證相關功能。為讓開發人員能夠建構樹狀結構外產品,請務必確保功能穩定性不受特定產品影響。

密封測試會帶來許多挑戰,但這超出本 RFC 的範圍。

測試其他項目

端對端測試大量仰賴合成輸入事件,以便以可重現的方式模擬使用者互動,以便進行測試。雖然大多數 UI 架構都包含用於插入事件的方式 (例如 Flutter Driver),但這不足以測試涉及多個執行階段的任何情況。這表示 Fuchsia 必須提供適當的 API,以便建立假輸入內容。這項功能是透過 SL4F 和 Fuchsia 輸入合成程式庫完成,該程式庫會透過專屬的注入 API 將事件插入輸入管道。這個 API 應僅供開發人員版本使用,絕不能用於正式版版本,因為它允許注入任意輸入內容。

輸入產業

除了這裡所述的高階架構之外,支援每種輸入裝置類型都會增加相當程度的複雜度。後續 RFC 會說明這些詳細資訊。主要輸入垂直產業包括:

  • 實體鍵盤 (藍牙和 USB 鍵盤皆可)
  • 虛擬或螢幕小鍵盤
  • 滑鼠
  • 觸控
  • 觸控板

說明文件

本 RFC 的內容應與實作詳細資料一併加入 Fuchsia 公開文件。

考慮的替代方案

本節將介紹部分 (廣泛的) 替代方案。

將根呈現工具轉換為管道

過去,Scenic 負責調度所有使用者輸入事件,包括沒有圖形/位置元件的鍵盤事件。目前部分產品設定會使用這項功能,但已移除鍵盤事件。root presenter 中現有的輸入處理程式碼可擴充,以處理其他用途。不過,這個程式碼缺乏測試涵蓋率,因此需要大幅重寫,才能提供一致性和可設定性等所需的屬性,並移除輸入處理和圖形 API 之間不必要的耦合。

產品專屬 Scenic

由於輸入內容 (尤其是以指標為基礎的輸入內容) 與圖形密切相關,因此探索的其中一個選項會透過 Scenic (Fuchsia 圖形引擎) 將輸入內容處理作業重新導向。這個架構將與目前狀態截然不同。在這個版本中,合成器會從 Scenic 中分離出來,並以「即時模式」運作,也就是說,只要視窗管理員進行變更,就必須繪製。Scenic 會成為視窗管理員,而視窗管理員是一種產品專屬元件,需要為每個產品類別實作不同的實作方式。輸入內容會透過這個元件轉送。

雖然這在任何單一產品中都能正常運作,但仍需要將個別產品的任何輸入自訂項目整合至圖像引擎。這可能表示每個新產品類型都需要專門的 Scenic 實作。這種做法在未來可能會是實用的最佳化方式,但目前的用途實例認為這項做法太重。