WinAPI - show key pressed - c++

I'm trying to learn WinAPI programming but now I got stuck with this problem - I want to get pressed key and show it. I have this piece of code
LRESULT CALLBACK WndProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam){
switch(Msg){
case WM_CREATE:
break;
case WM_CHAR:
char ascii_code = wParam;
unsigned int key_state = lParam;
SetWindowText(hwndStatic, TEXT("You pressed key "+ascii_code));
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd, Msg, wParam, lParam);
}
but the output is weird... It shows random messages(different for each key). What am I doing wrong?
I tried to debug it (step by step) and the ascii_code contains the pressed key but the TEXT() doesn't show it.

You can't add characters together like this:
"You pressed key "+ascii_code;
This will take the address of "You pressed key ", e.g. 1000 and add the ascii code value to it, e.g. 95.
The function will try to print the string at memory address 1095. It will print all the memory until it hits a null character (zero). This could be anything.
You need to either use C functions to build your string, or, as this is tagged C++ use std::string.
std::string message = "You pressed key ";
message += ascii_code;
SetWindowText(hwndStatic, TEXT(message.c_str()))

"You pressed key "+ascii_code
You cannot concatenate strings like that. The real type of "foo bar" is const char[8] - a raw C-like array of characters. When you apply + on it, it decays to a pointer to its first element and the operation is carried on the pointer. This means you end up printing some random data based on where this pointer ends up pointing in the end.
If you want to concatenate a character to a string, you have to use more intelligent string representation, such as std::string:
(std::string("you pressed key ") + ascii_code).c_str();

Related

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;

Expression must have a class type VC++ error?

I am trying to get the program to say what key the user has pressed using Windows hooks. So far I have been able to get the program to say some kinda message when they press a key but rn im trying to get it say what key they pressed but when I try to access the structure that has that data i get the error: "Expression must have a class type" and I have no idea how to fix it. I tried doing: struct -> vkCode but then I get the error: "expression must have pointer type" So i am at a loss as what to do, here is my code.
LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM keyState, LPARAM keyInfo) {//The function that is called when a key is pressed
LRESULT reValue = 0;//Initialize the return value
DWORD keyCode = keyInfo.vkCode;
if (keyState == WM_KEYDOWN) {
MessageBox(hWnd, L"A key was pressed", L"Message", MB_OK);//Put this in message box if the key is down
}
if (nCode < 0) {
reValue = CallNextHookEx(keyboardHook, nCode, keyState, keyInfo);
}
return reValue;
};
here is the line where the error is
DWORD keyCode = keyInfo.vkCode;

global low level keyboard hook being called when SendInput is made. how to prevent it?

I have a win 32 application written in c++ which sets the low level keyboard hook. now i want to sendInput to any app like word / notepad. how do i do this?
i have already done enough of using findwindow / sendmessage. for all these, i need to know edit controls. finding the edit control is very difficult.
since SendInput works for any windows application, i want to use it. the problem is i get a call to my callback function with the pressed key.
for e.g i pressed A and i want to send U+0BAF unicode character to the active applciation windows. in this case, assume it is notepad.
the problem is i get two characters U+0BAF and A in the notepad.
A is being sent because i am calling CallNextHookEx( NULL, nCode, wParam, lParam);
if i return 1 after sendInput, then nothing is sent to notepad.
any suggestion?
If I understood your problem correctly, you should ignore "injected" key events in your hook procedure, like this:
LRESULT CALLBACK
hook_proc( int code, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT* kbd = (KBDLLHOOKSTRUCT*)lParam;
// Ignore injected events
if (code < 0 || (kbd->flags & LLKHF_INJECTED)) {
return CallNextHookEx(kbdhook, code, wParam, lParam);
}
...
Update: additionally, you have to eat characters and notify some other routine for a character press through Windows messages.
Example:
...
// Pseudocode
if (kbd->vkCode is character) {
if (WM_KEYDOWN == wParam) {
PostMessage(mainwnd, WM_MY_KEYDOWN, kbd->vkCode, 0);
return 1; // eat the char, ie 'a'
}
}
return CallNextHookEx(kbdhook, code, wParam, lParam);
And, in some other module, you handle WM_MY_KEYDOWN:
ie, #define WM_MY_KEYDOWN (WM_USER + 1)
and call the appropriate routine that will generate new key events.

Switch statement use

Should i use this form of switch statement:
switch(msg)
{
case WM_LBUTTONDOWN:
{
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, (LPWCH)szFileName, MAX_PATH);
MessageBox(hwnd, (LPCWSTR)szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
}
break;
case WM_CLOSE:
DestroyWindow(hwnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
or make a function for the first case constant ?
There's nothing wrong with how you have it, but it's probably cleaner code to call a function so you can keep your functions a reasonable size.
Also, take a look at message crackers
What you going to do when will hadle 20 or 50 window messages?
Maybe it right time for create map - events on functions ( fuctors ) and call them?
Or start to use rule - one message = one function call.
char szFileName[MAX_PATH];
HINSTANCE hInstance = GetModuleHandle(NULL);
GetModuleFileName(hInstance, (LPWCH)szFileName, MAX_PATH);
MessageBox(hwnd, (LPCWSTR)szFileName, L"This program is:", MB_OK | MB_ICONINFORMATION);
Could you explain this strange trick with convetation (LPCWSTR)szFileName. Why you don't use array wchar_t instead casting? - you will have big problem with long paths ( path_length > MAX_PATH / sizeof( wchar_t ) )
One reccomendation - avoid to use casts in general and C-style casts in particulary.
If you are asking if you should turn the code in the first case into a function, then yes, definitely.
Well, it would depend on how many other cases you would have.
Something as small as that, I would say it is not worth it to make it a function, but if your switch statement contains more cases, it will just get ugly, especially if a lot of the cases has multiple lines like that. Putting it into a function would clean it up and make your code look nicer.
One of the most important things I'd say would be consistency. If you create a function for LBUTTONDOWN then create a function for everything. This way there is a predictable pattern for where to find stuff if it breaks.
Related to the topic at hand:
I personally find an if / else if pattern to work better, as it eliminates the problem of a forgotten break:
if (msg == WM_LBUTTONDOWN) {
// your code here
return 0;
} else if (msg == WM_DESTROY) {
PostQuitMessage(0);
return;
} else if (msg == WM_KEYDOWN) {
if (wp == VK_F1) {
DoSomething();
return;
}
}
return DefWindowProc(hWnd, msg, wp, lp);
It's really up to you, in the end.
I would probably declare a map and use functors for every message:
typedef std::map<UINT, boost::function<int (HWND, WPARAM, LPARAM) > > messageFuncs_t;
messageFuncs_t messageFuncs;
Then, when the window class is created, just add a new function for each message:
messageFuncs[WM_LBUTTONDOWN] = &onMouseDownEvent;
... And then implement the message loop thus:
messageFuncs_t::iterator fun = messageFuncs.find(msg);
if(fun != messageFuncs.end())
return (*fun)(hWnd, wparam, lparam);
else
return DefWindowProc(hWnd, msg, wp, lp);
... Or whatever works. Then it's easy to add new messages, and the work for each is delegated to a function. Clean, concise, and makes sense.
You are missing a break on the first case. Other than that, I would definitely put that code on a separate function.
It's fine, but I generally don't like mixing styles and indentations. If I needed to bracket one case I'd probably bracket them all and keep the indentation consistent.
Also bb is right, you should use wchar_t array instead of char in that case.
I'm writing fairly many Win32 message crackers such as these switches.
My rule of thumb is: Wiring up the behavior goes into the switch, behavior into a separate function. That usually means the switch contains the decision whether this command should be handled (e.g. testing for sender ID), and "prettyfying" the parameters.
So in that particular case, a separate function.
The original motivation is that I often end up triggering the behavior in other circumstances (e.g. "when no file name has been specified and the dialog is called with the moon parameter set to full, show the SaveAs dialog immediately").

Keyboard Hook... not getting Lower or Upper case characters

The function below is logging the "0", "z" and the "1" ok... but its not capturing the "Z" (shift-z)... any help would be appreciated...
__declspec(dllexport)
LRESULT CALLBACK HookProc (UINT nCode, WPARAM wParam, LPARAM lParam)
{
if ((nCode == HC_ACTION) && (wParam == WM_KEYUP))
{
// This Struct gets infos on typed key
KBDLLHOOKSTRUCT hookstruct = *((KBDLLHOOKSTRUCT*)lParam);
// Bytes written counter for WriteFile()
DWORD Counter;
wchar_t Logger[1];
switch (hookstruct.vkCode)
{
case 060: Logger[0] = L'0'; break;
case 061: Logger[0] = L'1'; break;
case 90: Logger[0] = L'z'; break;
case 116: Logger[0] = L'Z'; break;
}
// Opening of a logfile. Creating it if it does not exists
HANDLE hFile = CreateFile(L"C:\\logfile.txt", GENERIC_WRITE,
FILE_SHARE_READ, NULL,OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
// put the file pointer to the end
SetFilePointer(hFile,NULL,NULL,FILE_END);
// Write the hFile typed in logfile
WriteFile(hFile,&Logger,sizeof(Logger),&Counter,NULL);
//WriteFile(hFile,&hookstruct.vkCode,sizeof(hookstruct.vkCode),&Counter,NULL);
// Close the file
CloseHandle(hFile);
}
}
The keyboard does not send characters. It sends keys. Whether you're typing z or Z, you're still pressing the same key, and that key has the same VK code both times.
You should also get notification when the Shift key is pressed or released. You can use those notifications to translate the keystrokes into characters. The caps-lock state will also be relevant for that. You may also be concerned about dead keys.
You can check whether the Shift key is pressed. GetAsyncKeyState will tell you the state of the key right now, and GetKeyState will tell you the state of the key as of the last message removed from the message queue.
There's no virtual key code for Z.
Try something like this:
case 90:
if(GetKeyState(VK_LSHIFT|VK_RSHIFT)
Logger[0] = L'Z'; break;
else
Logger[0] = L'z'; break;