2009-12-26 35 views
13

看來,如果您在全局WH_KEYBOARD_LL掛鉤中調用ToAscii()ToUnicode(),並且按下死鎖,它將被「銷燬」。鍵盤掛鉤中的ToAscii/ToUnicode銷燬死鎖

例如,假設您在Windows中將輸入語言配置爲西班牙語,並且您希望在程序中鍵入重音字母。通常情況下,按下單引號鍵(死鍵),然後按字母「a」,然後在屏幕上按預期方式顯示帶重音符號的-

但是,如果您在低級鍵盤掛接功能中調用ToAscii()ToUnicode(),則此功能無效。看起來,死鑰匙被銷燬,所以沒有重音字母顯示在屏幕上。取消對上述功能的調用可解決問題......但不幸的是,我需要能夠調用這些功能。

我谷歌搜索了一段時間,雖然很多人似乎有這個問題,但沒有提供好的解決方案。

任何幫助將不勝感激!

編輯:我打電話ToAscii()在我LowLevelKeyboardProc鉤子函數接收到的虛擬鍵碼和掃描碼轉換成將被顯示在屏幕上,用戶產生的字符。

我試過MapVirtualKey(kbHookData->vkCode, 2),但這不像ToAscii()那樣「完整」例如,如果按Shift + 2,則會得到'2',而不是'@'(或Shift + 2將爲用戶的鍵盤佈局/語言生成的任何內容)。

ToAscii()是完美的...直到死鎖被按下。

EDIT2:這裏的鉤子函數,用不相干的信息刪除:

LRESULT CALLBACK keyboard_LL_hook_func(int code, WPARAM wParam, LPARAM lParam) { 

    LPKBDLLHOOKSTRUCT kbHookData = (LPKBDLLHOOKSTRUCT)lParam; 
    BYTE keyboard_state[256]; 

    if (code < 0) { 
     return CallNextHookEx(keyHook, code, wParam, lParam); 
    } 

    WORD wCharacter = 0; 

    GetKeyboardState(&keyboard_state); 
    int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, 
        keyboard_state, &wCharacter, 0); 

    /* If ta == -1, a dead-key was pressed. The dead-key will be "destroyed" 
    * and you'll no longer be able to create any accented characters. Remove 
    * the call to ToAscii() above, and you can then create accented characters. */ 

    return CallNextHookEx(keyHook, code, wParam, lParam); 
} 
+0

請顯示ToUnicode()的調用代碼。你在哪裏得到lpKeyState參數? – jdigital 2009-12-27 03:00:02

+0

@jdigital:嗯,我個人打電話給ToAscii,但我也讀過ToUnicode。我的調用基本上是WH_KEYBOARD_LL鉤子函數中的ToAscii(kbHookData-> vkCode,kbHookData-> scanCode,GetKeyboardState(),&lpchar,0)。當ToAscii調用返回-1時,這意味着按下了一個死鍵......並且如我上面解釋的那樣,死鍵被「銷燬」。 – 00010000 2009-12-27 04:14:32

+0

我刪除了我的答案,它是完全不正確的,假設你指的是c-runtime函數來轉換字符串而不是Win32 apis來轉換掃描碼......對不起。 – 2009-12-27 04:31:59

回答

3
  1. 停止使用toascii將(),並使用ToUncode()
  2. 記得ToUnicode還可以將您在死鍵什麼 - 這就是爲什麼他們被稱爲死鑰匙。
  3. 任何密鑰都有掃描碼或虛擬鍵碼,但不需要一個字符。

您不應該將按鈕與字符組合 - 假設任何按鍵/按鈕具有文本表示(Unicode)是錯誤的。

所以:

  • 輸入文本使用字符由Windows
  • 報告檢查按鈕按下使用掃描碼虛擬按鍵(可能(例如遊戲)。虛擬鍵更好)。
  • 對於鍵盤快捷鍵使用虛擬鍵碼代碼。
+0

我嘗試使用ToUnicode(),但同樣的事情發生......「死鑰匙」被破壞,所以當我按下重音鍵時會顯示雙重口音,而且我無法制作任何重音字母。卸載鉤子立即解決了這個問題。不調用ToAscii()或ToUnicode()會立即修復此問題。 – 00010000 2009-12-28 18:15:36

+0

嘗試製作鍵盤狀態結構的副本,以防止Windows更改原來的結構。 – sorin 2009-12-31 16:41:29

2

呼叫「toascii將」功能兩次死鍵,一個正確的處理就像在:

int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, 
       keyboard_state, &wCharacter, 0); 
int ta = ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, 
       keyboard_state, &wCharacter, 0); 
If (ta == -1) 
... 
+3

這只是'殺死'我的死鑰匙。例如。 'ë'變成'e',但是按下一個死鑰匙仍然給出例如¨¨ – 2013-08-26 11:40:35

2

調用ToAsciiToUnicode兩次就是答案。 我發現這個並將它轉換爲Delphi,並且它可以工作!

cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0); 
cnt:=ToUnicode(VirtualKey, KeyStroke, KeyState, chars, 2, 0); //yes call it twice 
+0

它好一點,因爲我的'^'字符只有在第二次按鍵按下後纔會顯示,但不起作用,因爲重音不會覆蓋該字母,因爲它應該產生「ô」,但只有產生'o' – Flox 2017-06-04 09:42:56

+0

其實你的答案是一樣的@藍眼睛下面:https://stackoverflow.com/a/3625039/2165463 – Flox 2017-06-04 09:43:46

0

我複製vkCode在隊列中做轉換從另一個線程

@HOOKPROC 
def keyHookKFunc(code,wParam,lParam): 
    global gkeyQueue 
    gkeyQueue.append((code,wParam,kbd.vkCode)) 
    return windll.user32.CallNextHookEx(0,code,wParam,lParam) 

這還沒有通過操作系統

1

一個相當古老的線程延遲鍵處理的優勢。不幸的是,它沒有包含我正在尋找的答案,也沒有任何答案似乎正常工作。我終於通過在調用ToUnicode/ToAscii之前檢查MapVirtualKey函數的MSB來解決了這個問題。似乎是工作就像一個魅力:

if(!(MapVirtualKey(kbHookData->vkCode, MAPVK_VK_TO_CHAR)>>(sizeof(UINT)*8-1) & 1)) { 
    ToAscii((UINT)kbHookData->vkCode, kbHookData->scanCode, 
     keyboard_state, &wCharacter, 0); 
} 

上的MapVirtualKey返回值引用MSDN,如果MAPVK_VK_TO_CHAR使用:

[...]死鍵(附加符號)通過設置指示返回值的最高位。 [...]

+0

你能請詳細說明嗎?我沒有得到你的代碼,如果你不輸入if()會怎麼樣?什麼也不做? – 2017-01-28 00:08:17

+1

如果它沒有輸入if,則當前按下的按鍵是死鎖。根據你想要達到的目標,你可以對它做出反應,或者簡單地忽略它,以防止你只想聽到非死亡的按鍵。希望這可以幫助。 – 2017-01-29 16:18:53

+0

謝謝,我知道了 – 2017-01-29 16:20:48