鍵盤輸入 (開始使用 Win32 和 C++)

鍵盤用於數種不同的輸入類型,包括:

  • 字元輸入。 使用者輸入檔或編輯方塊的文字。
  • 鍵盤快速鍵。 叫用應用程式函式的按鍵筆劃;例如,CTRL + O 以開啟檔案。
  • 系統命令。 叫用系統函式的按鍵筆劃;例如,ALT + TAB 切換視窗。

考慮鍵盤輸入時,請務必記住按鍵筆劃與字元不同。 例如,按下 A 鍵可能會導致下列任何字元。

  • a
  • A
  • 如果鍵盤支援合併讀音符號) ,則為 á (

此外,如果按住 ALT 鍵,按下 A 鍵會產生 ALT+A,系統完全不會將它視為字元,而是做為系統命令。

機碼

當您按下按鍵時,硬體會產生 掃描碼。 掃描碼會從一個鍵盤到下一個鍵盤而有所不同,而且有個別的按鍵和按鍵關閉事件掃描碼。 您幾乎不會關心掃描代碼。 鍵盤驅動程式會將掃描碼轉譯為 虛擬按鍵碼。 虛擬金鑰代碼與裝置無關。 在任何鍵盤上按下 A 鍵會產生相同的虛擬按鍵程式碼。

一般而言,虛擬金鑰代碼不會對應至 ASCII 代碼或任何其他字元編碼標準。 如果您思考過,這很明顯,因為相同的索引鍵可以產生不同的字元 (a、A、á) 和某些索引鍵,例如函式索引鍵,不會對應到任何字元。

也就是說,下列虛擬金鑰代碼確實對應至 ASCII 對等專案:

  • 0 到 9 個索引鍵 = ASCII '0' – '9' (0x30 – 0x39)
  • 透過 Z 鍵 = ASCII 'A' – 'Z' (0x41 – 0x5A)

在某些方面,基於討論的原因,此對應很可惜,因為您不應該將虛擬金鑰代碼視為字元。

標頭檔 WinUser.h 會定義大部分虛擬金鑰代碼的常數。 例如,向左鍵的虛擬鍵程式碼 VK_LEFT (0x25) 。 如需虛擬金鑰代碼的完整清單,請參閱 虛擬金鑰碼。 未針對符合 ASCII 值的虛擬索引鍵代碼定義常數。 例如,A 金鑰的虛擬金鑰程式碼0x41,但沒有名為 VK_A 的常數。 請改用數值。

Key-Down和Key-Up訊息

當您按下按鍵時,具有鍵盤焦點的視窗會收到下列其中一則訊息。

WM_SYSKEYDOWN訊息指出系統索引鍵,這是叫用系統命令的按鍵筆劃。 系統金鑰有兩種類型:

  • ALT + 任何索引鍵
  • F10

F10 鍵會啟動視窗的功能表列。 各種 ALT 鍵組合會叫用系統命令。 例如,ALT + TAB 切換至新的視窗。 此外,如果視窗有功能表,可以使用 ALT 鍵來啟動功能表項目。 某些 ALT 按鍵組合不會執行任何動作。

所有其他按鍵筆劃都會被視為非系統索引鍵,並產生 WM_KEYDOWN 訊息。 這包括 F10 以外的函式索引鍵。

當您釋放金鑰時,系統會傳送對應的按鍵訊息:

如果您按住鍵長到足以啟動鍵盤的重複功能,系統會傳送多個按鍵向下鍵訊息,後面接著單一按鍵訊息。

在到目前為止所討論的四個鍵盤訊息中, wParam 參數包含按鍵的虛擬按鍵程式碼。 lParam參數包含一些封裝成 32 位的其他資訊。 您通常不需要 lParam中的資訊。 其中一個可能很有用的旗標是位 30,即「先前的索引鍵狀態」旗標,此旗標會針對重複的按鍵關閉訊息設定為 1。

如名稱所示,系統按鍵筆劃主要是供作業系統使用。 如果您攔截 WM_SYSKEYDOWN 訊息,請之後呼叫 DefWindowProc 。 否則,您將封鎖作業系統處理命令。

字元訊息

第一次在課程模組 1中看到的TranslateMessage函式會將按鍵筆劃轉換成字元。 此函式會檢查向下鍵訊息,並將其轉譯成字元。 針對產生的每個字元, TranslateMessage 函式會將 WM_CHARWM_SYSCHAR 訊息放在視窗的訊息佇列上。 訊息的 wParam 參數包含 UTF-16 字元。

如您所猜測, WM_CHAR 訊息是從 WM_KEYDOWN 訊息產生,而 WM_SYSCHAR 訊息則從 WM_SYSKEYDOWN 訊息產生。 例如,假設使用者按下 SHIFT 鍵,後面接著 A 鍵。 假設標準鍵盤配置,您會取得下列訊息序列:

WM_KEYDOWN:SHIFT
WM_KEYDOWN:A
WM_CHAR: 'A'

另一方面,ALT + P 的組合會產生:

WM_SYSKEYDOWN:VK_MENU
WM_SYSKEYDOWN:0x50
WM_SYSCHAR: 'p'
WM_SYSKEYUP:0x50
WM_KEYUP:VK_MENU

(ALT 金鑰的虛擬金鑰程式碼命名為VK_MENU,原因為)

WM_SYSCHAR訊息表示系統字元。 如同 WM_SYSKEYDOWN,您通常會將此訊息直接傳遞至 DefWindowProc。 否則,您可能會干擾標準系統命令。 特別是,請勿 將WM_SYSCHAR 視為使用者輸入的文字。

WM_CHAR訊息是您通常視為字元輸入的內容。 字元的資料類型是 wchar_t,代表 UTF-16 Unicode 字元。 字元輸入可以包含 ASCII 範圍以外的字元,特別是使用在美國外部常用的鍵盤配置。 您可以安裝區域鍵盤,然後使用螢幕鍵盤功能來嘗試不同的鍵盤配置。

使用者也可以安裝輸入法編輯器 (輸入法) ,以使用標準鍵盤輸入複雜的腳本,例如日文字元。 例如,使用日文輸入法輸入片假名字元カ (ka) ,您可能會收到下列訊息:

WM_KEYDOWN:VK_PROCESSKEY (輸入法進程金鑰)
WM_KEYUP:0x4B
WM_KEYDOWN:VK_PROCESSKEY
WM_KEYUP:0x41
WM_KEYDOWN:VK_PROCESSKEY
WM_CHAR: カ
WM_KEYUP:VK_RETURN

某些 CTRL 按鍵組合會轉譯成 ASCII 控制字元。 例如,CTRL+A 會轉譯為 ASCII ctrl-A (SOH) 字元 (ASCII 值0x01) 。 針對文字輸入,您通常應該篩選掉控制字元。 此外,請避免使用 WM_CHAR 來實作鍵盤快速鍵。 請改用 WM_KEYDOWN 訊息;或甚至更好,請使用快速鍵資料表。 快速鍵資料表會在下一個主題 快速鍵資料表中說明。

下列程式碼會顯示偵錯工具中的主要鍵盤訊息。 嘗試使用不同的按鍵組合播放,並查看產生的訊息。

注意

請務必包含 wchar.h,否則不會定義swprintf_s。

LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    wchar_t msg[32];
    switch (uMsg)
    {
    case WM_SYSKEYDOWN:
        swprintf_s(msg, L"WM_SYSKEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSCHAR:
        swprintf_s(msg, L"WM_SYSCHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    case WM_SYSKEYUP:
        swprintf_s(msg, L"WM_SYSKEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYDOWN:
        swprintf_s(msg, L"WM_KEYDOWN: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_KEYUP:
        swprintf_s(msg, L"WM_KEYUP: 0x%x\n", wParam);
        OutputDebugString(msg);
        break;

    case WM_CHAR:
        swprintf_s(msg, L"WM_CHAR: %c\n", (wchar_t)wParam);
        OutputDebugString(msg);
        break;

    /* Handle other messages (not shown) */

    }
    return DefWindowProc(m_hwnd, uMsg, wParam, lParam);
}

其他鍵盤訊息

大部分的應用程式都可以安全地忽略一些其他鍵盤訊息。

  • WM_DEADCHAR訊息會傳送給合併索引鍵,例如讀音符號。 例如,在西班牙文語言鍵盤上,輸入輔色 (') 後面接著 E 會產生字元 é。 系統會針對輔色字元傳送 WM_DEADCHAR
  • WM_UNICHAR訊息已過時。 它可讓 ANSI 程式接收 Unicode 字元輸入。
  • 當 IME 將按鍵序列轉譯成字元時,就會傳送 WM_IME_CHAR 字元。 除了一般 WM_CHAR 訊息之外,還會傳送它。

鍵盤狀態

鍵盤訊息為事件驅動。 也就是說,您會在發生有趣的情況時收到訊息,例如按下按鍵,而訊息會告訴您剛發生的狀況。 但您也可以呼叫 GetKeyState 函式,隨時測試金鑰的狀態。

例如,請考慮如何偵測滑鼠左鍵 + ALT 鍵的組合。 您可以藉由接聽按鍵筆觸訊息並儲存旗標來追蹤 ALT 鍵的狀態,但 GetKeyState 可節省您的問題。 當您收到 WM_LBUTTONDOWN 訊息時,只要呼叫 GetKeyState ,如下所示:

if (GetKeyState(VK_MENU) & 0x8000)
{
    // ALT key is down.
}

GetKeyState訊息會接受虛擬金鑰程式碼作為輸入,並傳回一組位旗標, (實際上只有兩個旗標) 。 值0x8000包含位旗標,可測試按鍵目前是否按下。

大部分的鍵盤都有兩個 ALT 鍵,由左到右。 上述範例會測試是否按下其中一個。 您也可以使用 GetKeyState 來區分 ALT、SHIFT 或 CTRL 鍵的左和右實例。 例如,下列程式碼會測試是否按下正確的 ALT 鍵。

if (GetKeyState(VK_RMENU) & 0x8000)
{
    // Right ALT key is down.
}

GetKeyState函式很有趣,因為它會報告虛擬鍵盤狀態。 此虛擬狀態是以訊息佇列的內容為基礎,並在您從佇列中移除訊息時更新。 當您的程式處理視窗訊息時, GetKeyState 會在每個訊息排入佇列時提供鍵盤的快照集。 例如,如果佇列上的最後一則訊息 WM_LBUTTONDOWNGetKeyState 會在使用者按一下滑鼠按鍵時報告鍵盤狀態。

因為 GetKeyState 是以訊息佇列為基礎,所以也會忽略傳送至另一個程式的鍵盤輸入。 如果使用者切換至另一個程式, GetKeyState會忽略傳送至該程式的任何按鍵。 如果您真的想要知道鍵盤的立即實體狀態,則有一個函式: GetAsyncKeyState。 不過,對於大部分的 UI 程式碼而言,正確的函式是 GetKeyState

下一個

快速鍵資料表