IME - How to handle key press - c++

In my game code, I process key input by handling WM_KEYDOWN message.
wParam gives me the keycode i need.
The problem is with IME, especially KoreanIME.
I get WM_IME_COMPOSITION and then WM_KEYUP, but never the WM_KEYDOWN.
So, the bottom line is.. I need to get keycode when i receive WM_IME_COMPOSITION.
Is there a way to do so?
Any help will be greatly appreciated.
Thanks!

according to http://msdn.microsoft.com/en-us/library/dd374133(VS.85).aspx the composite key is in the wParam, encoded as DBCS (http://www.microsoft.com/typography/unicode/cs.htm). I guess you have to extract the appropriate byte from the word and decide according to that.

I know this is a bit late, but for the benefit of others, one could use
BOOL ImmDisableIME(
__in DWORD idThread
);
Pass the ID of the UI thread, the one which handles key presses.
http://msdn.microsoft.com/en-us/library/dd318535(v=VS.85).aspx

Related

Determine whether WM_KEYDOWN's wParam is printable

I am trying to detect non-printable characters in my window's WM_KEYDOWN message, but research so far has yielded no results. I have tried the following methods:
1: iscntrl(wParam), which does not work for the arrow keys
2: ischar(wParam), which also does not work for the same keys
3: ToAscii(wParam, MapVirtualKey(wParam, 0) ...), which still does not work
IMO the third method should work because arrow keys are not on any ASCII or Unicode tables.
The thing is I would like to send to my event handlers both the keycode and the character. Since WM_CHAR is posted after WM_KEYDOWN, I would like to just send the key in WM_KEYDOWN if it is not printable (because WM_CHAR would not be sent to the window so I cannot do it there).
Thanks
Given that most of the keys which are generally considered "printable" are contiguous, why not just use a few if statements to decide how you want to handle them? In WM_KEYDOWN, decide whether a key is "printable" or not, and if it is, fire it off to WM_CHAR.
The functions that you're researching aren't designed for this specific purpose, so ironically, you might spend more time researching them than it would take to make an ad-hoc solution on your own.
Your method #3 should work for this. In PreTranslateMessage, handling WM_KEYDOWN:
BYTE keyboardState[256];
::GetKeyboardState(keyboardState);
WORD ascii;
int len = ::ToAscii(wParam, (lParam >> 16) & 0xFF, keyboardState, &ascii, 0);
if (len == 1)
{
/* it's printable */
printf("%c", ascii & 0xFF);
}

Handling keyboard input in win32, WM_CHAR or WM_KEYDOWN/WM_KEYUP?

So in the text editor program that i've been working on, I've used WM_CHAR to process input from the keyboard. However, I found that some of the character mesages are not recorded. For example, if I use [shift]+ number key to type a symbol such as % or &, some re recorded while others such as [shift]+9 (which results in ')'), are not recorded. So, I'm wondering if I should use WM_KEYDOWN/WMKEYUP pair to handle keyboard input. I once wrote a keylogger in assembly(actually it was just a tutorial that i was trying out) and had used WM_KEYDOWN/WM_KEYUP pairs and that worked out quite good. So, should I move on to this, or is it something unusual that is happening with my program?
Thanks,
Devjeet
This is really a long reply to your comment above, but putting it in an answer because it's too long for a comment :)
The core issue to understand here is that keys and characters are not quite the same thing. Some (but not all) keys generate characters; some keys generate different characters depending on shift or other keyboard state. And to implement an editor, you need to handle both textual input and also non-textual keyboard input like arrow keys. Now the long-winded version, picking off from what seems to be an incorrect assumption:
Apparently, windows works in really strange ways. [...] It seems that when you press [shift]+9, windows sends a VK_LEFT in the wParam of message WM_CHAR
Sounds like you might be mixing two things up here. The thing with WM_CHAR is that it gives you character codes for textual characters: so if someone presses the 9 key, you'll get '9'. If someone presses SHIFT+9, Windows will take the shift state into account - and you get '(' (if using US keyboard). But you won't ever get a WM_CHAR for arrow keys, HOME, END, and so on, since they are not textual characters. WM_KEYDOWN, on the other hand, does not deal in characters, but in VK_ codes; so pressing 9 gives you VK_9 regardless of shift state; and left arrow gives you VK_LEFT - again regardles of shift state.
The things is that WM_CHAR and WM_KEYDOWN both give you two parts to the overall input picture - but you really have to handle both to get the full picture. And have to be aware that the wParam is a very different thing in both cases. It's a character code for WM_CHAR, but a VK_ code for WM_KEYDOWN. Don't mix the two.
And to make things more confusing, VK_ values share the same values as valid characters. Open up WinUser.h (it's in the include dir under the compiler installation dir), and look for VK_LEFT:
#define VK_LEFT 0x25
Turns out that 0x25 is also the code for the '%' character (see any ascii/unicode table for details). So if WM_CHAR gets 0x25, it means shift-5 was pressed (assuming US keyboard) to create a '%'; but if WM_KEYDOWN gets 0x25, it means left arrow (VK_LEFT) was pressed. And to add a bit more confusion, the Virtual Key codes for the A-Z keys and 0-9 keys happen to be the same as the 'A'-'Z' and '0'-'9' characters - which makes it seem like chars and VK_'s are interchangable. But they're not: the code for lower case 'a', 0x61, is VK_NUMPAD1! (So getting 0x61 in WM_CHAR does mean 'a', getting it in WM_KEYDOWN means NUMPAD1. And if a user does hit the 'A' key in unshifted state, what you actually get is first a VK_A (same value as 'A') in WM_KEYDOWN, which gets translated to WM_CHAR of 'a'.)
So tying all this together, the typical way to handle keyboard is to use all of the following:
Use WM_CHAR to handle textual input: actual text keys. wParam is the character that you want to append to your string, or do whatever else with. This does all the shift- processing for you.
Use WM_KEYDOWN to handle 'meta' keys - like arrow keys, home, end, page up, and so on. Pass all the A-Z/0-9 values through, the default handling will turn them into WM_CHARs that you can handle in your WM_CHAR handler. (You can also handle numpad keys here if you want to use them for special functionality; otherwise they 'fall through' to end up as numeric WM_CHARs, depending on numlock state. Windows takes care of this, just as it handles shift state for the alphabetic keys.)
If you want to handle ALT- combos explicitly (rather than using an accelerator table), you'll get those via WM_SYSKEYDOWN.
I think there are some keys that might show up in both - Enter might show up as both a WM_KEYDOWN of VK_RETURN and as either \r or \n WM_CHAR - but my preference would be to handle it in WM_KEYDOWN, to keep editing key handling separate from text keys.
Spy++ will show you the messages being sent to a window, so you can experiment and see what messages are appropriate for your application.
If you have Visual Studio installed, it should be in your Start menu, under Programs -> Microsoft Visual Studio -> Visual Studio Tools -> Spy++.
WM_CHAR
WM_KEYDOWN
The helpful message above inspired me to create this snippet, which gives you a human-readable indication of what key was pressed from any WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP independent of the state of the modifier keys.
// get the keyboard state
BYTE keyState[256];
GetKeyboardState(keyState);
// clear all of the modifier keys so ToUnicode will ignore them
keyState[VK_CONTROL] = keyState[VK_SHIFT] = keyState[VK_MENU] = 0;
keyState[VK_LCONTROL] = keyState[VK_LSHIFT] = keyState[VK_LMENU] = 0;
keyState[VK_RCONTROL] = keyState[VK_RSHIFT] = keyState[VK_RMENU] = 0;
// convert the WM_KEYDOWN/WM_KEYUP/WM_SYSKEYDOWN/WM_SYSKEYUP to characters
UINT scanCode = (inLParam >> 16) & 0xFF;
int i = ToUnicode(inWParam, scanCode, keyState, outBuf, inOutBufLenCharacters, 0);
outBuf[i] = 0;
By modifying the keyState array so that all the modifier keys are clear, ToUnicode will always output the unshifted key you pressed. (So, on the English keyboard you'll never get '%' but always '5') as long as it's a human readable key. You still have to do the VK_XXX checking to sense the arrow and other non-human readable keys however.
(I was trying to rig up a user editable "hot key" system in my app, and the distinction between WM_KEYXXX and WM_CHAR was making me nuts. The code above solved that problem.)

Obtaining the virtual key code from a WM_CHAR message

I am getting text input and keypress input from the WM_CHAR and WM_KEYDOWN messages
What I want to do is filter out WM_CHAR messages the have the same VK_ code as the key that is bound to enable the control that you enter text in.
EG: Game uses ~ to enable console, key binding is done via VK_OEM3 and WM_KEYDOWN, but text input into the console needs text from WM_CHAR.
As the WM_KEYDOWN happens first, the console is activated, then a WM_CHAR of ~ is sent to the console buffer which I don't want.
I figured the best way to prevent this is to compare the VK_ from the WM_CHAR to the bound key for the control and filter it out.
Is there a way to get the VK_ from a WM_CHAR message?
I read that you can get the scancode out of Lparam at bits 16-23
But am unsure how to:
Extract the value of the scancode from lparam
Translate the scan code to a VK_ correctly
After some messing around I managed to extract the virtual key with the following code:
This code gets the address of lParam as a unsigned char array (one byte of length), then uses pointer arithmatic to address the 3rd byte (bits 16-23):
unsigned char scancode = ((unsigned char*)&lParam)[2];
This code translates from the scancode to the virtual key:
unsigned int virtualKey = MapVirtualKey(scancode,MAPVK_VSC_TO_VK);
Perhaps you migh use MapVirtualKey.
I am not sure how to extract scancode from lparam as documentation does not state that - either get entire lparam and count that this function knows which bits to look at, or use bitfield struct and just get right bits out of it. I think on of those methods should work - trying both shouldn't be difficult.

Get text using SendMessage() C++

I am trying to get text from a textbox in a specific window. For this I'm using SendMessage Api function, I dont know if this is the corect way:
SendMessage(hwnd, WM_GETTEXT, 0, 0);
But I dont know how to print the text. For the argument 3 and 4 in msdn site it says: Additional message-specific information. So i dont know if I need to pass something else beside 0. I tried this also:
SendMessage(hwnd, WM_GETTEXT, sizeof(text), LPARAM(text));
But it prints the name of the textbox, I need to retrieve the text inside the box?
How can I do this? Is SendMessage() the correct API function to use ?
Thank you.
edit:
I omit to say, I am enumerating the child windows from a window, and for me it looks like a textbox, where you have to type a name. I am retrieving the username of a Instant messaging window so I cant compare it to a string, is that a textbox ?
You should use GetWindowText. More information here.
Read the MSDN documentation again. It does NOT say "Additional message-specific information" for those parameters:
wParam The maximum number of
characters to be copied, including the
terminating null character.
ANSI applications may have the string
in the buffer reduced in size (to a
minimum of half that of the wParam
value) due to conversion from ANSI to
Unicode.
lParam A pointer to the buffer that
is to receive the text.
This code works for local only:
char *szText;
szText = (char *)GlobalAlloc(GPTR, 255);
SendMessage(hEditControl, WM_GETTEXT, 255, (LPARAM)szText);
MessageBox(hWnd, szText, "It's your message", MB_OK | MB_TOPMOST);
GlobalFree((HGLOBAL)szText);

WinAPI: How to process keyboard input in custom edit control

So i'm creating my own edit control (multi-line textbox) in C++ using the windows API. It's going pretty well, but i'm a bit confused about one thing.
First off, the control is being built to be able to handle unicode and all input will be converted to unicode. In other words, all input will be stored as wchar_t.
What i'm confused about is which message to process for keyboard input. MSDN has the following window notifications:
WM_CHAR
WM_KEYDOWN
WM_UNICHAR
And others, but i believe it's one of these three that i need to process. My guess would be WM_UNICHAR, but the documentation is a bit unclear about it. Also, upon looking over the VKcodes, i saw this:
VK_PACKET
0xE7
Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP.
Sorry if it's a silly question, but i just want to be sure about this.
If your control is created as a unicode window (using CreateWindowW) then
in WM_CHAR you will get wide char out of the box.
If you want to provide non-unicode version of your control then you need to handle
WM_INPUTLANGCHANGE, something like this:
case WM_INPUTLANGCHANGE:
{
HKL NewInputLocale = (HKL) lParam ;
g_InputCodePage = LangToCodePage( LOWORD(NewInputLocale) ) ;
}
And so your WM_CHAR handler should look like:
case WM_CHAR:
{
unsigned char c = (byte)wParam;
if(!::IsWindowUnicode(hwnd))
MultiByteToWideChar(g_InputCodePage , 0, (LPCSTR) &c, 1, (LPWSTR) &wParam, 1) ;
}
And don't forget about WM_IME_CHAR and friends.
And yet about RTL input.
WM_KEYDOWN is sent to the window with the focus when a non-system key has been pressed. When the message is translated by the TranslateMessage function, a WM_CHAR message is sent to the window. WM_CHAR uses UTF-16. WM_UNICHAR is similat to WM_CHAR, except that it uses UTF-32. It's purpose is to send/post Unicode characters to ANSI windows. If the window is ANSI (created with CreateWindowA), when WM_CHAR is generated. If it is Unicode (created with CreateWindowW) then WM_UNICHAR is generated. So your control should probably handle both.
Also see this discussion Why is my WM_UNICHAR handler never called?.