C++ Window losing focus when child button is pressed - c++

I am trying to get a GUI running for a C++ application but I am having an issue with key press events. Basically, everything works fine, as long as I do not click on any buttons (the main window registers key events), but as soon as I click on a button, the main window loses focus and it no longer captures key events. This might be a stupid question, but I am very new to C++. This is some of the code I am using:
Creation of the main window:
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Application Name", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
540, /* The programs width */
250, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
Creation of one of the buttons:
CreateWindow(TEXT("button"), TEXT("Start"),
WS_VISIBLE | WS_CHILD,
x, y, width, height,
hwnd, (HMENU) 6, NULL, NULL);
I have also noticed that whenever I click on a button, the WM_KILLFOCUS event is fired, which is why I think that this is a focus issue. I have also tried capturing the WM_KILLFOCUS event and then set the focus again with SetActiveWindow but that crashed my program.
Any help would be appreciated :)

It turned out that I was using the wrong function (SetWindowActive). Assaf Levy's answer seemed to complex for me and I thought that there might be another way around this. I managed to find the SetFocus function which gives the focus to any given window by providing it it's handle.
To make it work, what I needed to do was to, once that the the necessary code was executed within the WM_COMMAND block, I called the SetFocus function with the handle of the main window. This gave focus back to the main window and allowed it to receive events.
Note, putting the SetFocus in the WM_KILLFOCUS block will cause the buttons and any other component in it to become unresponsive to events.

This is by design. The main window is a window, but so the button is a window, and only one can have focus at any given time. If you don't want the button to "steal" the focus, add an OnFocus handler (or intercept WM_SETFOCUS) and immediately return focus to the previous window (I believe it's in the WPARAM of WM_SETFOCUS).
An easy hack would be:
hMyButton = CreateWindow("button", ...).
Define a MyButtonProc(HWND, UINT, WPARAM, LPARAM) function.
Call SetWindowLong(hMyButton, GWL_WNDPROC, (LONG)MyButtonProc). Save the value returned by this function in a g_OldButtonProc.
Inside MyButtonProc() catch WM_SETFOCUS, and call SetFocus(hMyMainWindow).
Always return CallWindowProc(h_OldButtonProc, hwnd, msg, ...) at the end of your MyButtonProc() function, unless the message was WM_SETFOCUS.
That will do the trick (tested).

The first answer was partially accurate. Subclassing the button can get "rid" of the "problem"; however handling WM_SETFOCUS be it in parent window, or subclass procedure or BN_SETFOCUS will result in unresponsive UI if you take the focsus from the button.
What you should override in the subclass procedure is WM_LBUTTONUP. Since by the time you release the mouse button you have already clicked the windows button.
Note I think this is utter rubbish for a button to be stealing focus. There should be a style like BS_NO_STEAL_FOCUS, that prevents this. As it is very cumbersome when you want another window to be handling key presses or scrolling.
/** Procedure for subclass.
This procedure is called first for the widget/control.
Unhandled or partially handled message can goes to
original procedure by calling DefSubclassProc(...).
buttonProcEx takes all four params of normal procedure, plus a
param for user defined object.
Note this is what win32 should have done in the first place.
*/
LRESULT CALLBACK buttonProcEx(HWND hwnd,uint msg,WPARAM,LPARAM,DWORD_PTR)
{
if(msg == WM_LBUTTONUP)
{
setFocus(GetParent(hwnd));
return 0; //do not allow default behaviour
}
else return DefSubclassProc(hwnd,msg,wparam,lparam);
}
//Call this after creating your button
SetWindowSubclass((HWND)button,buttonProcEx,0,NULL);
or
struct Content {...}content; //lifetime should be long enough
SetWindowSubclass((HWND)button,buttonProcEx,0,(DWORD_PTR)&content);

Related

Window does not get focus after expand it from tray while holding tab WINAPI

When you have an application hiding in the tray, you should be able to expand it. Here the problem comes in: when I holding tab key to switch focus in taskbar and try to show the window with hWnd->ShowWindow(SW_SHOW) and SetForegroundWindow(*hWnd) calls, my window is not activated. I have the ability to work with it, but it doesn't have focus for the tab key until I click it again (in the tray) without holding the tab.
The problem is that when I call ShowWindow and SetForegroundWindow I get 0 return code from both.
Sample code:
// blablabla working with messages loop
void OnShowTrayWindow(UINT /*message*/, WPARAM /*wParam*/, LPARAM /*lParam*/) {
// handle some situations
m_hWnd->ShowWindow(SW_SHOW); // returns 0 in my case
SetForegroundWindow(*m_hWnd); // returns 0 in my case
SetFocus(m_hWnd);
}
My window have WS_TABSTOP flag in styles. Actually, tab works perfectly when I have activated window.
P.S. I think that this behavior can be related with the SetForegroundWindow requirements (see https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setforegroundwindow)

WinAPI timer callback not called while child window is in focus

I'm working on a 3D editor app using Direct3D and WinAPI. I create a main window, which has a child window that takes up a portion of the main window's client area. This is used by D3D as the render target. I then also create a separate window with CreateWindow, which is built the same way as the main window (i.e a "main window" and an internal child used as a render target), and I make this window a child of the main application window (to ensure that they are minimized/restored/closed together).
The D3D rendering is executed by the render target child windows processing their WM_PAINT messages. To reduce unnecessary overhead, I set the window procedures to only render on WM_PAINT if GetForegroundWindow and GetFocus match the respective window handles. In other words, I only want a window's rendering to be refreshed if it's on top and is focused.
This is my main message loop:
HWND mainWnd;
HWND mainRenderWnd;
HWND childWnd;
HWND childRenderWnd;
// ...
MSG msg = {};
while (WM_QUIT != msg.message)
{
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
{
if (!TranslateAccelerator(mainWnd, accel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
else
{
// Run non-UI code...
}
}
When the main window gets WM_SETFOCUS, I have it set the focus to its render target child window, since I'll want to process inputs there (e.g camera controls):
// ...
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
//...
case WM_SETFOCUS:
{
SetFocus(mainRenderWnd);
return 0;
}
//...
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
I do the same in the window procedure for childWnd, setting the focus to childRenderWnd. This window is opened and closed by the user, i.e at any one time it may or may not exist, but when it does and is not minimized, it needs to be the foreground window with focus. Also, to control the framerate for the child window, I use a Timer to refresh it:
static constexpr UINT_PTR RENDER_TIMER_ID = (UINT_PTR)0x200;
void TimerCallback(HWND Arg1, UINT Arg2, UINT_PTR Arg3, DWORD Arg4)
{
if (IsIconic(childWnd) || !(GetFocus() == childRenderWnd))
return;
// Invalidate the render area to make sure it gets redrawn
InvalidateRect(childRenderWnd, nullptr, false);
}
// ...
SetTimer(childWnd, RENDER_TIMER_ID, 16, (TIMERPROC)TimerCallback);
With all this set up, mainWnd and mainRenderWnd seem to work just fine. However, childRenderWnd refuses to have anything rendered to it when it is in the foreground and in focus. While debugging, I found that while this is the case, the timer callback never gets executed, nor does a WM_TIMER message get dispatched to the child window.
On the other hand, the moment I deliberately move focus out of the child window and onto the main window (while keeping both open), the timer message gets sent, and the callback is executed. Another problem is that when I minimize the app while both windows are open, and then restore them both, the render target of neither of the windows is refreshed. Instead, it seems like the focus got "flipped", as I have to click on my child window first, then my main window, and that makes it refresh properly (while the child still refuses to render anything).
What am I missing? I searched for others having problem, e.g an incorrect message pump setup blocking WM_TIMER, but nothing seems to explain what's going on here.
Thanks in advance for the help!
IInspectable and Raymond Chen's comments have helped lead me to the answer. I tried to reproduce the error in a minimal app and finally came upon the source of my trouble. Originally, the main window would just call InvalidateRect in the message loop if there were no messages to be dispatched, effectively redrawing itself every chance it got. This originally did not seem to cause any harm, the scene was rendered just fine, and the window responded to inputs. Once I introduced a second window, however, it must have flooded the message loop with paint messages, making it impossible for any timer messages to get through.
The solution, quite simply, was to give a timer to both windows to set the rate at which they would refresh their D3D render targets. Coupled with focus checks, I can now easily alternate between both windows, with only one refreshing itself at any given time.
The question remains whether the WinAPI timer system is the best choice. My bad code aside, people have mentioned that the timer's messages are low-priority, which might make it a poor choice for framerate control in the long run.
EDIT: I ended up going with IInspectable's suggestion to use a while loop within the main message loop to process to dispatch all messages, and once those are processed, I perform a frame update. This allows me to consistently update all windows and control the frame rate without risking the issue of window messages being stuck.

Win32 C++ Subclassed label not receiving WM_PAINT after calling WM_SETTEXT

Is it normal behavior that a subclassed control does not receive WM_PAINT after you call WM_SETTEXT on it?
The parent does receive WM_CTLCOLOR, but I want to paint evertything inside my subclassed WM_PAINT message.
I assume calling InvalidateRect after calling WM_SETTEXT is the way to go?
Let me know if you want to see code. I feel like its not necessary for this question that is why I left it out initially.
Whether WM_PAINT is sent in response to WM_SETTEXT depends on what window class has been sub-classed, buttons for example are invalidated but list boxes are not (the window text for a list box is little more than a debugging aid as it is not shown in the UI).
If your class is such that setting the text should invalidate you could always add something like the following to your subclass' WindowProc:
case WM_SETTEXT: {
LRESULT res = CallWindowProc(lpfnParent, hWnd, WM_SETTEXT, wParam, lParam);
InvalidateRect(hWnd, nullptr, true);
return res;
}
That way you don't need to have an InvalidateRect each time you set the control text.

SendMessage(hWnd, Msg, wParam, lParam) difficulties

I am trying to make a program click a button on another program; I decided to use the function:
SendMessage(hWndVariable, MsgVariable, wParamVariable, lParamVariable)
but there is an issue. The window with the window handle hWndVariable has 3 buttons. I initially planned to use the following parameters in the SendMessage function:
SendMessage(hWndVariable, BN_CLICK, 0, 0);
Question:: but since there are 3 buttons, how would the program know which one is being clicked? lol I am guessing that I am either missing something or doing something completely wrong.
SendMessage(hWndVariable, BN_CLICK, 0, 0);
This is your problem right here. First, you're sending a nonexistent message (you meant BN_CLICKED). Second, you're not sending the message correctly.
As described in answers to your previous questions, you need to get the button's ID. You can do this using Spy++.
Then, per the BN_CLICKED documentation, you can send your message like this:
SendMessage(parentWindowhWnd, WM_COMMAND, (BN_CLICKED << 16) | BUTTONID, buttonhWnd);
Fill in the values appropriately - parentWindowhWnd is the HWND of the window containing the button, BUTTONID is the button's ID, and buttonhWnd is the HWND of the button itself.
BN_CLICKED is a notification that the button sends to its parent window. You are thinking of the BM_CLICK message instead, which you can send to a button window to simulate a click on it:
//SendMessage(hWndVariable, BM_CLICK, 0, 0);
SendMessage(hWndVariable, BM_CLICK, 0, 0);
In order for this to work, hWndVariable has to point to the specific button that you want to click on, not its parent window like you are currently doing.

How to kill focus of "edit" control on "Enter" key press

I have a main window created in main function. In procedure for the main window on WM_CREATE message I create a edit control which as a child of parent window using system "edit" window class. I want the focus to be transferred to main window when enter key is pressed in edit control. Since I used system class I don't have access to its procedure.
I am using C++ for this in Visual Studio 10
Since I'm new to win32 apps I want a simple solution no matter how long the code is
If your window has only one focusable control (such as an edit control), then that control will always have the focus. You cannot have a window with no focused controls, and the parent window itself is not focusable (i.e. cannot have the focus).
So you will first need to add another focusable control to your window, if you don't have one already (I couldn't tell from the question). For example, you might add an "OK" or "Cancel" button. That way, whenever you unfocus the edit control, the button can receive the focus.
Then, you will need to subclass the edit control so that you can process its key press events (e.g. WM_KEYDOWN and WM_KEYUP). To subclass a single window, call the SetWindowLongPtr function and pass the window handle along with the GWLP_WNDPROC flag and a pointer to your custom window procedure. This effectively replaces the default window procedure for that class of control with your custom window procedure. For example:
// Stores the old original window procedure for the edit control.
WNDPROC wpOldEditProc;
// The new custom window procedure for the edit control.
LRESULT CALLBACK CustomEditProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_KEYDOWN:
{
if (wParam == VK_RETURN)
{
// The user pressed Enter, so set the focus to the other control
// on the window (where 'hwndOther' is a handle to that window).
SetFocus(hwndOther);
// Indicate that we processed the message.
return 0;
}
}
}
// Pass the messages we don't process here on to the
// original window procedure for default handling.
CallWindowProc(wpOldEditProc, hWnd, msg, wParam, lParam);
}
// ----- Add to the parent window's WM_CREATE: -----
// Create the edit control
HWND hwndEdit = CreateWindowEx(...);
// Subclass it.
wpOldEditProc = (WNDPROC)SetWindowLongPtr(hwndEdit,
GWLP_WNDPROC,
(LONG_PTR)CustomEditProc);
// Show it.
ShowWindow(hwndEdit, SW_SHOW);
// ... your other code (e.g. creating and showing the other control)
// ----- Add to the parent window's WM_DESTROY: -----
// Unsubclass the edit control.
SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR)wpOldEditProc);
// ... your other code (e.g. calling PostQuitMessage(...) to close your app)
Further reading about subclassing windows is here on MSDN. The sample code there (and lots of other places on the web) assumes that you're subclassing an edit control in a dialog window. Because dialogs are special types of parent windows that handle a lot of keyboard processing automatically, you need to take extra steps to overcome this default processing done by the dialog. If you're using a regular window created with CreateWindowEx, that is not necessary.
If you want multiple edit controls that all behave the same way in response to certain key presses, it is much cleaner and better design to register a custom window subclass. Whereas the above code subclassed only a single edit control object, this approach would create a new type of custom edit control class. You could create as many instances of this new type of edit control as you wanted, and they would all behave the same way.
But I won't go into how to do that here. You can find the code online if you're interested, and your particular use case makes it a bit more complicated. In order to change the focus, the control has to know which other control it should set the focus to. This is difficult to handle globally. Using a dialog window as the parent might be advisable. It manages the Z order and setting the focus for you automatically.