SendMessage(WM_SYSCOMMAND) failed when mouse captured - winapi

I'm using the win32sdk, but some messages would never work as expected while mouse was captured by calling SetCapture(), such as:
case WM_LBUTTONDOWN:
SetCapture(hWnd);
SendMessage(hWnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0);
ReleaseCapture();
return 0;
The Window won't be maximized. but why?
Additional,
1. if I use PostMessage() instead, it works.
2. if I use PostMessage() instead and remove the ReleaseCapture(); statement, it doesn't work again.

In general:
PostMessage is asynchronous and you call ReleaseCapture() before WM_SYSCOMMAND is processed. So you have only one question: Why you can't maximize if mouse is captured?
I haven't found any info on this but read here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646262(v=vs.85).aspx
"When the mouse is captured, menu hotkeys and other keyboard accelerators do not work." I suppose WM_SYSCOMMAND is not processed also because of this restriction. May be it was done like this to keep coords consistent.

As norekhov said menu hotkeys don't work when the mouse is captured. When the mouse is captured the the only action a user can take that will result in the WM_SYSCOMMAND message being sent is to use a system menu hotkey.
Note that the WM_SYSCOMMAND message is only meant to be used to notify a window of a user initiated action. When you send it to a window, you're in essence trying to mimic a user's action. In this case you don't need to do this. You can tell the window to maximize itself directly:
ShowWindow(hWnd, SW_SHOWMAXIMIZED);
In this case it won't appear to be a user command, so it won't be ignored because the mouse has been captured.

Related

How to discard some messages for a window?

My goal is to disable some tool-tip-like thing in window of another process. My thoughts are to block WM_MOUSEMOVE if the coordinates of mouse movement is in certain rectangle of the window.
I can use SetWindowsHookEx to receive that messages (WH_CALLWNDPROC and WH_GETMESSAGE), but it doesn't allow to block them. I can return 1 instead of calling CallNextHookEx, but it doesn't prevent WndProc of window to receive the message. However, this approach works for blocking events in MOUSE_LL/KEYBOARD_LL.
SetWindowsHookEx is also not good, because it installs hook to all windows across the system.
How I can prevent window of another process from receiving certain windows messages?
The WH_GETMESSAGE message hook doesn't let you "block" or cancel the message but you can modify it. So simply change lpMsg->message to WM_NULL to prevent the mouse move message from being processed by the target window.

Mouse drag in embbeded Win32 window

In a Qt dialog I have an embedded native Win32 window. As in any standard Win32, I define my own message queue, where, per default, I forward all events to the parent window, and in case an event of interest arrives, I perform some extra work.
My problem is that when I press the left mouse button, then I get the WM_LBUTTONDOWN as expected, but if I keep it pressed, then I get no more mouse clicks events, that is, I get the WM_MOUSE messages, but the mask (wParam), or calling GetKeyState, do not indicate that the mouse key is kept pressed.
The window is created with following parameters,
dwExStyle = WS_EX_TRANSPARENT;
dwStyle &= ~(WS_BORDER| WS_CAPTION | WS_DLGFRAME | WS_THICKFRAME);
CreateWindowExW(0,"Window","Name",dwStyle,
0,0,512,512,
hwndParent,NULL,hInstance,NULL )
When this native window is not embedded in any dialog, it works correctly.
I could also embed this window in a .NET dialog window and observe the same problem.
Any clue what could be going wrong?
Did you mean WM_MOUSEMOVE? Did you try capturing the mouse first?
WM_LBUTTONDOWN is sent only once per click. You'll have to use a boolean to keep track of whether the button is pressed or released during the WM_MOUSEMOVE events. Make use of the WM_LBUTTONDOWN and WM_LBUTTONUP messages together to keep track of this.

Win32 App (Aero): Prevent dialog move

I've a dialog based Win32-app on Win7-Aero which only displays a dialog. The dialog should have a title bar. I don't want that the user can move the dialog on the screen.
I've no luck so far... handling WM_NCHITTEST, WM_SYSCOMMAND... setting SWP_NOMOVE.
What is the best way to achieve NoMove? I think DWM changes something on Win7.
You could do this by handling WM_WINDOWPOSCHANGING and when you see an attempted move, change the coordinates back to where they should be. E.g.
switch (uMsg)
{
case WM_WINDOWPOSCHANGING:
if (!(reinterpret_cast<LPWINDOWPOS>(lParam)->flags & SWP_NOMOVE))
{
reinterpret_cast<LPWINDOWPOS>(lParam)->x = g_iMyXCoord;
reinterpret_cast<LPWINDOWPOS>(lParam)->y = g_iMyYCoord;
}
return 0;
}
You would probably need to add some intelligence to this to distinguish between attempted moves by the user, and moves that your own program makes (or that the system makes if necessary - e.g. if a monitor disappears for instance).
Even though you say it doesn't work, I would have thought you could also do this by trapping WM_NCHITTEST and returning HTBORDER whenever HTCAPTION would have been returned - however you would have to do this by sub-classing the window rather than in the DialogProc (because you would need to call the default handler first and then process/change the return value). Same for WM_SYSCOMMAND (to catch moves the user attempts via the system menu).

Modeless dialog keyboard handling (winapi)

I've got an application with a main window which has a bunch of controls, including the spacebar, which is handled by a simple method called onSpacebar(). On top of that main window, I've got a persistent modeless dialog.
I need the spacebar to behave the exact same way, regardless of whether the dialog has focus, or the main window has focus.
This dialog is backed by a DialogProc which looks something like this:
BOOL CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_NOTIFY:
std::cout<< "WM_NOTIFY" <<std::endl;
switch(LOWORD(wParam))
{
// which component caused the message?
case COMP_TREE:
if(((LPNMHDR)lParam)->code == NM_DBLCLK){
onDoubleclk()
}
//...
break;
// other components...
}
break;
case WM_CLOSE:
// the dialog can only be closed when the whole app is closed
//EndDialog(hDlg, IDCANCEL);
return TRUE;
case WM_DESTROY:
PostQuitMessage(0);
return TRUE;
}
return FALSE;
}
From what I gather, I should call my onSpacebar() method from within the DialogProc, similarily how I handle the double click. I can see that WM_NOTIFY is received by the dialog when the spacebar is pressed (the phrase WM_NOTIFY is printed to cout), but I can't seem to differentiate the spacebar notification from the other numerous notifications the dialog receives.
Please, tell me how to recognize that the particular WM_NOTIFY was in response to a spacebar keypress.
A WM_NOTIFY message is not the standard way that a window processes key press events. When a key is pressed, your window should be receiving WM_KEYDOWN, WM_KEYUP, and possibly WM_CHAR messages. WM_NOTIFY serves an entirely different purpose altogether: passing on a message from a common control to its parent window.
So the fact that you're receiving a WM_NOTIFY message in response to a key press is a fairly unusual thing, explainable when you understand how focus works (which is key to solving your ultimate question).
In Windows, only one window can be focused at a time, and the currently focused window is the one that receives all keyboard input. Thus, if a dialog box has the focus, it will receive key press notifications. If a child control on that dialog box has the focus, it (not its parent dialog) will receive key press notifications. And there is a focusable child control on a dialog box, it will always receive the focus in preference to its parent dialog, therefore it will also always receive key press notifications.
So the likely explanation for your curious WM_NOTIFY messages is that one of the common controls on your dialog has the focus, it is receiving the space key press event, and after processing it, passing on a notification to its parent window (your dialog) in the form of a WM_NOTIFY message. As you might imagine, this is not a reliable method of detecting that the space bar has been pressed.
Instead, you need to figure out some way of trapping key press notifications before they get sent to the focused control. To do that, you'll need to modify your application's message loop to trap WM_KEYDOWN or WM_KEYUP messages before calling either DispatchMessage or IsDialogMessage.
If the key event corresponds to the space bar, you will call your onSpacebar function and indicate that the message was handled, preventing it from being passed on and processed by another window.
If the key event does not correspond to the space bar, then you will need to handle the message as you usually would, ensuring that it does get passed on and processed by the other window.
Since this approach filters out space key presses at a global level, it solves both the problems of child controls on a dialog stealing the key press and the other modeless dialog. However, you do need to be careful because it's very easy to screw things up so that the user can't navigate your dialog using the keyboard at all.
More fundamentally, I think your idea to handle presses of the space bar is fundamentally flawed. The logic of certain common controls basically requires that they process presses of the space bar. For example, consider a textbox: if you filter out all presses of the space bar at a global level, the user will never be able to type a space in a textbox. If you insist on handling the space bar, you will need to check the focused control in your global handler, and if it's a textbox (or other common control that you wish to receive spaces), pass it on; otherwise, handle it yourself.
Honestly, what I'd do instead is choose a more unique key combination (like, I don't know, Ctrl+Space) and set that up as an accelerator. Presumably, your global message loop is already processing accelerator keys by calling the TranslateAccelerator function, so that would take care of all the dirty work for you. No code is even required—you'd do everything simply by editing the accelerators resource file in your project. The MSDN documentation on keyboard accelerators is here, but you'll probably have an easier time consulting your favorite book on Visual C++.

During XGrabKey(board), discover which window had been focused

A program has called XGrabKey() to make a hotkey.
The user presses that key combination (while another window is focused).
The program receives control to do something in response to the key combination. Meanwhile, the program has been temporarily focused (because of the effects of XGrabKey (see man XGrabKey, man XGrabKeyboard)).
I want the program to create a synthetic X event (a keypress or mouse click) to the originally focused window. In some cases this means I need to focus that window before sending it the event (Firefox ignores synthetic events when it is not focused), which means I need to know which window it is. How can I find out which window it is?
Wait for the next FocusOut event, verify that the mode is set to NotifyUngrab, get the focus with XGetInputFocus(), and send away your synthetic events.

Resources