How to handle keyboard events in a winapi standard dialog? - c++

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;

Related

Winapi - Alternatives to WM_CLOSE

I know with Windows notification message, WM_CLOSE refers to closing the window via "X" button on the top right hand corner of the window.
Does anyone know the notification message for closing with File->Exit?
The reason I asked is because I'm trying to implement JNI native code to gracefully close window when user initiated system shutdown. refer to my earlier post (Winapi - SetWindowLongPtr in ShutdownBlockReasonCreate / Destroy implementation of JNI native code) for background.
When clicking on 'X' to close, confirmation dialog box comes up which prevents shutdown reason message from disappearing (when I expect it to disappear after a while). I know File->Exit from menu bar doesn't ask for confirmation, but how do I implement this using windows notification message?
After some digging around the only suggestions I found is to use DestroyWindow. So I tried closing the window using DestroyWindow() function, but it only "Destroys" the window, rather than ending the whole application. Here's my switch statement in my WndProc CallBack function:
switch (message) {
case WM_QUERYENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_ENDSESSION:
PostMessage(hWnd, WM_CLOSE, 0, 0);
return 0;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
Any help would be much appreciated!
Cheers
I know with Windows notification message, WM_CLOSE refers to closing the window via "X" button on the top right hand corner of the window.
Actually, when the window's standard "X" button is clicked (or the standard "Close" item on the window's top-left corner menu is selected if enabled, or the window receives an ALT+F4 keystroke), a WM_SYSCOMMAND message is issued to the window with the wParam containing the SC_CLOSE flag. If that message is passed to DefWindowProc() (the default behavior), it then issues a WM_CLOSE message to the window.
See Closing the Window.
It is possible that other conditions can also cause a WM_CLOSE message to be issued.
Does anyone know the notification message for closing with File->Exit?
What happens when that menu item is selected is defined by the application, not the OS. The application can do whatever it wants, including destroying the window immediately if it wants to.
However, that being said, if the menu is a standard Win32 menu, then the window will receive a WM_COMMAND message containing the ID of the menu item that was selected, at least.
The reason I asked is because I'm trying to implement JNI native code to gracefully close window when user initiated system shutdown.
By default, you don't need to do anything for that. The OS automatically closes all open windows during system shutdown. Rather than closing your window manually, you should instead react to your window being closed, if you need to clean up any resources.
When clicking on 'X' to close, confirmation dialog box comes up which prevents shutdown reason message from disappearing (when I expect it to disappear after a while).
Then the application is not handling system shutdown correctly.
Most applications present such a confirmation box in response to receiving the WM_CLOSE message. If the confirmation is aborted, the application discards the message and moves on. However, applications shouldn't prompt the user for confirmation during system shutdown. But not all applications follow that rule.
I know File->Exit from menu bar doesn't ask for confirmation
Again, that is for the application to decide, not the OS.
how do I implement this using windows notification message? After some digging around the only suggestions I found is to use DestroyWindow.
Correct. Or, you can alternatively post a WM_QUIT message to the message queue instead. See the PostQuitMessage() function.
So I tried closing the window using DestroyWindow() function, but it only "Destroys" the window, rather than ending the whole application.
It is the application's responsibility to terminate itself, usually by exiting its message loop when its main window has been destroyed.
Here's my switch statement in my WndProc CallBack function:
There is no need to post WM_CLOSE in response to WM_QUERYENDSESSION or WM_ENDSESSION. Let the OS handle that for you.
If you don't want the confirmation to appear during system shutdown, change your code to something more like this:
bool shuttingDown = false;
LRESULT CALLBACK AppWndProc(
_In_ HWND hWnd,
_In_ UINT message,
_In_ WPARAM wParam,
_In_ LPARAM lParam,
_In_ UINT_PTR uIdSubclass,
_In_ DWORD_PTR dwRefData
) {
switch (message) {
case WM_QUERYENDSESSION:
shuttingDown = true;
break;
case WM_ENDSESSION:
if (wParam == FALSE)
shuttingDown = false;
break;
case WM_CLOSE:
if (shuttingDown) {
DestroyWindow(hWnd);
// or:
// PostQuitMessage(0);
return 0;
}
break;
case WM_NCDESTROY:
RemoveWindowSubclass(hWnd, AppWndProc, uIdSubclass);
break;
}
return DefSubclassProc(hWnd, message, wParam, lParam);
}
There's no specific message to handle your File>Exit. You must handle it as any other menu item:
Define an identifier for your menu item. Choose anything you want, it has no particular meaning for windows.
When constructing your menu, specifiy this identifier in AppendMenu/InsertMenu/etc. or in your resource file
In your window procedure, intercept the WM_COMMAND message. If LOWORD(wParam) corresponds to the identifier, this means that the menu item has been activated
A typical way of handling an exit command is to send a WM_CLOSE message, as you are already doing in your example code.
So you will avoid code duplication and be sure that the behavior will be the same regardless of how the user choose to exit your application (via menu, click on the "x", or Alt+F4)
In the handing of WM_CLOSE, you can choose to show a message box, destroy the window, post a quit message, or whatever else you want. BY default the DefWindowProc calls DestroyWindow, which in turn sends the WM_DESTROY message.
Note that WM_CLOSE is also triggered when selecting the "Close" item of the system menu (Alt+Space or click on the window icon on the left next to the window title)

Uninstalling keyboard hook when the user leaves the application

I am trying to detect when a user alt tabs out of my window. I have tried several messages (WM_ACTIVATE, WM_KILLFOCUS, WM_ACTIVATEAPP, WM_NCACTIVATE, WM_CANCELMODE, and WM_SYSCOMMAND checking for SC_MINIMIZE). But the same problem still occurs. The following happens.
My application is in focus, and I hold down alt and press tab.
The next window is brought forth.
I keep holding down alt and then press tab again, but this time, only tab is recognized and so I end up tabbing in the new window rather than alt tabbing again as is the usual behavior.
I am using a low level keyboard hook, and if I uninstall that this alt tabbing behavior described above works perfectly. I basically want to uninstall the keyboard hook as soon as the user leaves my window in this fashion. As soon as I release alt tab while in another window, my window receives several of the messages I look for and the hook is uninstalled. But when you hold the keys in this manner, it does not work as expected while the hook is installed.
why do you need to remove the keyboard hook? The SetWindowsHook is local to your application and not affect the other apps, therefore it already does nothing if your app doesn't have the focus.
Edit
make sure you call the next hook in your callback with CallNextHookEx to not screw up screen readers
I used the following code and it seems to be catching the focus changes, and I am not getting any problem with regard to holding down ALT or TAB in various combinations. But I didn't thoroughly test it yet.
EDIT: I read your post again and see that your problem is probably an interaction between the two different hooks. So I am also hooking the keyboard in my app, but I am using an Import Address Table hook of DispatchMessage. My hooks don't interact the way yours do, but my solution may not be appropriate for you.
bool AddHookToKeyboardFocusChanges()
{
HHOOK hhookFocusChange = NULL;
hhookFocusChange = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWindowProcHook, NULL, GetCurrentThreadId()); // the last parameter makes it a local, not global hook
if(hhookFocusChange == NULL)
return false;
return true;
}
///////////////////////////////////////////////////////////////////////////////
// This is the routine that we register to be called on every call to a
// WindowProc in our application; we use it to catch WM_SETFOCUS and
// WM_KILLFOCUS messages that indicate gaining or losing keyboard input focus.
// Unlike keyboard, mouse, paint, and timer messages, the focus messages are not
// posted to the message queue. Instead they are sent directly to WindowProc.
// We must hook them here.
//
LRESULT WINAPI CallWindowProcHook(int nCode, WPARAM wParam, LPARAM lParam)
{
UINT message = ((CWPSTRUCT*)lParam)->message;
switch(message)
{
case WM_ACTIVATE:
OutputDebugString(L"Window activated.\n");
break;
case WM_SETFOCUS:
OutputDebugString(L"Window focused.\n");
break;
case WM_KILLFOCUS:
OutputDebugString(L"Window focus lost.\n");
break;
default:
break;
}
// CallNextHookEx calls the next hook in the chain.
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

Viewing Win32 messages

Hello everyone I am new to windows32 programming and I have a couple of questions-:
When I use the following code in a program it works fine -:
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
But when I replace null of GetMessage to hwnd(the handle of the window just created) the doesn't seem to close it still remains running in the background. Why does this happen when I replace NULL with hwnd means I am receiving messages for only one window then why doesn't it work????
while(GetMessage(&msg,hwnd,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
By the way the windows function is-:
LRESULT CALLBACK WinProc(HWND hWnd, UINT message,
WPARAM wparam, LPARAM lparam){
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wparam, lparam);
}
return 0;
}
Secondly-:
Is there any way I can see all the messages sent to any particular window????
Thirdly-:
What is the reason behind writing __stdcall(WINAPI) when compiling my windows programs ????
A quick reply would be appreciated.Thank You.
GetMessage returns 0 (making the loop end) only when it receives a WM_QUIT, but a WM_QUIT is not associated to any particular window, so it is never received if you have a GetMessage that asks only messages for a certain hWnd.
If it's a window of yours, you already see them inside their window procedure; if you want to filter them before dispatching them to their window procedure, you can check the msg structure that is populated by GetMessage before calling DispatchMessage.
The whole Windows API uses the stdcall calling convention (I think because it is slightly faster/produces less boilerplate code than the usual cdecl), so also your callbacks must follow that calling convention. Notice that you must use WINAPI (i.e. stdcall) only on functions that are called by Windows API functions, for the other ones you are free to use whatever calling convention you like best.
PostQuitMessage generates WM_QUIT which is processed by the message queue, but not associated with a particular window. By filtering only hwnd messages in your call to GetMessage, you don't process WM_QUIT.
Regarding seeing all messages being sent to a window / thread / process, see https://stackoverflow.com/questions/4038730/i-am-looking-for-a-windows-spy-application
Finally, regarding __stdcall, see What does "WINAPI" in main function mean?

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

not properly closing from taskbar closing event

if i close my application via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself, the application closes correctly, and everything works just as expected.
but recently i realized, on windows7, when i close the app by right klicking on the icon in the taskbar, and clicking "Close Window", the window closes, but my app is still running. when debugging, i don't get into either of the WM_QUIT/DESTROY/CLOSE events.
is there some special behavior when closing a window via taskbar? how can i detect that?
You should get WM_CLOSE. Maybe you're getting it on a different window that the one you're expecting? Although that shouldn't be able to happen unless you have multiple top-level windows.
via Alt-F4, or the corner "X" button, or by posting destroywindow(hwnd) myself
You can't post DestroyWindow(). Ensure that the window procedure of your main window resembles this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
// Other cases
//...
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
The PostQuitMessage() function call ensures that your message loop exits, GetMessage() returns FALSE when it receives the WM_QUIT message. This makes your main window behave like the main window, closing it ends the process. You may have other top-level windows that don't, they shouldn't have this WM_DESTROY message handler. DestroyWindow() is already called automatically by DefWindowProc() when it processes the WM_CLOSE message.