Convert a virtual-key code to a unicode character - WinApi C++ - 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?

Related

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).

Reading bits from the bin value

What is the order one has to read the bits from the bin value? Having for e.g. this official MS doc site regarding the lParam of the WM_CHAR message, they explain what bits have what meaning. Taking the bits 16-23 for the scan code value should I read the bits from right to left or vice versa?
The page you linked to uses LSB 0 bit numbering so you can extract bits 16-23 with
lParam & 0b00000000111111110000000000000000U
// | | | |
// bit 31 23 16 0
// MSB LSB
Note: The 0b prefix for binary numbers requires C++14. In C it's only available as an extension in some implementations.
You may also want to shift down the result with
(lParam & 0b00000000111111110000000000000000U) >> 16U
or simpler
(lParam >> 16U) & 0b11111111U // or (lParam >> 16U) & 0xFFU
two ways:
UINT bitsxtractBits(UINT val, int startBit, int nbits)
{
UINT mask = ((UINT)1 << nbits) - 1;
return (val & mask) >> startBit;
}
//note it will not work if you want to extract all bits (in this case 32).
//but in this case you do not need to extract them :)
and the usage to extract your bits:
bitsxtractBits(message, 16, 8)
or
union WM_CHAR_message
{
struct
{
UINT repatCount : 16;
UINT scanCode : 8;
UINT : 4;
UINT contextCode : 1;
UINT previousState : 1;
UINT transitionState : 1;
};
UINT raw;
};
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
union WM_CHAR_message msgu;
//C++ safe
memcpy(&msgu, &message, sizeof(msgu)); // will be optimized to the store instruction only
switch (message)
{
// ...
case WM_CHAR:
switch(msgu.scanCode)
{
//....
}
OnKeyPress(wParam);
break;
default:
return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}

Receiving wParam from message received from DLL

I'm working on a program that needs to work with an imported DLL. I can load the DLL, and execute functions within it fine.
The problem comes up when I need to extract data it has sent with Send/PostMessage.
The documentation says:
MSG_PSKCHARRDY
Numeric Value is WM_USER+1001 or 0x400+0x3E9 or 0x7E9 or 2025.
This message is sent from the DLL to the Window whose handle is passed when the fnStartSoundCard is called. It is sent whenever there is an ASCII character available from the receiver or if in the Transmit mode, when a character has been sent out the soundcard.
The following parameters are sent along with this message:
wParam = The ASCII character(0 to 255)
lParam = -1 if is a transmitted character, or the Receive channel number(0-49) that is sending the message.
I've added this as a case under my WindProc as case: WM_USER + 1001: and any code underneath is executed when the fnStartSoundCard function is called, so I know it's receiving the message.
But when I try to print the wParam as a char string, I always get an exception thrown at the end of my DispatchMessage(&msg) function here:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
Exception thrown at 0x76524463 (ucrtbase.dll) in PSK31.exe:
0xC0000005: Access violation reading location 0x0000004D.
My message handler looks like this:
case WM_USER + 1001:
if (hWnd == GetActiveWindow()) {
char textChar;
SOMETHING = (char*)wParam;
printf(SOMETHING);
Sleep(1000);
}
break;
How can I get the char extracted from the message?
There are two mistakes in your code.
The documentation you quote clearly says that the MSG_DATARDY message is defined as WM_USER+1000 but you are using WM_USER+1001 instead.
The documentation you quote does not say anything about the message's wParam and lParam values being pointers to strings, but you are trying to treat the wParam as if it were, and it is clearly not. Your code is crashing trying to read from address 0x0000004D, which is a memory address reserved by the OS, so wParam can't be a pointer to data in application-accessible memory. 0x4D (77) is a small number, certainly small enough to look like the actual frequency number, so the numeric values of wParam and lParam should be used as-is, not casted to string pointers.
Try this instead:
#define MSG_DATARDY (WM_USER + 1000)
case MSG_DATARDY:
if (hWnd == GetActiveWindow()) {
int freq = (int) wParam;
int strength = (int) lParam;
printf("RX frequency: %d Hz, signal strength: %d", freq, strength);
Sleep(1000);
}
break;
UPDATE: in leau of the updated documentation you quoted, you are still making the same mistake regarding the wParam. It is NOT a pointer to an ASCII character. It is the actual character instead, so use the value as-is:
#define MSG_PSKCHARRDY (WM_USER + 1001)
case MSG_PSKCHARRDY:
if (hWnd == GetActiveWindow()) {
char textChar = (char) wParam;
int channel = (int) lParam;
if (channel == - 1) {
printf("TX character: %c", textChar);
}
else {
printf("RX channel: %d, character: %c, ", channel, textChar);
}
Sleep(1000);
}
break;

Keyboard hook not restricting key press correctly

I have a dll that is injected into a specific process with the intention of restricting certain key presses from being sent to the aforementioned process..
This seems to work, with one major flaw.. When the keys are pressed that I intend to restrict, they are still being passed to the process.
I added the line to raise a message box whenever the hook should be returning the value of 1 (restricting the keys from progressing further own the chain), and the message box is raised, and even stranger, the key is stopped from progressing, but whenever I remove the messagebox code the restriction is completely ignored!!
Could anyone highlight what I am doing wrong? Or in the unlikely scenario that it is not my own wrongdoing, but some quirk that I am not aware of, please do let me know.
Many thanks.
Here is my hook proc code, which I expect is where the issue lies.
extern "C" __declspec(dllexport) int KeyboardHook(INT nCode, WPARAM wParam, LPARAM lParam) {
//-- Return unless valid nCode
if (nCode < 0) return CallNextHookEx(keyhook_handle, nCode, wParam, lParam);
//-- Setup some bools
BOOL alt_down = ((lParam & (1U << 29)) == 1);
BOOL key_last = ((lParam & (1U << 30)) == 0);
BOOL key_down = ((lParam & (1U << 31)) == 0);
BOOL let_pass = TRUE;
//-- Checks for keypresses
if (key_last && key_down) {
if (wParam == VK_F12) let_pass = FALSE;
if ((wParam == VK_RETURN) && alt_down) let_pass = FALSE;
}
//-- If not let_pass then return 1 to restrict key
if (!let_pass) {
//MessageBox(NULL, L"Key Stopped", L"Info:", MB_OK | MB_ICONERROR);
return 1;
}
//-- Call the next hook in the chain
return CallNextHookEx(keyhook_handle, nCode, wParam, lParam);
}

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

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 ;)