SendInput() isn't "sending" the correct shifted characters?
Asked Answered
G

2

7
void WriteChar(char c)
{
    INPUT input = {0};
    input.type = INPUT_KEYBOARD;
    input.ki.wVk= VkKeyScanEx(c, GetKeyboardLayout(0) ) ;   
    SendInput(1,&input, sizeof(INPUT));
}

VkKeyScanEx returns different key codes for '/' and '?'(same key), however if you try using this method to write a message containing '?', it will only write '/'. I don't know what's going on. Same thing occurs with ';' and ':'.

I partly don't understand key codes and scan codes. Most characters have a virtual key code, however I can't find something similar for question marks. They must exist, but aren't listed?

Gallinule answered 30/1, 2010 at 7:8 Comment(0)
R
9

Scan codes are the raw key ids returned from the keyboard. So a 101 key keyboard will (in theory) have 101 unique scan codes that it can return. (see footnote 1)

Virtual key codes are a separate set of codes that represent an key on an idealized keyboard. No matter where on a real keyboard the TAB key is, and what scancode is used for it, the virtual key code is always VK_TAB. windows.h defines VK_xxx codes for non-printable virtual keys, for the printable ones, the virtual key code is the same as the ASCII value.

But virtual key codes are still key codes. 'A' and 'a' have the same virtual key code, so if you want to send an 'A' then you have to send a VK_SHIFT down, then 'a' down, then 'a' up, then VK_SHIFT up.

VkKeyScanEx() converts a character into a scan key and shift state See the quote below from this page http://msdn.microsoft.com/en-us/library/ms646332(VS.85).aspx

If the function succeeds, the low-order byte of the return value contains the virtual-key code and the high-order byte contains the shift state, which can be a combination of the following flag bits.

So you can't just take the return from VkKeyScanEx(), you need to check to see if it has a shift key flagged. and send the shift key as a separate keystroke

SHORT vk = VkKeyScanEx(c, ...);
if (vk & 0x100) // check upper byte for shift flag
{
   // send a shift key down
}
if (vk & 0x200) // check for ctrl flag
{
   // send a ctrl key down
}
input.ki.wVk = vk & 0xFF;

// send keyup for each of the keydown

You also have to send a keyup for every keydown.

Footnotes:

1 This is in theory only, in practice standard PC keyboards emulate a old IBM keyboard that you can't even get anymore, so some keys can return 2 different scan codes based on another key, while other in other cases two keys can return the same scan code.

Rhombencephalon answered 30/1, 2010 at 7:42 Comment(5)
Hi, thanks for the reply. I assumed you didn't have to do keyup for every keydown because if you were to test this in a notepad window, it only writes a single character (whereas if it was held down and never released, it would obviously be a never ending string of the character). Why am I wrong for assuming this?Gallinule
When you hold a key down, the keyboard actually sends keydown,keydown,keydown,keydown,... and keyup when you finally release it. The exception to this is CTRL, SHIFT and ALT which don't repeat.Rhombencephalon
I don't think it's the actual keyboard itself that repeatedly sends the "keydown" signals. I believe this behaviour is actually controlled by the computer.Hann
If its an old style PS/2 keyboard, then it's the keyboard. I don't know what USB keyboards do, but I suspect it's the driver that handles repeat for USB keyboards.Rhombencephalon
Remember to send VK_RMENU for ALT since keyboard combos use right ALT for chars.Sulphathiazole
H
1

Try doing it like this. If you do it using KEYEVENTF_UNICODE, the host platform will need to be at least Windows 2000 or XP.

INPUT input[ 2 ];

input[ 0 ].type = INPUT_KEYBOARD;
input[ 0 ].ki.wVk = 0;
input[ 0 ].ki.wScan = c;
input[ 0 ].ki.dwFlags = KEYEVENTF_UNICODE;
input[ 0 ].ki.time = 0;
input[ 0 ].ki.dwExtraInfo = GetMessageExtraInfo();

input[ 1 ].type = INPUT_KEYBOARD;
input[ 1 ].ki.wVk = 0;
input[ 1 ].ki.wScan = c;
input[ 1 ].ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
input[ 1 ].ki.time = 0;
input[ 1 ].ki.dwExtraInfo = GetMessageExtraInfo();

SendInput( ( UINT )2, input, sizeof( *input ) );

Judging from the fact that you didn't fill out your input structure correctly and left some required members uninitialised, I'd assume you haven't seen the documentation for this. See SendInput, INPUT and KEYBDINPUT.

Hann answered 30/1, 2010 at 7:25 Comment(3)
I often see examples of input.ki.dwExtraInfo being set to 0. Should it be input[ 0 ].ki.dwExtraInfo = GetMessageExtraInfo();?Gumbo
@rasteve, I honestly don't know! I probably just did that because the documentation for KEYBDINPUT says this about dwExtraInfo: Use the GetMessageExtraInfo function to obtain this information..Hann
I read it as using GetMessageExtraInfo to get what you keyed into dwExtraInfo but now I am not too sure.Gumbo

© 2022 - 2024 — McMap. All rights reserved.