I'm trying to use the ToUnicode
function in response to receiving a WM_KEYDOWN
notification, which sounds a lot easier than it is.
Actually, ToUnicode
should superfluous if one simply uses WM_CHAR
, but much to my surprise this actually does not work properly at all! Having used WM_CHAR
in no-common-controls-programs for ages, I've just for the first time ever typed a word with a diacritic accent1 only to realize that dead keys don't work at all!
As in, if I type for example ´e
, then WM_CHAR
is telling me e
when it should be telling é
(similar for other dead key combinations, such asâ
).
ToUnicode
seems like the obvious solution according to its documentation -- unwieldy as it is, its MSDN description page states that it does exactly what I need. It does take an awful lot of parameters, but those too seem straighforward.
The first parameter is simply the virtual key code (wParam
), and the second one can be obtained via MapVirtualKey
.
The third parameter is optional, so not actually needed (that's what "optional" means, isn't it!). Here's the first surprise: If you don't provide the key state, the function simply fails ("no key mapped") for any key you press. Which means an extra call to GetKeyboardState
is needed.
That leaves us with this code:
case WM_KEYDOWN:
BYTE kb[256];
GetKeyboardState(kb);
WCHAR uc[5] = {};
switch(ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0))
{
case -1: _putws(L"dead key"); break;
case 0: _putws(L"no idea!"); break;
case 1:
case 2:
case 3:
case 4:
_putws(uc);
}
...
This outputs the proper Unicode character for every normal character (no big achievement, you already get that from WM_CHAR
), but spectacularly fails for dead keys, in the exact same way (one might suspect TranslateMessage
uses ToUnicode
to produce WM_CHAR
).
The shift and alt keys as well as altgr are all honored (so for example typing µ
(altgr-m) will give me µ
just fine), but the diacritic dead keys (like acute or circumflex) won't work. Which means if you were to try to type some French or Spanish words on my German-layout keyboard, you're without luck.
Is there a way to use this function properly, so it works? Or, alternatively, is there a different function that works properly for dead keys?
I cannot confirm the symptoms you describe. I used Spy++ to monitor the messages received by Notepad. Then I pressed the dead key ´
, followed by an e
.
As you can see, the WM_CHAR
message is absolutely correct with the Unicode character 233. That represents é
.
<00001> 000F0C86 P WM_KEYDOWN nVirtKey:VK_OEM_6 cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00002> 000F0C86 P WM_DEADCHAR chCharCode:'180' (180) cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00003> 000F0C86 P WM_KEYUP nVirtKey:VK_OEM_6 cRepeat:1 ScanCode:0D fExtended:0 fAltDown:0 fRepeat:1 fUp:1
<00004> 000F0C86 P WM_KEYDOWN nVirtKey:'E' cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00005> 000F0C86 P WM_CHAR chCharCode:'233' (233) cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:0 fUp:0
<00006> 000F0C86 P WM_KEYUP nVirtKey:'E' cRepeat:1 ScanCode:12 fExtended:0 fAltDown:0 fRepeat:1 fUp:1
So WM_CHAR
is everything you need if you just want the composed input. Otherwise, you can handle WM_DEADCHAR
and process the input manually.
Please read the docs about keyboard input on MSDN.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With