views:

497

answers:

3

I'm having trouble simulating character keypresses when a non-English input keyboard language is being used in Windows.

I tried calling SendInput() with KEYEVENTF_UNICODE:

KEYBDINPUT ki;
INPUT input;
int character = 0;

ki.wVk = 0;
ki.wScan = character;
ki.dwFlags = KEYEVENTF_UNICODE;
ki.time = 0;
ki.dwExtraInfo = 0;   
input.type = INPUT_KEYBOARD;
input.ki = ki;
SendInput(1, &input, sizeof(INPUT));

And this actually works (of course, in my code, I also do a KEYUP after the key down)... except in GTK+ apps (there may be other instances where it doesn't work either).

According to MSDN, If KEYEVENTF_UNICODE is specified, SendInput sends a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, passing the message to TranslateMessage posts a WM_CHAR message with the Unicode character originally specified by wScan. This Unicode character will automatically be converted to the appropriate ANSI value if it is posted to an ANSI window.

So I believe that when KEYEVENTF_UNICODE is passed, the functionality of SendInput() is different... not as low-level as it usually is.

For the life of me, I can't figure out any other way to get SendInput() to print out characters properly for the user's keyboard language. For example, if the keyboard input language is "Swedish", I can't get it to output '@' (instead, it prints out a quotation mark), and I can't get it to output non-ASCII characters properly, either (accented letters, etc).

Thanks in advance.

A: 

As I understand it SendInput() is just a wrapper around calls to mouse_event() and keybd_event() that gurantees that your input doesn't get interspersed with input from the user or other callers.

So I guess the question I have is, have you tried using keybd_event()?

John Knoeller
Yeah, I actually was trying to use keybd_event(), until I noticed that SendInput accepted Unicode characters directly with the KEYEVENTF_UNICODE flag. Since keybd_event() takes a virtual-key code and scan code just like SendInput() does, I wasn't able to figure out how to get keybd_event() to work for me, either.
00010000
Yeah. Some international keyboards use multiple keypresses to 'compose' a single keyevent. SendInput lets you get that keyevent without having to build (or know) all of the little keypresses that go into it.
John Knoeller
I'm afraid I can't be more help that that. I can point out that scancodes aren't the same thing as the virtual keycodes that they map to, but I presume you already know that.
John Knoeller
+1  A: 

I discovered that the proper way to do this is to get the virtual-key code of the character by calling VkKeyScanEx() with the character. The high-order bytes of the return value will tell you which modifier keys you need to "press": Control, Alt, and/or Shift; the low-order bytes are the actual virtual-key code.

To get the scan code of the VK, call MapVirtualKeyEx(vkCode, 0);

Then it's just a matter of doing the keypress simulation with the information just obtained.

00010000
I'm not sure how do you use this information but you should remember that the result is dependent on the current keyboard layout.
Sorin Sbarnea
A: 

In .NET all strings are kept as Unicode (UTF-8) strings, internally. You can verify that by converting a string to an array (byte[], NOT char[]!). So you can just ignore anything about scan codes, keyboard layouts and virtual keycodes.

The following works for me in C#/.NET:

string myText = "greekcyrillicjapaneseorwhathaveyou"; // can be input via a Forms textbox

char[] Mychars = myText.ToCharArray();

UInt16 uniCode = chars[5]; // if you want to simulate, say, the sixth' char of the string

...

ki.wScan = unicode

ki.dwFlags = KEYEVENTF_UNICODE; ...

Rolf Keller