Mouse drag in embbeded Win32 window - winapi

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.

Related

How to capture the action about starting dragging a window and releasing the capture of a window?

When cursor honver over the title zone (HTCAPTION),press left mouse button, then you can drag a window and move it. When you release the left mouse button , you can stop this dragging action. When you move a window , it triggered the message WM_MOVE. When release the mouse button , I don't know which message should be handled for catching this action.
What I'm doing is when you drag a window(let's say window A) into another window's area(window B), make window A a child window of window B, when drag window A out of window B's area , make window A a WS_POPUP window, without WS_CHILD style.
I handled message WM_MOVE and WM_CAPTURECHANGED( I don't think it's the right one).
In WM_CAPTURECHANGED , I found something wired. The API SetWindowPos seemed not work well. To be percise, the 3rd and the 4th parmater , specified the window's position not work.
case WM_CAPTURECHANGED: {
RECT rcc;
GetClientRect(main,&rcc);
// here main is the handler of window B , hwnd is for window A,as referrence above.
if(docker_mode==DOCKER_LEFT) {
// docker_mode is assigned by WM_MOVE message handler. recording which area window A was moved into.
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))!=WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,(~WS_POPUP)&(WS_CHILD|GetWindowLongPtr(hwnd,GWL_STYLE)));
SetParent(hwnd,main);
}
//The following code not work. It should be moved into the left-top corner of window B,
//but NOT in fact.
SetWindowPos(hwnd,NULL,0,0,300,rcc.bottom-rcc.top,SWP_NOZORDER);
}
else {
if((WS_CHILD&GetWindowLongPtr(hwnd,GWL_STYLE))==WS_CHILD) {
SetWindowLongPtr(hwnd,GWL_STYLE,((~WS_CHILD)&GetWindowLongPtr(hwnd,GWL_STYLE))|WS_POPUP);
SetParent(hwnd,NULL);
SetWindowPos(hwnd,NULL,300,0,0,0,SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED);
}
}
} break;
SetWindowLongPtr(...,GWL_STYLE,...) was called to set the window style . A top level has no WS_CHILD style, and the handle of parent window should be NULL , I use SetParent(hwnd,NULL) to do this. A child window should have WS_CHILD style, and the parent window should be assigned.
I put a button into the window , and copy those code into the handle of button click event. When click the button it works well , change a popup window into a sub window , put the sub window into right position. SetWindowPos has no problem at all. I don't know why.
SetWindowPos is a very interesting API when working on WM_CAPTURECHANGED handler. What's wrong ?
If I recall correctly, when the user drags a window, that window receives a sequence of messages like this:
WM_ENTERSIZEMOVE
WM_WINDOWPOSCHANGING
WM_MOVING
WM_WINDOWPOSCHANGED
WM_MOVE
WM_EXITSIZEMOVE
(There are other messages, too, but I don't think you need to worry about those. There may be some final messages after WM_EXITSIZEMOVE with the final resting place for the window.)
The steps in the middle will happen repeatedly as the user drags the window. (In the Old Days, only some of those middle steps would happen, and there may still be an option to cut down on the messages during the drag operation.)
You can try using Spy++ (included with Visual Studio) to confirm the above.
So you shouldn't need to deal with the mouse capture messages. Have window A watch for WM_EXITSIZEMOVE. At that point, window A can check its position to see if it overlaps the target window (B). If it does overlap, then it should send a message to window B to initiate the docking operation.

Grabbing any keypress in X11

I'm trying to implement a simple X11 key grabber in C for window switching with Alt-Tab etc. I can use the function XSelectInput to handle keyboard events for a specific window:
XSelectInput(display, window, KeyPressMask | KeyReleaseMask);
How can I receive "global" keyboard events regardless of which window is focused?
You need XGrabKey. This function is specifically designed for implementing hotkeys.
When the desired key combination is pressed, you get the event no matter what, and no other window gets the event.

SendMessage(WM_SYSCOMMAND) failed when mouse captured

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.

Win32, How to access button on toolbar

Let's say I have a compiled binary program that runs and exposes some GUI on the screen.
I need from another program in Win32 to access its toolbar, find a button and click on it.
I know how to find Hwnd of the toolbar, but I don't really know how to enumerate the buttons on it.
Any ideas how to do it in Win32 calls?
Is there any tool like Spy++ that is capable of showing button handles under toolbar?
Spy++ doesn't do it.
Thanks
If it is a standard Win32 Toolbar control, then you send the toolbar a TB_BUTTONCOUNT message to determine how many buttons are on the toolbar, then send a TB_GETBUTTON message to retrieve information about a button at a given index.
The tricky part is that the TBBUTTON structure that receives the button info needs to be allocated in the same process that owns the toolbar, so you will have to:
call GetWindowThreadProcessId() to retrieve the toolbar's process ID
call OpenProcess() to get a HANDLE to that process
call VirtualAllocEx() to allocate the structure inside of that process
send the TB_GETBUTTON message(s) to the toolbar, specifying the pointer returned by VirtualAllocEx()
call ReadProcessMemory() to copy the structure data back into your own process so you can process it as needed
call VirtualFreeEx() to free the allocated memory.
When the button is clicked it sends a WM_COMMAND message to the main window. Simulating a click on a toolbar button is not very practical. A better approach is to use Spy++ to find the WM_COMMAND message and its parameters. Then in your program send this same WM_COMMAND message.
AFAIR you can get the HWND of a toolbar button by calling GetDlgItem. The first parameter is the HWND of the toolbar, the second parameter is the ID of the button (the one you set in its TBBUTTON structure). You need to have the button ID to use this approach.
=== EDIT ===
In addition to EnumChildWindows, suggested by #graham.reeds, you can try SendInput. Move the target window to the foreground, calculate the screen coordinates of the upper-left corner of the toolbar (using its HWND), add the X-Y offset of the middle of the target button, and send a mouse click to that position. (I used this approach successfully to click on Flash and Silverlight objects rendered inside the IE window.)
Off the top of my head:
Use EnumChildWindows to find the child controls of the toolbar.
Then use GetWindowText to see if it is a button.
If it is PostMessage to it to invoke it's operation.

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