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);
}
Related
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)
I am trying to make a program that sits in the background that can ignore mouse clicks - outside of the program.
How do I tell Windows this through c++?
I already made the program recognize the mouse click. Just not how to ignore it.
The reason I need to do this is because my mouse has a flaw where it accidentally double-clicks (or more) when I only click one time.
So basically, when the program register that I click with the mouse, it will let the first click through, but then disable that button (ignoring every following clicks) for ~200 milliseconds.
If possible, I would like to avoid using any external libraries. Only the standard ones that comes with Visual Studio.
Thank you very much for reading!
You can use a low-level mouse hook:
// Variable to store the hook handle
HHOOK miHook;
// This is the hook procedure
LRESULT CALLBACK LowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if(nCode == HC_ACTION) {
MSLLHOOKSTRUCT &msll = *(reinterpret_cast<MSLLHOOKSTRUCT*>(lParam)); // In there is more context if you need it
if(wParam == WM_LBUTTONDOWN) {
// Do your logic here
if(letsIgnoreThisClick) {
return -1; // This will make the click be ignored
}
}
}
return CallNextHookEx(miHook, nCode, wParam, lParam); // Important! Otherwise other mouse hooks may misbehave
}
// This is how you install the hook
miHook = SetWindowsHookEx(WH_MOUSE_LL, reinterpret_cast<HOOKPROC>(&LowLevelMouseProc), hInstance, 0);
// And this is how you would remove the hook again
UnhookWindowsHookEx(miHook);
This code example can't be used as-is of course, but has to be adjusted to your needs and the individual parts have to be put in the right locations in your code.
Please also read the remarks section for SetWindowsHookEx. You are probably going to need to create a DLL where your function is located (you can load it from your main code). The hInstance in my example has to be the instance handle of the module which contains the hook procedure. Also you need to pump messages in order for your hook to work correctly!
I noticed that RichEdit does not send messages to parent window when CTRL key is pressed when the control is in focus. When parent window is active then all goes ok. But when cursor is in RichEdit only mouse 0x20 WM_SETCURSOR messages go ok. When pressing a key as in typing without control keys 0x111 WM_COMMAND is send, and when I try to press CTRL and during this any other key like 'S' for implementing save-as function, nothing is sent. Is there a way to create callback to RichEdit or in other way capture CTRL+S ?
Escape also doesn't send a message to parent window.
Found how to set a callback to richedit.
DefEditProc = (WNDPROC)SetWindowLong(richeditWindow, GWL_WNDPROC, (long)&richEdit.EditKeyProc);
and before in code:
LRESULT EditKeyProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if(uMsg == WM_KEYDOWN) {
if(wParam == 'S' && GetAsyncKeyState(VK_CONTROL));
return 0;
}
return CallWindowProc(DefEditProc, hwnd, uMsg, wParam, lParam);
}
I think that it's not the best way to go if you just want to catch some particular key shortcuts to make defined actions like Ctrl+S for save.
I would say that the right way to go is to use accelerator tables. It has two advantages :
If the accelerator table is in resources, you can easily change or remove the shortcut without actually digging into the C/C++ code. There are also facilities for multilingual software, and you can also quite easily open/save the accelerator table in a file unstead of using resources if you want the user to customize the shortcuts, etc.
The shortcut is not only triggered when you are in that particular richedit. I think it's a good thing for users. Imagine that you have another control in the same window. With your code, Ctrl+S wouldn't work, unless you register your callback on all control windows. I'm an user, I'm currently on the other control, and I press Ctrl+S. Oh no, my document hasn't been saved ! frustrating and buggy-looking...
IF you are also using menus, there is no that much code to add...
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
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;