I'm having a problem receiving message in WM_KEYDOWN. WM_KEYDOWN works just fine until I click any button in my app. From that point it no longer receives my input from the keyboard. How to fix it?
If you are using Win32 controls such as CreateWindowEx(NULL, L"BUTTON", ... this is expected Each control is actually a child window and is capturing all of the window messages after it has focus.
Once the button is clicked you can capture the WM_COMMAND - BM_CLICK message to then call SetFocus(hwnd) to refocus on your window (as Giswin mentioned).
Probably your window has no focus before you click any button on your app. you can add code somewhere in your app to set focus programmatically:
yourwindow->SetFocus();
or use winapi:
::SetFocus(hWnd);
Just in case anyone is wondering, I (unsurprisingly) noticed the same behavior for handling WM_CHAR responses in my WindowProcedure callback as well. As soon as you click a button, the focus changes from the main window to the button control (which is a child window) and keyboard presses no longer have any effect.
As suggested by #NTSCCobalt, adding a simple SetFocus(main window handler) in your WM_COMMAND cases will solve the problem, e.g.
case DEL__BUTTON:{
<Button specific code>
SetFocus(hwnd);
return 0;
}
Related
When I set the parent of a button (A) to another button (B), I found that it won't trigger the WM_COMMAND message of button A, and that there will be a WM_PARENTNOTIFY message received by the window (parent of button A). But after looking up the reference, I found no way to get the identity of button B, like HMENU or HWND. Could someone help me?
Yes, it's sure that it seems strange that somebody put a button into another button, or say set the parent of a button to another button, but it do has some realistic meaning when the parent button has a style of BS_GROUPBOX, just as the Frame in Visual Basic.
img_button_in_button
My solution to this problem is calling SetWindowSubClass after created a new control and so that the new callback function set in calling this API can receive the real hWnd of the control triggering this event.
Something to remark:
Use return DefSubclassProc(hWnd, uMsg, wParam, lParam); if that event is not to be handled by the control.
Remove WS_CHILD style for those controls calling SetWindowSubClass, or those controls can not be correctly displayed and the only thing displayed would be just an empty window.
Thanks for all who helped me in this question!
I want to handle the clicks on child windows the same as clicks on parent window - how can I do that in winapi?
Currently, I can move the parent window by pressing anywhere on it but not on the child windows, because then it won't move. How can I change that?
The answer that works:
case WM_NCHITTEST:
if (hWnd==parent)
return HTCAPTION;
else return HTTRANSPARENT;
Capture the mouse click on the desired child controls(s), and then send a WM_SYSCOMMAND message with SC_DRAGMOVE (0xF012, aka SC_MOVE OR'ed with 2) as the wParam parameter to the parent window. That will invoke a drag operation on the parent window.
This is a widely known trick, and well documented online (just not by Microsoft) if you do a search for SC_DRAGMOVE.
Is it possible for the the main application window to detect a WM_CLOSE event when a modal dialog is active?. If not, is there any way of detecting the WM_CLOSE event because the event handler for the dialog does not detect it either.
To observe this behaviour for yourself, open the 'about' menu of notepad and then right-click on the notepad icon in the taskbar and select the 'close window' option, it will have no effect.
Does anyone know of a way to catch a WM_CLOSE event for an application when a modal window is active?
When selecting "close" by right-clicking an application's icon in the task bar no WM_CLOSE is sent.
What happens is that the application's main window is sent a WM_SYSCOMMAND with wParam set to SC_CLOSE.
For an example on how to exploit this "feature" please see my other answer on this here.
I have a Windows application that registers one CALLBACK procedure that handles WM_HELP messages for the dialog, and one CALLBACK procedure that handles WM_LBUTTONUP messages for a custom button.
Now, when the user clicks the "?" button, then clicks the custom button, the help opens up as expected (on mouse down), BUT if the help window is not occluding the button, a WM_LBUTTONUP message is triggered as well for the custom button (on mouse up). This causes the button to trigger when the user was only asking for help.
Is there any way to stop the WM_LBUTTONUP message from being sent if the button press is for help?
EDIT: The custom button is implemented using a STATIC control. I believe this is because it needs to have an image and no border. So, it does not send BN_CLICKED notifications. In fact, it does not seem to trigger WM_COMMAND in the parent at all.
Thanks
This is normal. Be sure to use the button's BN_CLICKED notification to see the difference. Generated when the user clicks the button, not generated when the user uses the help cursor. The button still sees the normal button up/down messages so that's not a good trigger to detect a click. Extra bonus is that the button can now also be clicked with the keyboard (space bar).
A good class library takes care of these nasty little details.
A better way would be to create ? as a custom control with BS_CHECKBOX | BS_PUSHLIKE style and capture the mouse. After that you will get all the WM_LBUTTONDOWN message to this custom control and then you can use WindowFromPoint to get the window where the WM_LBUTTONDOWN happened and can send a custom notification to the parent window. The parent window can then show a the tooltip or open the help doc or discard it.
The advantage is, you create the control only once and you can use it in multiple places.
Okay, I fixed it by creating the custom button (static control) with the SS_NOTIFY style, then handling the STN_CLICKED notification in the WM_COMMAND message. (SS_NOTIFY causes WM_COMMAND to trigger in the parent when it is clicked.) This does not trigger when using the "?" button. Thanks!
HWND button = CreateWindowEx(0, "BUTTON", ...);
SetFocus(button); // Button no get focus! :(
Also, I have other controls on my form that I am able to SetFocus() to.
Thanks, Martin
It has been FOREVER since I've had to do this, but...
Were this a dialog, I would tell you to send a WM_NEXTDLGCTL via PostMessage(). The default dialog item message handler would take care of the rest for you setting keyboard focus and selection activation. However, this is a different case if I read this correctly. You're creating both parent and child windows raw on the fly. If this is the case, SetFocus() to the parent window, and handle WM_SETFOCUS on the parent window by bringing it to top, then setting focus on the child window. WM_SETFOCUS, and WM_KILLFOCUS were designed to allow you to switch the 'activated' state of your controls, and most handle it for you (unless your window is an owner draw control or some such). But in a raw window, when your base parent window is sent the focus, you need to appropriately ensure the proper child has it if you're hosting any (think of it as managing your own 'dialog'). Again, normally this is done by the default dialog procedure for you if this were a dialog, but being raw windows you're kind of stuck managing it all yourself.
Though I can't imagine how, I hope that helped somewhat.
SetFocus is a function, not a procedure. Call it as a function and check its returned value. Either the retuned value is null because you made an error in the CreateWindowEx() call and "button" isn't a valid handle or it's a window not associated with your thread's message queue, or the return value is not null (it's now the prior focused window's handle) and you do have the focus (but are somehow failing to detect it).
Try setting the WS_TABSTOP style on the button.
If you create that button in respond of the WM_INITDIALOG message you should return FALSE to prevent dialog box procedure to change the focus.