C++ ToUnicodeEx() not recognizing shift key unless i have a messgaebox() - c++

im having a bit of trouble writing a keyboard hook in C++.
I can read keystrokes but im trying to using ToUnicodeEx() to convert keystrokes when shift key is pressed.
In the code i have so far i have
i = ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
MessageBox(MainnhWnd,keybuff, L"message", MB_OK | MB_ICONEXCLAMATION);
with this 'MessageBox' line when I press Shift+2 i get two message boxes pops up, the first is blank for the shift key, the second shows a '#' character. This is expected.
But if i remove this messagebox, the ToUnicodeEx() function converts the keystroke as if the shift key had not been used. I can see this by either setting a breakpoint, with a hit counter, or outputting the character to an edit box in my program windows.
Also when i include the MsgBox line and use the CapLock, my letters change accordingly but after i remove the msgbox line it only uses the state of the cap lock at the time my program starts (cap locks is on when programm starts, all letters are capital, vice verse, caps off when programm starts all letters are small,, even if i change the cap lock state)
Anyone know why my hook just remembers the keyboard state at start, unless i include the msgbox?
My hook is set like:
theHook = SetWindowsHookEx ( WH_KEYBOARD_LL, (HOOKPROC) KeyEvent, exe, 0);
and my hook callback function is:
DLLEXPORT LRESULT CALLBACK KeyEvent(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode>=0) {
int i = 0;
KBDLLHOOKSTRUCT keyboard;
WCHAR keybuff[256]= {0};
if ((wParam == WM_KEYDOWN)|| (wParam == WM_SYSKEYDOWN)||(wParam == WM_SYSKEYUP)) {
keyboard = *((KBDLLHOOKSTRUCT*)lParam);
if (keyboard.vkCode == VK_RETURN) {
i += wsprintf (((LPWSTR)keybuff + i),L"[Return]\r\n");
}
else {
HKL keyboardlayout = GetKeyboardLayout(0);
GetKeyboardState((PBYTE)&keyState);
i = ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
MessageBox(MainnhWnd,keybuff, L"message", MB_OK | MB_ICONEXCLAMATION);
}
if (keybuff>0) {
addToEditBox(keybuff);
}
}
}
return CallNextHookEx(theHook, nCode, wParam, lParam);
}

According to documentation of ToUnicodeEx function, you should provide a pointer to a 256-byte array that contains the current keyboard state (const BYTE *lpKeyState). Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down.
Before you call ToUnicodeEx, you should set this array like this (pseudocode):
enum Keys
{
ShiftKey = 16, // shift
ControlKey = 17, // ctrl
Menu = 18, // alt
Capital = 20, // caps lock
};
BYTE keyState[256]= {0};
if (Control key down)
keyState[Keys::ControlKey] = 0x80;
if (Shift key down)
keyState[Keys::ShiftKey] = 0x80;
if (Alt key down)
keyState[Keys::Menu] = 0x80;
if (Caps lock ON)
keyState[Keys::Capital] = 0x01;
And when keyState array is set, then you can call:
ToUnicodeEx(keyboard.vkCode, keyboard.scanCode, (PBYTE)&keyState, (LPWSTR)&keybuff, sizeof(keybuff) / 16, 0,keyboardlayout);
I have been working with ToUnicodeEx function just like this and it worked fine.
Hope this will help you ;)

Related

Low Level Keyboard hook reads the caps lock key as a space character

I'm using a low level keyboard hook to log keystrokes into a .txt file, my issue is that every time I set caps lock ON it logs a null character into the .txt which is represented as an unwanted space character.
I believe this happens because as I set the caps lock ON it also maps its virtual key, which for some reason if represented by a null character; I know this because when I open the file inside VSCode every caps lock ON stroke is represented by a null character (It literally says the word null inside a tiny red box), but when I open the file with the notepad its only blank spaces.
The rest of the code works as intended, I just don't know how to prevent the blank spaces from generating every time I set caps lock ON.
#include <fstream>
#include <ctype.h>
#include <windows.h>
LRESULT CALLBACK kybHP(int nCode, WPARAM wParam, LPARAM lParam){
KBDLLHOOKSTRUCT *lPp = reinterpret_cast<KBDLLHOOKSTRUCT *>(lParam);
switch (wParam){
case WM_KEYDOWN:
// If the shift key is being pressed, cout normally which by default is in UPPERCASE.
if (GetAsyncKeyState(VK_SHIFT) & 0x8000){
char key = MapVirtualKey(lPp ->vkCode, MAPVK_VK_TO_CHAR);
std::ofstream logs;
std::cout<<key;
logs.open("keylogs.txt", std::ios_base::app);
logs<<key;
logs.close();
}
//If Caps Lock is ON, cout normally which by default is in UPPERCASE.
else if (GetKeyState(VK_CAPITAL) == 1){
char key = MapVirtualKey(lPp ->vkCode, MAPVK_VK_TO_CHAR);
std::ofstream logs;
std::cout<<key;
logs.open("keylogs.txt", std::ios_base::app);
logs<<key;
logs.close();
}
else if (lPp->vkCode == VK_BACK){
std::cout<<"[BACK]";
std::ofstream logs;
logs.open("keylogs.txt", std::ios_base::app);
logs<<"[BACK]";
logs.close();
}
//If the shift key isn't pressed, cout in lowercase; this is accomplished by using the tolower function.
else{
char key = MapVirtualKey(lPp ->vkCode, MAPVK_VK_TO_CHAR);
char lowerkey = std::tolower(key);
std::ofstream logs;
std::cout<<lowerkey;
logs.open("keylogs.txt", std::ios_base::app);
logs<<lowerkey;
logs.close();
}
break;
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
int main(){
HHOOK keyboard = SetWindowsHookEx(WH_KEYBOARD_LL, &kybHP, 0, 0);
MSG message;
while (GetMessage(&message, NULL, NULL, NULL) > 0){
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(keyboard);
return 0;
}
The return value of MapVirtualKey is UINT.
If Caps Lock is ON, and Backspace is pressed.
char key = MapVirtualKey(lPp ->vkCode, MAPVK_VK_TO_CHAR);
MapVirtualKey will return 8, the char key will get 8 which is'\b' in the ASCII chart. That's why you get "a null character". In fact, it is not a null character, it is a '\b' character.
As #Paul said, you need to use logs << "[CapsLock]" instead.

What information does dwExtraInfo hold for the PMOUSEHOOKSTRUCT?

LRESULT CALLBACK LowLevelMouseProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
BOOL fpassmove = FALSE;
if (nCode == HC_ACTION)
{
switch (wParam)
{
case WM_MOUSEMOVE: // how do i catch a dx instead of a cursor points?
PMOUSEHOOKSTRUCT me = (PMOUSEHOOKSTRUCT)lParam;
printf("x:%d\ny:%d\nextrainfo:%04X\n", me->pt.x,me->pt.y, me->dwExtraInfo );
break;
}
}
return(fpassmove ? 1 : CallNextHookEx(NULL, nCode, wParam, lParam));
}
int main()
{
// Install the low-level keyboard & mouse hooks
HHOOK hhkLowLevelMouse = SetWindowsHookEx(WH_MOUSE_LL, LowLevelMouseProc, 0, 0);
// Keep this app running until we're told to stop
MSG msg;
while (!GetMessage(&msg, NULL, NULL, NULL)) { //this while loop keeps the hook
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hhkLowLevelMouse);
return(0);
}
I am looking at all mouse moment from a global hook, and I'm trying to find the dx and dy of the mouse event, And I was hoping to find it in "dwExtraInfo". However, I have no idea how to make sense of the data inside "dwExtraInfo".
the windows documentation is not helpful in telling me what the data in dwExtraInfo means
dwExtraInfo
Type: ULONG_PTR
Additional information associated with the message.
Could not find any documentation on dwExtraInfo directly, but found something related: https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getmessageextrainfo:
Return value
Type: LPARAM
The return value specifies the extra information. The meaning of the
extra information is device specific.
One example of such device specific extra information is Pen gestures: https://learn.microsoft.com/en-us/windows/win32/tablet/system-events-and-mouse-messages
Distinguishing Pen Input from Mouse and Touch
When your application receives a mouse message (such as
WM_LBUTTONDOWN), it may call the GetMessageExtraInfo function to
evaluate whether the message originated from a pen or a mouse device.
The value returned from GetMessageExtraInfo needs to be mask-checked
against 0xFFFFFF00, and then compared with 0xFF515700. The following
definitions may make this clearer:
#define MI_WP_SIGNATURE 0xFF515700
#define SIGNATURE_MASK 0xFFFFFF00
#define IsPenEvent(dw) (((dw) & SIGNATURE_MASK) == MI_WP_SIGNATURE
If the comparison is true, then this mouse message was generated by a
Tablet PC pen or touch screen. In all other cases, you can assume that
this message was generated by a mouse device.
The lower 8 bits returned from GetMessageExtraInfo are variable. Of
those bits, 7 (the lower 7, masked by 0x7F) are used to represent the
cursor ID, zero for the mouse or a variable value for the pen ID.
Additionally, in Windows Vista, the eighth bit, masked by 0x80, is
used to differentiate touch input from pen input (0 = pen, 1 = touch).

Is there a way to override the physical key state on Windows in C++?

I essentially want to make a small program which outputs the pressed key at a configurable speed for as long as that key is pressed. I'm using a global WH_KEYBOARD_LL hook in a separate DLL for this.
All of this works, except for the fact, that the original key stays pressed, making this not work in programs that keep an internal key state, as all the new, fake inputs are just ignored. Keys are also auto repeated, though that is not exactly a problem, considering the nature of this program. It would still be nice to also not have auto repeats either, though.
Basically:
physical key down -> (internal_state[key] = true) -> separate loop thread sends down & up inputs at loop speed -> physical key up -> (internal_state[key] = false)
But everything between the physical key up and down is ignored.
Now I could easily go around this issue by using a different, non one-to-one key map (e.g. holding shift outputs lots of space presses) or instead of having to hold the key to just use a toggle. While that would work, it's not what I want.
What I essentially need is a way of overriding the current key state, making the key not pressed after it's first pressed, even though it's still being pressed, physically anyway. Basically something like SetKeyboardState, except not bound to the calling thread, but rather changing the global state.
I'm not sure if this is possible without writing a custom driver, which is beyond the scope of what I want to accomplish, even if that might be interesting to do.
I've tried using keybd_event with dwFlags set to KEYEVENTF_KEYUP, as well as the SendInput equivalent, neither of which cleared the key state.
Edit (minimal code):
LRESULT CALLBACK KeyboardHookProc(
int nCode,
WPARAM wParam,
LPARAM lParam
)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT* kb = (KBDLLHOOKSTRUCT*) lParam;
switch (wParam)
{
case WM_KEYDOWN:
if (
kb->dwExtraInfo != 1
&& kb->vkCode == KeyboardSpamKey
)
{
KeyboardSpam = true;
// this is where "the magic" would need to happen
}
break;
case WM_KEYUP:
if (
kb->dwExtraInfo != 1
&& kb->vkCode == KeyboardSpamKey
)
{
KeyboardSpam = false;
}
break;
}
}
return CallNextHookEx(
KeyboardHook,
nCode,
wParam,
lParam
);
}
void ThreadLoop()
{
while (ThreadEnable)
{
auto now = std::chrono::high_resolution_clock::now();
auto next = now + ThreadSpeed;
// inputKeyboard just returns a zero initialized INPUT, with ip.type = INPUT_KEYBOARD
INPUT ip = inputKeyboard();
ip.ki.wScan = MapVirtualKey(
KeyboardSpamKey,
MAPVK_VK_TO_VSC
);
ip.ki.dwFlags = KEYEVENTF_SCANCODE;
// dwExtraInfo set to 1 to be ignored in KeyboardHookProc
ip.ki.dwExtraInfo = 1;
if (KeyboardSpam)
{
SendInput(
1,
&ip,
sizeof(
ip
)
);
ip.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
SendInput(
1,
&ip,
sizeof(
ip
)
);
}
std::this_thread::sleep_until(
next
);
}
}
ThreadLoop is the function of a detached thread; ThreadEnable and KeyboardSpam are static bools in the main file

GetKeyboardState one key delay

I'm working on ToUnicodeEx function and it requires keyboard state as the input parameter. So, I used the GetKeyboardState function to do that. But I noticed when I'm typing key combinations with modifier keys like SHIFT+A there is one character delay. Here is the example.
aaa (holding SHIFT now) aAAAAAAA (release SHIFT) Aaaa
While I was debugging this I noticed GetKeyboardState is causing this delay. How can I handle or prevent this delay?
Here is my whole keyboard hook proc.
void proc(KBDLLHOOKSTRUCT kbdStruct) {
fdebug = fopen("debug.txt", "a");
foutput= fopen("output.txt", "a");
WCHAR pwszBuff[9];
WCHAR key[9];
char str[8];
BOOL isDead = FALSE;
BYTE lpKeyState[256];
HWND currentHwnd = GetForegroundWindow();
LPDWORD currentProcessID = 0;
DWORD currentWindowThreadID = GetWindowThreadProcessId(currentHwnd, currentProcessID);
DWORD thisProgramThreadId = GetCurrentThreadId();
hkl = GetKeyboardLayout(thisProgramThreadId);
if (AttachThreadInput(thisProgramThreadId, currentWindowThreadID, TRUE))
{
GetKeyboardState(lpKeyState);
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
}
else
{
GetKeyboardState(lpKeyState);
}
int ret = ToUnicodeEx(kbdStruct.vkCode, kbdStruct.scanCode, lpKeyState, pwszBuff, 8, 0, hkl);
fprintf(fdebug, "vkCode: %d\n", (int)kbdStruct.vkCode);
fprintf(fdebug, "ret: %d\n", (int)ret);
fprintf(fdebug, "lastIsDead: %d\n", (int)lastIsDead);
fprintf(fdebug, "lastIsMod: %d\n", (int)lastIsMod);
fprintf(fdebug, "lastVKCode: %d\n", (int)lastVKCode);
if (ret == -1) {
isDead = TRUE;
ClearKeyboardBuffer(kbdStruct.vkCode, kbdStruct.scanCode, hkl);
}
else if (ret == 0) {
}
else {
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
}
if (lastVKCode != 0 && lastIsDead == TRUE) {
ToUnicodeEx(lastVKCode, lastScanCode, lastKeyState, pwszBuff, 4, 0, hkl);
memcpy(&key, &pwszBuff, sizeof(pwszBuff));
WideCharToMultiByte(CP_UTF8, 0, key, -1, str, sizeof(str), NULL, NULL);
fprintf(fdebug, "str: %s\n", str);
lastVKCode = 0;
}
fprintf(fdebug, "%s", "---------------------------------------------------\n");
fprintf(foutput, "LSHIFT: %d\n", (int)lpKeyState[160]);
fprintf(foutput, "RSHIFT: %d\n", (int)lpKeyState[161]);
fprintf(foutput, "%s", "---------------------------------------------------\n\n");
lastVKCode = kbdStruct.vkCode;
lastScanCode = kbdStruct.scanCode;
lastIsDead = isDead;
fclose(fdebug);
fclose(foutput);
}
Here is updated version of hookcallback thanks for Ton Plooij. But still, I have the same problem.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
LRESULT ret = CallNextHookEx(_hook, nCode, wParam, lParam);
if (nCode >= 0)
{
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
{
hookStruct = *((KBDLLHOOKSTRUCT*)lParam);
proc(hookStruct);
}
}
return ret;
}
AttachThreadInput(thisProgramThreadId, currentWindowThreadID, FALSE);
This does not do what you hope it does. Sometimes. It is a valiant and necessary effort to get the proper values when you call GetKeyboardState(). Took me a while to find the failure mode, it wasn't obvious at all and I could not get the code to fail the same way. It works just fine when a GUI process is in the foreground, try it with Notepad or VS for example.
But not when it is a console mode process.
Explaining that is a bit convoluted, it is actually GetWindowThreadProcessId() that returns misleading information. It tries too hard to keep up the illusion that it is the console process that owns the console window. It doesn't, it is actually the associated conhost.exe process that owns it. It was csrss.exe on old Windows versions, conhost.exe was added in Windows 7 to solve the drag+drop issues caused by UIPI (aka UAC).
But without any decent way to discover the specific conhost.exe process that owns the window, let alone the thread id. The subject of this Q+A. Pretty doubtful it is going to help you.
Only decent advice is the well-known unpleasant one: if you need to reliably translate keystrokes then you need to use a WH_KEYBOARD hook instead of WH_KEYBOARD_LL. So GetKeyboardState() is always accurate, the hook callback runs in-process.
A LowLevelKeyboardProc receives WM_KEYUP and WM_KEYDOWN messages in its wParam. You could simply keep track of pressed modifier keys yourself, in this case to detect shift down and up. Store the key state information in a static variable and use this to test if shift is pressed while processing other keys instead of using GetKeyState.
You can try GetAsyncKeyState().
This function in my keyboard hook module work perfectly.
https://msdn.microsoft.com/en-us/library/windows/desktop/ms646293(v=vs.85).aspx
It seems that this function can catch hardware interrupt when you press keys.
And your GetKeyboardState has something to do with the Windows Registry.
It seems to have something to do with belows:
“HKEY_USERS\DEFAULT\ControlPanel\Keyboard”,Modify “KeyboardDelay” value to 0(default 1)
And change “KeyboardSpeed” value to 48(dafault 31).
According to Hans Passant's answer I searched for how can I get correct value from GetWindowThreadProcessId() and succeeded with instead of getting hWnd and windowThreadID every time in hook callback, I get these values to global variable just after program start and used variables in hook callback.

Convert a virtual-key code to a unicode character - WinApi C++

I am trying to convert a virtual-key code to a unicode character. The virtual-key codes are received from a low level keyboard hook.
LRESULT __stdcall hook_callback(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0 && wParam == WM_KEYDOWN)
{
const auto kbd_hook = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
BYTE state[256];
GetKeyboardState(state);
WCHAR key_buffer[2];
ToUnicode(kbd_hook->vkCode, kbd_hook->scanCode, state, key_buffer, 2, 0);
// handle key_buffer...
}
return CallNextHookEx(hook, nCode, wParam, lParam);
}
This works fine except for the fact that Shift and Caps Lock are not taken into account. Pressing Shift + 1 will result in 1, instead of the expected ! (assuming the locale is US). However, if I fill the state buffer by individually getting each key, it works as expected:
BYTE state[256];
for (SHORT i = 0; i < 256; ++i) {
const SHORT key_state = GetKeyState(i);
// Right shifts the high order bit by 8 to avoid a narrowing
// conversion from SHORT to BYTE.
state[i] = (key_state >> 8) | (key_state & 1);
}
If I fill the state buffer like so, pressing Shift + 1 will result in ! as expected.
Why does GetKeyState() work but GetKeyboardState() doesn't?