首頁 > 軟體

在基於 Web 的 VNC 應用程式中支援多種鍵盤佈局

2020-06-16 17:26:56

基於 Web 的 KVM 管理工具(比如 KimchiOvirt)可幫助使用者輕鬆建立和管理虛擬機器 (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 是一個硬體模擬器。當您連線到在 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 包含一個標識所按下的實體鍵的字串。該值不受當前鍵盤佈局或修飾鍵狀態的影響,所以特定的鍵將始終返回相同的值。


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

有效的實現

擴充套件的 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。

結束語

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

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

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

本文永久更新連結地址http://www.linuxidc.com/Linux/2016-12/137810.htm


IT145.com E-mail:sddin#qq.com