Home > OS >  winuser.h keyboard input char to hex convertion
winuser.h keyboard input char to hex convertion

Time:07-31

I've been searching and testing this for a while now and haven't found an answer to the problem i have.

What i'm trying to do is make my own kind of library for mouse and keyboard simulated keypress. I'm trying to do this for a fun little project where i can automate some tasks that are impossible to integrate with any other way. Simulating a user this way would be handy.

My problem lies with keyboard key presses. to be more precise here's an example code for pressing the letter 'a' on the keyboard:

    INPUT inputs[2] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = 0x41;

    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = 0x41;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));

This works fine. So i tried to make it into a variable:

void keyboardKeyPress(char key)
{
    INPUT inputs[2] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = key;

    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = key;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}

This also works fine. BUT as soon as i iterate through a string using this function, it outputs something weird. i tested this with the string "hello" and it outputs "85/". Here's the code i'm using:

#include <iostream>
#include <cmath>
#include <windows.h>
#include <winuser.h>

using namespace std;

void keyboardKeyPress(char key)
{
    INPUT inputs[2] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = key;

    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = key;
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}

void keyboardType(const string str)
{
    for(int i = 0; i < str.length(); i  )
    {
        keyboardKeyPress(str[i]);
    }

}

int main()
{
    keyboardKeyPress(65);
    keyboardKeyPress(66);
    keyboardKeyPress(' ');
    keyboardType("hello");
    return 0;
}

It outputs "ab 85/". I tried to do many things. i realised you can use hex codes instead of chars because the .ki.wVk actually wants unsigned short's. it works when you plug the values in statically but as soon as you try to get the hex values from an eg unsigned short array, it goes back to displaying "85/". The array:


WORD ascii[] = {
    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
    0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
    0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
    0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
    0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
    0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
    0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
    0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
    0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
    0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
    0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
    0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
    0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F
};

The array index is basically the ascii integer number and the value stored is the unsigned short (or WORD from winuser). And here's the changed function:

void keyboardKeyPress(char key)
{
    INPUT inputs[2] = {};
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = ascii[int(key)];

    inputs[1].type = INPUT_KEYBOARD;
    inputs[1].ki.wVk = ascii[int(key)];
    inputs[1].ki.dwFlags = KEYEVENTF_KEYUP;
    SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
}

CodePudding user response:

Your functions don't work as expected because ASCII codes are not Virtual Key codes, though there is some overlap but not the way you think.

The A and B keys on the keyboard are represented by virtual key codes VK_A (65/0x41) and VK_B (66/0x42), respectively. They also happen to be the same values as the ASCII codes for the 'A' and 'B' characters, not the 'a' (97/0x61) and 'b' (98/0x62) characters.

When typing on a keyboard, uppercase and lowercase letters are differentiated by whether the Shift key (virtual key code VK_SHIFT, 16/0x10) is held down or not.

Since you are not simulating the Shift key being held down, that is why keyboardKeyPress(65) and keyboardKeyPress(66) are outputting a and b.

However, the ASCII code for the 'h' character (104/0x68) is the same value as the virtual key code VK_NUMPAD8. The H key on the keyboard is represented by virtual key code VK_H (72/0x48) instead.

The 'e' character is ASCII code 101/0x65, aka virtual key code VK_NUMPAD5, not VK_E (69/0x45).

The 'l' character is ASCII code 108/0x6C, aka virtual key code VK_SEPARATOR (which does not represent any ASCII character) , not VK_L (76/0x4C).

The 'o' character is ASCII code 111/0x6F, aka virtual key code VK_DIVIDE, not VK_O (79/0x4F).

That is why keyboardType("hello") is outputting 85/.

Also, your ascii[] array is useless, because it is simply mapping the character codes back to their original values as-is, not to the proper virtual key codes.

So, to fix your code, you would have to get rid of the ascii[] array, and instead add additional logic to "hold down" the VK_SHIFT virtual key for an uppercase letter if it is not currently down, and "release" it for a lowercase letter if it is currently down. And then things get more complex if you need to deal with languages that have non-ASCII characters, etc.

That said, simulating textual characters is much easier if you use the KEYEVENTF_UNICODE flag. Use virtual key codes only for non-textual keys. And you should send the entire string as one atomic unit instead of sending each character individually (injecting multiple events atomically into the event queue is one of the key features of SendInput() over keybd_event()). See my previous answer for an example of using SendInput() with strings.

  • Related