2011-01-27 103 views
6

如果我需要爲用戶定製的鍵盤佈局,看起來像他/她的鍵盤,我該怎麼做?是否可以創建與使用的鍵盤相同的鍵盤佈局?

例如是這樣的:

enter image description here

法語,瑞典語,英語,加拿大等都會有不同的佈局,正確的。這是很多工作,或者只是使用某種內置.NET區域類的問題?

+4

看起來像是一個很好的附加組件,可供人寫作;) – Oded 2011-01-27 21:50:39

+0

只需使用Google圖片即可獲得國際鍵盤佈局的圖片。例如,嘗試使用[法語鍵盤佈局]的谷歌搜索(http://www.google.com/images?hl=zh-CN&q=french+keyboard+layout)。 – Timwi 2011-01-27 21:51:47

+0

是的,但我需要用預定義的樣式從頭開始繪製它。另外,如果我使用佈局,那麼我需要存儲所有的圖像,對不對?我需要在運行時動態執行此操作(啓動自定義對話框時)。 – 2011-01-27 21:53:47

回答

8

按鍵生成一個硬件事件,向Windows操作系統報告「掃描代碼」。然後,該掃描碼被轉換成基於與其他鍵盤狀態因素沿着掃描碼的「虛擬鍵碼」(大寫鎖定狀態,移位/Alt鍵/Ctrl鍵 keystate,以及任何未決的死鍵招)。轉換的VK值是由KeyDown事件等報告的內容。

從掃描代碼到VK代碼的轉換取決於當前輸入語言環境 - 簡單地說,輸入語言環境定義掃描代碼和虛擬鍵代碼之間的映射。有關鍵盤輸入的完整說明,請參閱the MSDN documentation

通過顛倒這個查找過程,可以確定與每個虛擬鍵碼相對應的掃描碼(當然,由於shift/ctrl/alt狀態等,相同的掃描碼將映射到多個VK碼)。 Win32 API通過使用MAPVK_VK_TO_VSC_EX選項提供MapVirtualKeyEx函數來執行此映射。您可以使用它來確定哪個掃描代碼生成特定的VK代碼。

不幸的是,這是儘可能以編程方式 - 無法確定鍵盤的物理佈局或每個掃描代碼的密鑰位置。但是,大多數物理鍵盤的佈線方式相同,因此(例如)左上角的鍵在大多數物理鍵盤設計上都具有相同的掃描代碼。根據基本的物理鍵盤佈局(101鍵,102鍵等),您可以使用此假定慣例來推斷與掃描代碼對應的物理位置。這並不能保證,但這是一個非常安全的猜測。

下面的代碼是我寫的一個更大的鍵盤處理庫的摘錄(我一直打算開源,但沒有時間)。該方法初始化一個數組(this._virtualKeyScanCodes),該數組是以VK代碼爲索引的給定輸入語言環境(存儲在this._inputLanguage中,聲明爲System.Windows.Forms.InputLanguage。可以使用該數組來確定與VK代碼對應的掃描代碼,例如通過檢查this._virtualKeyScanCodes[VK_NUMPAD0] - 如果掃描碼爲零,那麼在當前輸入區域設置中,鍵盤上的VK不可用;如果掃描碼不爲零,則爲您可以從中推斷出物理鍵的掃描碼。

不幸的是,當您進入死鍵(例如,生成重音字符的多個組合鍵)的領域時,事情稍微複雜一些。這對於現在來說太複雜了,但如果你想進一步探索,Michael S. Kaplan寫了一系列詳細的blog posts。祝你好運!

private void Initialize() 
{ 
    this._virtualKeyScanCodes = new uint[MaxVirtualKeys]; 

    // Scroll through the Scan Code (SC) values and get the Virtual Key (VK) 
    // values in it. Then, store the SC in each valid VK so it can act as both a 
    // flag that the VK is valid, and it can store the SC value. 
    for (uint scanCode = 0x01; scanCode <= 0xff; scanCode++) 
    { 
     uint virtualKeyCode = NativeMethods.MapVirtualKeyEx(
      scanCode, 
      NativeMethods.MAPVK_VSC_TO_VK, 
      this._inputLanguage.Handle); 
     if (virtualKeyCode != 0) 
     { 
      this._virtualKeyScanCodes[virtualKeyCode] = scanCode; 
     } 
    } 

    // Add the special keys that do not get added from the code above 
    for (KeysEx ke = KeysEx.VK_NUMPAD0; ke <= KeysEx.VK_NUMPAD9; ke++) 
    { 
     this._virtualKeyScanCodes[(uint)ke] = NativeMethods.MapVirtualKeyEx(
      (uint)ke, 
      NativeMethods.MAPVK_VK_TO_VSC, 
      this._inputLanguage.Handle); 
    } 

    this._virtualKeyScanCodes[(uint)KeysEx.VK_DECIMAL] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_DECIMAL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_DIVIDE] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_DIVIDE, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_CANCEL] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_CANCEL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 

    this._virtualKeyScanCodes[(uint)KeysEx.VK_LSHIFT] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_LSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RSHIFT] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_RSHIFT, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LCONTROL] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_LCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RCONTROL] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_RCONTROL, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LMENU] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_LMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RMENU] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_RMENU, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_LWIN] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_LWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_RWIN] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_RWIN, NativeMethods.MAPVK_VK_TO_VSC, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_PAUSE] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_UP] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_VOLUME_UP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_DOWN] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_VOLUME_DOWN, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_VOLUME_MUTE] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_VOLUME_MUTE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 

    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_NEXT_TRACK] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_MEDIA_NEXT_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PREV_TRACK] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_MEDIA_PREV_TRACK, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_PLAY_PAUSE] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_MEDIA_PLAY_PAUSE, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 
    this._virtualKeyScanCodes[(uint)KeysEx.VK_MEDIA_STOP] = 
     NativeMethods.MapVirtualKeyEx(
      (uint)KeysEx.VK_MEDIA_STOP, NativeMethods.MAPVK_VK_TO_VSC_EX, this._inputLanguage.Handle); 

    this._stateController = new KeyboardStateController(); 
    this._baseVirtualKeyTable = new VirtualKeyTable(this); 
} 

編輯:另見this question這與您的相似。

2

沒有包含鍵盤佈局的內置.NET類。鍵盤佈局是操作系統的功能,通常是Windows。在.NET介入時,按下的鍵已從硬件事件轉換爲軟件事件。如果你想看到這個動作,找到兩個鍵盤佈局,其中一個鍵在它們之間移動。使用Key_Down事件上的事件處理程序設置虛擬應用程序,然後注意事件參數是相同的;如果按下了密鑰,則無論-密鑰位於何處,您都按下了密鑰-