歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 在基於 Web 的 VNC 應用程序中支持多種鍵盤布局

在基於 Web 的 VNC 應用程序中支持多種鍵盤布局

日期:2017/2/28 13:46:24   编辑:Linux教程

基於 Web 的 KVM 管理工具(比如 Kimchi 和 Ovirt)可幫助用戶輕松創建和管理虛擬機 (VM),甚至是從移動設備創建和管理虛擬機。這些工具依靠遠程桌面共享技術,比如 虛擬網絡計算 (VNC),而使用 VNC 的技術需要一個基於 Web 的 VNC 客戶端,比如 noVNC。

VNC 最初的目的是使物理 PC 能夠從遠程進行訪問。因為虛擬化不是 VNC 關注的問題,所以在將 VNC 用於 VM 時,需要經過特殊處理才能解釋和操作擊鍵。Web 技術也帶來了額外的挑戰:Web 應用程序必須解決浏覽器支持上的差異,否則僅能用於某些選定的浏覽器。Web 應用程序只能通過浏覽器 API 訪問 PC 硬件,而桌面應用程序能夠更直接地進行訪問。

本文旨在幫助 JavaScript 開發人員理解和解決相關挑戰,讓基於 Web 的 VNC 客戶端(或其他任何面臨同樣問題的基於 Web 的硬件模擬器)能夠准確地響應從多種鍵盤布局生成的擊鍵信息。我首先將解釋桌面操作系統如何處理鍵盤信號。然後,您將學習 RFB(VNC 使用的協議)如何將擊鍵信息從 VNC 客戶端發送到 VNC 服務器,還將了解此過程在虛擬化場景中涉及到哪些問題,以及 QEMU 社區如何為桌面 VNC 客戶端解決這些問題。然後,我將介紹如何使用一個相對較新的浏覽器 API 為基於 Web 的 VNC 客戶端實現 QEMU 解決方案。

操作系統如何處理擊鍵

鍵盤是一種硬件設備,對於每個按下或釋放的鍵,它都會發送一個信號。這些信號稱為掃描碼,由一個或多個字節組成,用於唯一地標識按下或釋放實體鍵的操作。

IBM 在 IBM XT 中設立了第一個掃描碼標准。大部分制造商都遵循 XT 標准來確保設備與 IBM 硬件兼容。但是,掃描碼不是一種容易供應用程序使用的好的鍵盤表示,因為不同的鍵盤類型可能使用不同的掃描碼。舉例而言,USB 鍵盤遵循與 XT 標准不同的掃描碼標准。

鍵碼

為了使應用程序能夠處理任何類型的鍵盤,操作系統將掃描碼轉換為與不依賴於鍵盤的鍵碼。例如,在 PS2 鍵盤中按 Q,會得到與在 USB 鍵盤中按 Q 相同的鍵碼。得益於從掃描碼到鍵碼的轉換(鍵盤驅動程序 的第一個任務),應用程序不需要處理所有已知的鍵盤類型。

掃描碼與鍵碼之間的轉換是可逆的。任何鍵碼都可以轉換回生成它的准確的硬件掃描碼。例如,在標准美國 102 鍵鍵盤上按下標為 Q 的鍵,不會解釋為 Q 鍵被按下,而是解釋為位於第三行第二列的鍵被按下

鍵符 (keysyms)

對應用程序而言,使用鍵碼仍不是很理想,因為根據不同的鍵盤布局,同一個實體鍵可能表示不同的符號。例如,在法國鍵盤中,位於第三行第二列的鍵是 A,不是 Q。大部分應用程序(例如文本編輯器)都希望獲知用戶按下了 Q,而不是按下的鍵在布局中的位置。

鍵符 (keysym) 是在考慮鍵盤布局圖 (keymap) 後從一次或多次按鍵/釋放鍵的操作生成的符號。從鍵碼到鍵符的轉換是操作系統執行的最後一次轉換,該操作會向應用程序提供准確的鍵符。

圖 1 演示了一個兼容 XT 的鍵盤將一個從美國或法國鍵盤布局將按鍵信號發送到基於 Linux 的系統的轉換順序。

圖 1. 按鍵信號如何從鍵盤發送到應用程序

不同於掃描碼到鍵碼的轉換,從鍵碼到鍵符的轉換是不可逆的,原因有兩個。首先,這種轉換需要知道用於生成鍵符的鍵盤布局圖,而且不是所有場景都可以獲得此信息。其次,無法知道使用了哪種鍵組合來創建鍵符。例如,A 的鍵符可通過按 Shift + a 或在鎖定大寫時按 a 來生成。這種模糊性是 QEMU 在使用 RFB 時遇到的問題的來源。

RFB 協議、QEMU/KVM 虛擬化和 VNC

RFB(遠程幀緩沖區)是 VNC 用於遠程訪問 GUI 的協議。在該協議及其擴展協議中定義的多種 RFB 客戶端到服務器消息類型中,本文關注的是 KeyEvent,也就是在按下或釋放一個鍵時從 RFB 客戶端發送到服務器的消息。圖 2 顯示了該消息格式。

圖 2. RFB KeyEvent 客戶端消息的格式

  • message-type 指定消息類型。KeyEvent 消息為類型 4。
  • down-flag 指定鍵的狀態。如果按下該鍵,該值為 1;如果釋放,該值為 0。
  • padding 是一個填充了 0 的 2 字節字段。
  • keysym 是按下或釋放的鍵的鍵符。

當收到 KeyEvent 消息時,依據 down-flag 的值,RFB 服務器將按下或釋放鍵時的鍵符復制到遠程桌面中。在此消息中使用鍵符,是早期 QEMU 版本在用於虛擬化的 VNC 客戶端/服務器上遇到設計問題的根源。

首次嘗試

QEMU 項目首次嘗試引入 keymap 選項,以告訴 QEMU 生成鍵符的 VNC 客戶端中使用了哪個鍵盤布局圖。有了此信息,QEMU 就可以嘗試從鍵符轉換回鍵碼;如果未指定鍵盤布局圖,它會使用默認的美國布局。此方法不足以解決非美國鍵盤的 QEMU 問題。QEMU 需要能夠支持 VNC 客戶端使用的任何鍵盤布局(針對 100 多種語言的布局),而且從上一節中我們已經知道,不同的組合鍵可能生成相同的鍵符。

QEMU 是一個硬件模擬器。當您連接到在 QEMU 虛擬機中運行的 VNC 服務器時,服務器不會單純地接收和顯示擊鍵;它會模擬它們,就像有人在虛擬機中的一個真實鍵盤上按鍵一樣。結果,在收到 RFB KeyEvent 消息時,QEMU 會嘗試著將已發送的鍵轉換為生成該鍵的 XT 掃描碼。但是,KeyEvent 消息發送的是鍵符。QEMU 曾經面臨著如何根據鍵符利用已按下或已釋放的鍵來獲取實際 XT 掃描碼的挑戰。

在 QEMU 最初嘗試解決此問題失敗後(參見 “首次嘗試” 邊欄),GTK-VNC 和 QEMU 社區合作創建了 RFB 協議的一個官方擴展,該擴展添加了一條新的 KeyEvent 消息,其中不僅包含鍵符,還包含在 VNC 客戶端中按下的鍵碼。圖 3 顯示了該消息格式。

圖 3. QEMU 擴展 KeyEvent RFB 消息的格式

  • message-type 指定消息類型。擴展的 QEMU KeyEvent 消息為類型 255。
  • submessage-type 有一個一字節的默認值 0。
  • down-flag 指定鍵的狀態。如果按下該鍵,該值為 1;如果釋放,該值為 0。
  • keysym 是已按下或釋放的鍵的鍵符。
  • keycode 是生成該鍵符的鍵碼。

借助額外的 keycode 信息,QEMU 可將鍵碼轉換回掃描碼並進行模擬。此能力還使 VNC 服務器不知道 VNC 客戶端使用了哪個鍵盤布局圖。只要客戶端的鍵盤布局圖與來賓操作系統(在虛擬機中運行的操作系統)中配置的鍵盤布局圖相同,鍵盤就會按預期工作。

Web 技術和擊鍵處理

在桌面應用程序和 Web 應用程序之間的鍵盤事件處理差異,為全面實現基於 Web 的 VNC 客戶端增加了一個復雜性層。該層是浏覽器。桌面應用程序可更直接地訪問底層硬件,而 Web 應用程序受到浏覽器支持的限制。

浏覽器中的擊鍵處理基本知識

現在出現的問題總數比 2000 年代初期更少,但浏覽器之間仍然缺乏標准化。而且談到鍵盤處理,差異可能很大。

浏覽器提向 Web 應用程序提供了 3 種鍵盤事件:

  • keydown:按下一個鍵。
  • keyup:釋放一個鍵:
  • keypressed:按下一個字符鍵。

keydownkeyup 事件與操作系統處理的鍵盤事件類似。keypressed 事件僅在生成鍵符時發生。Shift 或 Alt 等特殊鍵不會生成 keypressed 事件。Web 應用程序要可靠地獲得生成的字符,則必須依靠 keypressed 事件。

每個事件擁有至少以下 3 個屬性:

  • keyCode 屬性指按下的鍵,不含修飾鍵,比如 Shift 或 Alt。當按下 a 鍵時,甚至在生成的鍵符為 A 時,keyCode 也是相同的。許多網站和 Web 教程會誤導性地將此屬性稱為鍵的掃描碼。
  • charCode 屬性是鍵事件(如果有)生成的鍵符的 ASCII 碼。
  • which 屬性返回的值在大多數時候與 keyCode 相同,提供按下的鍵的 Unicode 值。

可以使用 Javascript 鍵事件測試腳本 頁面查看在按下某個鍵時鍵盤事件有何行為。例如,按下左 Shift 鍵會得到:

keydown keyCode=16 which=16 charCode=0 keyup keyCode=16 which=16 charCode=0

按下 a 鍵會得到:

keydown keyCode=65 (A) which=65 (A) charCode=0 keypress keyCode=0 which=97 (a) charCode=97 (a) keyup keyCode=65 (A) which=65 (A) charCode=0

按住 a 鍵不放會得到:

keydown keyCode=65 (A) which=65 (A) charCode=0 keypress keyCode=0 which=97 (a) charCode=97 (a) keydown keyCode=65 (A) which=65 (A) charCode=0 keypress keyCode=0 which=97 (a) charCode=97 (a) keydown keyCode=65 (A) which=65 (A) charCode=0 keypress keyCode=0 which=97 (a) charCode=97 (a) keyup keyCode=65 (A) which=65 (A) charCode=0

這種對鍵盤事件的浏覽器支持使實現 VNC Web 客戶端成為可能。一些 VNC 客戶端項目已開始試驗解決多鍵盤布局問題。但 noVNC 項目沒有實現 QEMU VNC 擴展來處理該問題,所以在 2015 年,我們決定嘗試一下。毫無疑問,我曾認為解決該問題僅需使用 keyCode(浏覽器提供的所謂的掃描碼)並將其放在 QEMU 擴展的 KeyEvent 消息中。哪裡可能出錯了?

keyCode,所謂的掃描碼

在 noVNC 中使用 keyCode 屬性實現 QEMU 擴展,沒有解決鍵盤布局問題。我了解到,盡管 keyCode 屬性擁有定位行為,但它依賴於布局,因此無法在 QEMU KeyEvent 消息中用作鍵碼。

下面的簡單試驗展示了不同布局中的 keyCode 屬性的行為。我們再次使用 Javascript 鍵事件測試腳本 頁面來展示鍵盤事件,以下是在美國布局鍵盤中按下 q 鍵時的輸出:

keydown keyCode=81 (Q) which=81 (Q) charCode=0 keypress keyCode=0 which=113 (q) charCode=113 (q) keyup keyCode=81 (Q) which=81 (Q) charCode=0

將布局更改為法國,以下是同一個鍵的輸出:

keydown keyCode=65 (A) which=65 (A) charCode=0 keypress keyCode=0 which=97 (a) charCode=97 (a) keyup keyCode=65 (A) which=65 (A) charCode=0

請注意,當布局發生更改時,keyCode 值從 81 變為了 65。在法國 AZERTY 布局鍵盤中,第三行第二個鍵是 a,keyCode 反映了這一布局變化。

在我嘗試在 noVNC 項目中實現 QEMU 擴展時,浏覽器的 JavaScript 中沒有描述物理位置的屬性 — a 鍵的不依賴於布局的鍵碼。所以,我必須暫時擱置這項工作。

KeyboardEvent.code 成為了救星

2016 年初,Chrome 浏覽器穩定版 48 中包含一個名為 code 的新 KeyboardEvent 屬性。(Firefox 之前已引入此屬性,Opera 隨後也提供了它。)Mozilla Developer Network 對此屬性進行了如下描述:

KeyboardEvent.code 包含一個標識所按下的實體鍵的字符串。該值不受當前鍵盤布局或修飾鍵狀態的影響,所以特定的鍵將始終返回相同的值。


借助這個新屬性,我可以繼續並完成我的實現。

有效的實現

浏覽器支持狀況

截至編寫本文時,Chrome、Firefox、Firefox for Android 和 Opera 都支持 KeyboardEvent.code 屬性。Microsoft Edge 路線圖 將此 API 列入 “考慮” 范圍。對於任何不支持 KeyboardEvent.code 的浏覽器,VNC Web 客戶端必須禁用 QEMU VNC 擴展,退而使用默認的 RFB KeyEvent 消息,或者找到另一種方法來使用可用的 KeyboardEvent 屬性獲取不依賴於布局的實體鍵。

擴展的 QEMU KeyEvent 消息已在多個桌面 VNC 客戶端中良好地建立和實現。既然 KeyboardEvent.code 屬性使恢復按下的實體鍵成為可能,那麼 VNC Web 客戶端就沒有理由不采用相同方式實現該擴展。我為 noVNC 項目實現的解決方案可供任何基於 Web 的 VNC 客戶端使用。

忽略 keypressed 事件

我在解決方案中選擇了忽略 keypressed 事件。這些事件僅在一個或多個 keypressed 事件生成一個可讀字符(一個鍵符)時觸發。檢測到來自支持 QEMU VNC 擴展的客戶端的連接時,QEMU VNC 服務器會(在大多數時候,我稍後將討論)忽略消息的 keysym 字段,僅依靠 keycode 字段在虛擬機中模擬 XT 掃描碼。

代碼實現

我設計的完整、有效的實現可在 GitHub 上獲得。

在這裡,我將重點介紹一些特別值得注意的細節。

如何將 KeyboardEvent.code 轉換為 xt_scancode

KeyboardEvent.code 提供了鍵的物理位置,但未使用可直接用在 RFB 消息中的格式。以下是該屬性的可能值的一個示例:

'Esc' key: xt_scancode 0x0001 keyboardevent.code = "Escape" Spacebar: xt_scancode 0x0039 keyboardevent.code = "Space" 'F1' key: xt_scancode 0x003B keyboardevent.code = "F1"

我的實現使用了這篇有關 KeyboardEvent.code 的 Mozilla Developer Network 文章 中提供的表,創建一個將 KeyboardEvent.code 值轉換為相應的 xt_scancode 的哈希表,例如:

XT_scancode["Escape"] = 0x0001; XT_scancode["Space"] = 0x0039; XT_scancode["F1"] = 0x003B;

創建 QEMU RFB KeyEvent 消息

buff 視為一個大小為 12 的字節數組:

buff[offset] = 255; // msg-type buff[offset + 1] = 0; // sub msg-type buff[offset + 2] = (down >> 8); buff[offset + 3] = down; buff[offset + 4] = (keysym >> 24); buff[offset + 5] = (keysym >> 16); buff[offset + 6] = (keysym >> 8); buff[offset + 7] = keysym; var RFBkeycode = getRFBkeycode(keycode) buff[offset + 8] = (RFBkeycode >> 24); buff[offset + 9] = (RFBkeycode >> 16); buff[offset + 10] = (RFBkeycode >> 8); buff[offset + 11] = RFBkeycode;

數據結構與 圖 3 類似,這絕非偶然。在本代碼中,keycode 是從 keyboardevent.code 值轉換得到的 xt_scancodekeysym 是一個 0 字段(大部分情況下如此)。

getRFBkeycode() 函數將 XT_scancode 轉換為 QEMU VNC 擴展定義的格式:

function getRFBkeycode(xt_scancode) { var upperByte = (keycode >> 8); var lowerByte = (keycode & 0x00ff); if (upperByte === 0xe0 && lowerByte < 0x7f) { lowerByte = lowerByte | 0x80; return lowerByte; } return xt_scancode }

NumLock 的獨特情況:鍵符發揮作用的時刻

我提到過鍵符基本上被忽略。在至少一種情況下,QEMU VNC 服務器考慮鍵符:當使用數字鍵盤 (Numpad) 中的鍵時。

在我的解決方案的第一個實現中(忽略 QEMU KeyEvent 消息的鍵符字段),出現了一種奇怪的行為:當按下任何多用途數字鍵盤鍵時,比如 0、1、2、3、4、6、7、8、9 或小數點(en_US 布局中的句點),即使虛擬機和客戶端上的 NumLock 狀態為 ON,QEMU VNC 服務器也會:

  • 將虛擬機的 NumLock 狀態更改為 OFF(如果它為 ON
  • 按鍵

例如,在客戶端和虛擬機上的 NumLock 狀態為 ON 時按數字鍵盤鍵 8,會將虛擬機中的 NumLock 狀態更改為 OFF,然後執行向上箭頭鍵的操作。在 NumLock 狀態為 OFF 時按數字鍵盤鍵 8 的行為才是符合預期的。

此問題可通過可靠方式利用客戶端和虛擬機的 NumLock 狀態來解決。但遠程 QEMU VNC 服務器不可能知道客戶端鍵盤的 NumLock 狀態。服務器可以看到何時按下/釋放 NumLock 鍵,但無從了解當前的 NumLock 狀態,因為 QEMU VNC KeyEvent 消息未傳遞該信息。

經過在桌面 VNC 客戶端上廣泛測試後,我認識到在這些環境中發送了鍵符。盡管鍵碼不會基於 NumLock 狀態而發生更改,但鍵符會受到影響。結論是,QEMU VNC 服務器使用鍵符字段來猜測客戶端的 NumLock 狀態,並采取相應行動來嘗試���步虛擬機狀態。在實現中,發送的鍵符為 0 時,服務器將此解釋為 “客戶端的 NumLock 狀態為 OFF”,強制將客戶端 NumLock 狀態更改為 OFF,然後發送按下的鍵碼。

因為如果不發送鍵符,會默認為 NumLock 狀態為 OFF,所以解決方案是僅在 NumLock 狀態為 ON 時發送鍵符。

發送數字鍵盤的鍵符

生成鍵符的鍵盤事件是 keypressed 事件,我的解決方案忽略了該事件。那麼如何將鍵符應用於 QEMU KeyEvent 消息?

幸運的是,確定鍵符不是一定需要 keypressed 事件。數字鍵盤在所有布局中都是標准的(否則,如果沒有鍵盤布局圖,QEMU VNC 服務器就無法猜測 NumLock 狀態)。所以,數字鍵盤鍵的鍵符值可預先確定。

這就留下了一個問題,如果不使用 keypress 事件,如何區分數字鍵 7 用作 Home 鍵的情況和用作數字 7 的情況。我的實現使用了 KeyboardEvent.keyCode 屬性(在 keydown 事件上設置)來進行區分,如下面的代碼片段所示。

下面的函數接收一個鍵盤事件 evt,並將 KeyboardEvent.code 值與屬於數字鍵盤的值相比較:

function isNumPadMultiKey(evt) { var numPadCodes = ["Numpad0", "Numpad1", "Numpad2", "Numpad3", "Numpad4", "Numpad5", "Numpad6", "Numpad7", "Numpad8", "Numpad9", "NumpadDecimal"]; return (numPadCodes.indexOf(evt.code) !== -1); }

我使用前面的函數來查看是否需要對某個指定的鍵盤事件進行任何特殊處理。

下面的函數接收一個鍵盤事件 evt,並將它的 keyboardevent.keyCode 屬性與一個名為 numLockOnKeyCodes 的預定義值集相比較:

function getNumPadKeySym(evt) { var numLockOnKeySyms = { "Numpad0": 0xffb0, "Numpad1": 0xffb1, "Numpad2": 0xffb2, "Numpad3": 0xffb3, "Numpad4": 0xffb4, "Numpad5": 0xffb5, "Numpad6": 0xffb6, "Numpad7": 0xffb7, "Numpad8": 0xffb8, "Numpad9": 0xffb9, "NumpadDecimal": 0xffac }; var numLockOnKeyCodes = [96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 108, 110]; if (numLockOnKeyCodes.indexOf(evt.keyCode) !== -1) { return numLockOnKeySyms[evt.code]; } return 0;

在 NumLock ON 狀態下,numLockOnKeyCodes 值對應於數字鍵盤鍵 0 到 9 和小數點。如果 evt.keyCode 是這些值之一,那麼該函數會返回 numLockOnKeySyms 提供的等效鍵符;否則,它會返回 0。

以下是在代碼內調用這些函數的方式:

result.code = evt.code; result.keysym = 0; if (isNumPadMultiKey(evt)) { result.keysym = getNumPadKeySym(evt); }

在此代碼中,result 是在處理過程中傳遞的對象。這樣,解決方案就可以確保正確處理 NumLock 鍵。

AltGR 和 Windows

我在 Windows 10 上運行的所有支持的浏覽器(Chrome、Firefox 和 Opera)中測試 noVNC 解決方案時出現了另一個異常:AltGR 修飾鍵在 Linux 虛擬機上未按預期工作。

通過調試代碼,我發現, AltGR 鍵通過兩條 KeyEvent 消息發送到 QEMU VNC 服務器,而不是一條消息。第一條消息是一個左 Ctrl 鍵;第二條消息是一個右 Alt 鍵 — 與您期望某人按下左 Ctrl 後立即按右 Alt 的效果相同。當客戶端在 Linux PC 中運行時,發送 AltGR 鍵作為右 Alt。

出現此行為 是有歷史原因的。長話短說:舊的美國鍵盤沒有 AltGR 鍵,Windows 最初使用左 Ctrl + 右 Alt 來模擬它。此解決方案適合沒有 AltGR 鍵的鍵盤,但在使用有 AltGR 的鍵盤時可能帶來誤導。

一個解決方案是記錄此行為,並強制用戶刪除此默認映射。另一個是我選擇的解決方案 — 用於處理 noVNC 中的行為。我的代碼包含對按左 Ctrl 後按右 Alt 的組合的特殊處理:

if (state.length > 0 && state[state.length-1].code == 'ControlLeft') { if (evt.code !== 'AltRight') { next({code: 'ControlLeft', type: 'keydown', keysym: 0}); } else { state.pop(); } } (...) if (evt.code !== 'ControlLeft') { next(evt); }

此代碼告訴 noVNC:在 keydown 事件中,如果 KeyboardEvent.code 等於 ControlLeft,則不要立即轉發該事件。等待第二個 keydown 事件,並驗證它的代碼是否等於 AltRight,這意味著浏覽器收到了一個左 Ctrl + 右 Alt 的組合,這可能意味著在 Windows 浏覽器中按下了 AltGR 鍵。在這種情況下,丟棄左 Ctrl,僅轉發右 Alt,這是 Linux 中的默認行為。這種處理使 AltGR 鍵能按預期工作,甚至在 Windows 浏覽器中也是如此。

此方法的缺點是,即使用戶合理地按下了左 Ctrl + 右 Alt 的組合,也不會轉發該組合。我將此視為可接受的缺點,因為左 Ctrl + 右 Alt 不是一種常用的組合鍵(左 Ctrl + 左 Alt 和右 Ctrl + 右 Alt 容易鍵入得多)。適用性影響極小,而且用戶不需要在 Windows 重新配置鍵盤布局圖。

棄用的屬性

我的實現的另一個已知缺陷,是一個用於處理 NumLock 問題的屬性:

if (numLockOnKeyCodes.indexOf(evt.keyCode) !== -1) {

KeyboardEvent.keyCode(連同 whichcharCode,可在 “Web 技術和擊鍵處理” 部分看到)自 2015 年以來已被 棄用。但是,當時在大部分浏覽器中沒有實現應在它們的位置使用的屬性 KeyboardEvent.key(而且在編寫本文時,所有 Safari 版本和 Chrome 移動版本仍不支持它)。所有這些棄用的屬性被廣泛用在 noVNC 和其他任何需要鍵盤控制的應用程序中。我不希望浏覽器很快丟棄這些屬性,但依靠一個棄用的屬性不是推薦做法。我強烈建議受影響應用程序的開發人員將 keyCodewhichcharCode 重構為新的 KeyboardEvent.key API。

結束語

桌面與 Web VNC 客戶端

盡管更方便使用,但基於 Web 的 VNC 客戶端比桌面客戶端更慢。Kimchi 的一個社區要求是,使用名為 Virt Viewer 的 Linux VNC 客戶端讓桌面 VNC 客戶端更容易連接到 Kimchi 管理的虛擬機。作為 Kimchi 項目的活躍貢獻者,我開發了一個 Kimchi 特性,讓用戶可以選擇使用 Virt Viewer 還是 noVNC 來連接到 Kimchi 虛擬機的 VNC 服務器。

調查 VNC Web 應用程序中的鍵盤布局問題,在 noVNC 項目中實現解決方案並處理未預見的問題,是一個雖艱苦但有益的過程。

Web 開發自早期的噩夢時代以來已有了很大改善。浏覽器兼容性的提高使得大部分 Web 應用程序都只需編碼一次,即可在所有主要浏覽器中按預期運行。但當應用程序需要更高級的 API 時,比如鍵盤處理或者甚至移動設備加速計,問題就出現了。在這些 API 中,浏覽器支持緩沖區,這直接影響了應使用相同代碼庫在多個設備上運行(借助響應式 Web 設計和 HTML5)的應用程序的開發。

在面臨鍵盤布局問題時,VNC Web 客戶端就會受到這類跨浏覽器差異的影響。未實現 QEMU VNC KeyEvent 擴展的項目無法擺脫一些問題,比如如何在不知道使用的鍵盤布局圖的情況下解釋非美國鍵盤中的給定鍵符。除非 KeyboardEvent.code 屬性可用於所有浏覽器,否則實現該擴展的項目(正如我為 noVNC 所做的一樣)需要支持兩種不同的鍵盤處理模式。

Copyright © Linux教程網 All Rights Reserved