Using WM_KEYDOWN and wParam - c++

Noob question here, but I can't find any other threads that answer it. All I want to know is how to use the WM_KEYDOWN message, and then proceed to use its wParam parameter to check which key has been pressed. Like a lot of people, I'm using this to try and get windows to stop with the key-repeat delay.
I can get my program to respond to WM_KEYDOWN with
if (WM_KEYDOWN)
//do something
But I can't work out how to access the wParam parameter. The code
if (WM_KEYDOWN)
if (wParam == 'A')
//do something
doesn't seem to work.
This kind of code is way out of my depth, but people are saying it's the easiest way to get around the key-repeat delay. I don't really understand what a message is or how it can have a parameter.

As was pointed out in the comments you probably meant to write
if( message == WM_KEYDOWN )
since
if( WM_KEYDOWN )
will always be true since it's a constant.
As for the wparam check if I recall correctly you need to compare it to a lowercase character not an uppercase one.

This is a very old question as there were some changes to MSDN, however I will try to cover the multiple scenarios.
Scenario A
You're capturing a Message Callback through a Windows Procedure without using SetwindowsHookEx. Example: You're capturing messages inside WNDPROC.
First you need to detect the message type as in (msg == WM_KEYDOWN). msg contains the event that triggered the call. This way you can utilize wParam where it will be the Virtual Key code.
Scenario B
You're capturing a Message Callback through Low Level Keyboard Procedure (WH_KEYBOARD_LL). In this scenario wParam acts as msg from Scenario A, and lParam contains additional info. You'll need to map lParam into a KBDLLHOOKSTRUCT and extract the Virtual Key code from it.
KBDLLHOOKSTRUCT kbStruct = *((KBDLLHOOKSTRUCT*)lParam);
You can now access the Virtual Key code by using kbStruct.vkCode.
Scenario C
You're capturing a Message Callback through Keyboard Procedure (WH_KEYBOARD). In this scenario wParam contains your Virtual Key code, and lParam contains the flags. Refer to MSDN for more info the flags. In order to detect Key Down/Up and/or Holding the button, you'll have to rely on the flags on bits 31 and 30 (lParam>>31 and lParam&0x40000000).

Related

WM_DEVICECHANGE comes twice when disconnecting/connecting device

I'm listening in my message loop for WM_DEVICECHANGE, and when I remove or thrust my webcam, WM_DEVICECHANGE comes twice, with identical MSG (with same HWND, UINT, WPARAM and LPARAM). How to fix it?
This is to be expected. Although the wParam and lParam should be different to indicate a different stage of the device state change, it would not surprise me to know there are duplicate messages.
If I recall correctly, what we did in our code is that when we received a WM_DEVICECHANGE event is to do any of the following:
Once the first one came in, ignore all subsequent notifications for the next couple of seconds.
Or just use the WM_DEVICECHANGE as a hint and not the truth. When we received such a message, we would re-enumerate the device list with the appropriate API and see if anything changed since the last time we enumerated. If the new list was the same as the original list, then there was nothing to do.

Keyboard hooking alt-tab causing strange behavior?

I want to disallow the user of my application from using alt-tab. I'm trying to solve this by using a low level keyboard hook.
Setting it up works perfectly, the callback procedure is triggered when I press the key combination etc. The weird thing that happens is that I can alt-tab out of the application but then alt-tabbing is disabled, completely. I switch applications with the mouse and try alt-tabbing but nothing happens. I switch back to my application and alt-tab again and it switches the application, but only one step. When out of my application the alt-tab isn't working anymore.
I've tried different scenarios, first I thought it had something to do with the debugger in VS2010 but no, running it with out the debugger gives the same results.
Have I completely misunderstood this hook procedure, is it meant to only catch stuff happening when the application isn't in focus?
osman.hpp :
static HHOOK m_hhook;
static LRESULT CALLBACK lowLevelKeyboardProc( int key, WPARAM wParam, LPARAM lParam );
osman.cpp :
HHOOK OSMan::m_hhook;
/*
* pseudo init code
*/
void OSMan::init()
{
m_hHook = SetWindowsHookEx( WH_KEYBOARD_LL, (HOOKPROC)lowLevelKeyboardProc, 0, 0 );
}
LRESULT CALLBACK OSMan::lowLevelKeyboardProc( int key, WPARAM wParam, LPARAM lParam )
{
KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *) lParam;
switch (key)
{
case HC_ACTION:
{
if (pkbhs->vkCode == VK_TAB && pkbhs->flags & LLKHF_ALTDOWN)
return 1;
}
default:
break;
}
return CallNextHookEx( m_hHook, key, wParam, lParam);
}
edit:
added code.
If you want to disable alt+tab correctly, you should just register the hotkey via RegisterHotKey(0,0,MOD_ALT,VK_TAB); and then handle (well, more ignore) the message that this generates, this allows you to make it application local, not worry about Windows hook chains and allows you to easily enable or disable it on the fly.
Although for a game, the idTech 4 input handling code has a vast array of the input gems.
You are installing a System Wide hook, that is why you have disabled the use of Alt-TAB on the whole system.
You can't use a WH_KEYBOARD_LL you must use a WH_KEYBOARD hook, and make it process specific.
The params of the SetWindowsHookEx will change if you make your hook process specific.
Here is an overview of the params :
dwThreadId [in]
Type: DWORD
The identifier of the thread with which the hook procedure is to be associated.
If this parameter is zero, the hook procedure is associated with all existing threads running in the same desktop as the calling thread.
PS : in reply to comment :
The hook only is installed after the process got one appropriate event. While hooking onto keyboard messages, you will have to send at least one keyboard message before the hook is installed.
Work Around
Maybe you want to work around this issue by using the ShowWindow function ?
Here is the doc : http://www.pinvoke.net/default.aspx/user32.showwindow
cf : http://www.codeproject.com/Articles/4610/Three-Ways-to-Inject-Your-Code-into-Another-Proces
cf http://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
and
http://msdn.microsoft.com/en-us/library/windows/desktop/ms644959(v=vs.85).aspx#wh_keyboardhook

How to handle keyboard events in a winapi standard dialog?

i don't often work with winapi, i'm writing almost .NET code. But at this time I have to use the winapi to make a simple dialog. There i want to handle some keyevents. Therefore i watched for the corresponding callback message WM_KEYDOWN or WM_KEYUP at MSDN and added it to my callback function.
INT_PTR CALLBACK cbfunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
switch(message) {
// ...
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
// ...
}
return 0;
}
But neither WM_KEYUP nor WM_KEYDOWN ever get triggered. Then I stated looking for a solution for this problem. I thought may my dialog eats this messages. So I added:
case WM_GETDLGCODE:
return DLGC_WANTALLKEYS;
With the result that it doesn't help.
Other solutions I've found were the following:
Alternatively using the WM_GETDLGCODE event to handle this keys as suggested on here.
I've found a lot of threads (like this one) talking about a method called PreTranslateMessage. But I don't even have got this class, because I simply create my dialog by using DialogBoxParam
So none of them worked for me. In the moment i have got no idea how to handle it. Something I've noticed, is that on key press a WM_COMMAND message seems to occur.
Regards Nem.
According to this link, certain messages are hard to trap with dialog boxes because Windows processes them internally and they never get to the DialogProc. Here are two of the options I can think of:
Use GetAsyncKeyState on a WM_COMMAND event
Create a custom dialog box, the DialogProc for which will handle WM_KEYDOWN etc. messages.
DialogProc doesn't receive WM_KEY events (and many others too). You can:
Subclass the dialog window (overwrite its WndProc) and process all
messages there, sample
Register hot key for the dialog window's HWND and then receive WM_HOTKEY in DlgProc (but registered key combinations will be system-wide)
Create your own message loop, link
Replace This
case WM_KEYUP:
MMsgBox("up"); // I never get here
return 0;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
return 0;
With This
case WM_KEYUP:
MMsgBox("up"); // I never get here
break;
case WM_KEYDOWN:
MMsgBox("down"); // I never get here
break;

Intercept mouse input

I was wondering if there is a way to intercept and modify mouse input before it gets to windows?
What I'm wanting to do is intercept mouse motion events, apply some custom scaling and acceleration to the values, and then continue passing them along. I'd need something that can do this before the inputs get to the raw input API or DirectInput.
In order to affect all mouse input, including DirectInput, during logon and the SAS screen, etc., you'll need to load a filter driver into the mouse driver stack.
Other people have done it, for example http://www.maf-soft.de/mafmouse/
There should be a moufiltr sample in the Windows DDK which you can use as a starting point. You will most likely want to use a virtual machine for development since errors in a driver on your development machine could be difficult to recover from.
Have you seen this method of intercepting mouse and keyboard input without having to make a filter driver or hook?
http://oblita.com/Interception.html
There is a LowLevelMouseProc hook procedure that you can use to get information on any mouse input entering the system, although I doubt if you can actually change this information (and the docs are silent on this).
If this fails, GetMsgProc is an alternative that lets you intercept all messages posted to any window. Though this hook does let you modify the message, it's probably too late to have any effect on APIs such as DirectInput.
You could try a windows hook - which are functions you set to receive windows messages before they get passed through to the rest of the system - a CBT hook (for computer based training) is what might get you best results.
I don't know Whether this will work with DirectInput or the other new stuff MS has added to break all the old internal consistency. Its easy to set up though, so try it and see.
As far as I know the best way is to hook to windows message loop, In your case you should pass HWND 0 (If I remember correctly this the HWND of the desktop) so all the messages will pass though your function first.
http://msdn.microsoft.com/en-us/library/ms633591%28VS.85%29.aspx
More on hooks : http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx
Use it as follows:
m_nOldWindowProc = ::SetWindowLong(0 /I think.../, GWL_WNDPROC, (LPARAM)(WNDPROC)WindowProcCallback);
and the callback:
LRESULT CALLBACK CStubWindow::WindowProcCallback(HWND hwnd,
UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_WINDOWPOSCHANGING:
((WINDOWPOS*)lParam)->cx = STATUS_BAR_WIDTH;
((WINDOWPOS*)lParam)->flags = SWP_NOOWNERZORDER | SWP_NOMOVE;
break;
default:
break;
}
return ::CallWindowProc(m_nOldWindowProc, hwnd, message, wParam, lParam);
}

PostMessage for cross application messages

I'm trying to send a keystroke to another application. I can successfully find the window handle since using SendMessage worked exactly as intended.
However, when I switched the SendMessage over to PostMessage, the application no longer received the messages.
I did, however, find a workaround by using HWND_BROADCAST as the window handle, and it works fine, but isn't the ideal way to go about it.
What I'm asking is, I have a valid hWnd, how can I send it messages using PostMessage and not SendMessage?
Edit
This is what I'm trying to do.
HWND Target = FindWindow(0, "Window Title Goes Here");
LPARAM lParam = (1 | (57<<16)); // OEM Code and Repeat for WM_KEYDOWN
WPARAM wParam = VK_SPACE;
PostMessage(HWND_BROADCAST, WM_KEYDOWN, wParam, lParam); // Works
PostMessage(Target, WM_KEYDOWN, wParam, lParam); // Doesn't Work
SendMessage(Target, WM_KEYDOWN, wParam, lParam); // Works, but I need Post
The PostMessage function does not work when the message numbers between 0 and WM_USER-1. Use RegisterWindowMessage function to register your own messages.
Sent messages and posted messages take completely different routeres. Target is recieving your posted message, it's just either filtering or dispatching it to another window. It gets to do what ever it wants with it. When you send the messages, it goes directly to the window procedure without filtering, so is most likely that cause of that issue.
I don't know why HWND_BROADCAST is working; my best guess is that a window other than Target is processing the message. Or maybe its even being sent to a different window than Target. (You do realize that HWND_BROADCAST sends the messages to every top level window)
There is a Win32 API function designed to send input, SendInput(), that places the messages on the input queue just like a user keypress. However this doesn't let you specify a window, it sends its input to the active window. To use it you would have to activate and switch focus to Target, which means the user would see that window move to the top (just like you Alt-Tabbed to it). Along that same route VBScript has a SendKeys() function that does the same thing, but is easier to use.
As a final alternative you could use SendMessageCallback() which will give you the behavior of an asynchronous SendMessage which is what I assume you want. (And is different than PostMessage. Posted messages go into the posted message queue, sent messages are delivered directly)
*For the lparam go here http://msdn.microsoft.com/en-us/library/ms646280%28v=vs.85%29.aspx, change the 32 bits (31...3 2 1 0) of lParam. Once you have the binary sentence you want for your paramaters (cRepeat, Scancode etc), convert it to hexadecimal.
try this :
void SendString(HWND h, char *text)
{
int len = strlen(text);
for(int i = 0; i < len; i++)
PostMessage(h, WM_CHAR, text[i], 0);
}
HWND Target = FindWindow(0, "Window Title Goes Here");
LPARAM lParam = //The hexadecimal value matching with the parameters you want* example 0x29A1.
WPARAM wParam = VK_SPACE;
PostMessage(HWND_BROADCAST, WM_KEYDOWN, wParam, lParam);
PostMessage(Target, WM_KEYDOWN, wParam, lParam);
SendString(Target, (char*)"themessageyouwant\n");