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.
Related
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)
I would like to create a custom File Open dialog where I can replace the default context menu options shown when the user right clicks one of the files in the list, with my own context menu.
Based on articles such as this one, and this one, I tried adding:
UINT CALLBACK OfnHookProc(HWND hDlg, UINT uMsg, UINT wParam, LONG lParam)
and then refer to it using
ofn.lpfnHook = OfnHookProc;
I guess the ideal solution will be a class derived from OPENFILENAME. Not sure how.
For the Explorer-style Open dialog box:
The default templates are not available for modification.
The hook procedure does not receive messages intended for the standard controls in the dialog box.
So there seems little possibility to replace the default context menu via editing or subclassing the open dialog itself.
From the user's perspective, the chief benefit of the common dialog
box is its consistent appearance and functionality from
application to application. Hiding original controls or otherwise
changing the intended functionality of the original controls is a less appropriate customization.
However, there is a workaround maybe help:
Add your context menu item to the default one as an addition. Like this:
Refer to "Creating Cascading Menus with the ExtendedSubCommandsKey Registry Entry" for more detailed information.
Note: Modifying registry will affect all application instead of only your own application. So make sure keep this modification in a mini, required scope. For example, if putting this change in HKEY_CURRENT_USER\Software\Classes is enough don't put it in HKEY_LOCAL_MACHINE\SOFTWARE\Classes.
As mentioned by #remy-lebeau, you can do that using window subclassing as listed below:
get hWnd of the File Open dialog
replace WndProc via SetWindowLong(hWnd, GWL_WNDPROC, ..)
after that you will be able to track mouse position and handle WM_RBUTTONDOWN
To get window handle, you can use FindWindowEx, EnumWindows or even SetWindowsHookEx. Don't forget to pass unhandled messages to the original window procedure.
I have a dialog window that is created by CreateDialog().
Within the dialog window is a text edit control which is created automatically by the CreateDialog() call, however I can't seem to catch OnMouseMove messages for it - only its parent window (of the controls, not the dialog). CreateDialog() only allows you to set a procedure function for the main dialog (not the sub objects, like the edit controls) and if I catch the OnMouseMove messages there, they only trigger for mouse movement on the main dialog itself (anywhere there is NOT a control, ex. buttons, text edit boxes, etc).
Short of creating the window manually with CreateWindowEx() (and all the sub objects), is there a way to catch the OnMouseMove messages associated with the specific text edit control by its ID or something? I have its handle retrieved by GetDlgItem().
What I am ultimately trying to accomplish is to both read the text below the mouse cursor and display a relevant tooltip if the word is recognized/matched, and I am definitely open to other alternatives if you have any ideas!
Here is the basic code :
Creation of the dialog, using the DBG_DLG template to define the controls
hDbg = CreateDialog(hCurInst, TEXT("DBG_DLG"), 0, DbgDlgProc);
The DBG_DLG template is defined in the project's .rc file. I couldn't find a simple way to paste that code here, but it has a particular text edit control that I am trying to catch with an ID of ID_OP_ED.
Relevant code from DbgDlgProc() that does NOT work, and only catches messages associated with the main dialog and not the controls themselves. Hovering over the controls causes no messages to be caught by this routine.
BOOL CALLBACK DbgDlgProc(
HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
switch(message)
{
case WM_INITDIALOG:
return TRUE;
case WM_MOUSEMOVE:
OnMouseMove(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), (DWORD)wParam);
return FALSE;
Once you have the HWND of the child text edit (from GetDlgItem()), you can subclass it directly, using SetWindowLongPtr() or better SetWindowSubclass(). Your subclass will receive all of the messages sent directly to the control.
Refer to MSDN for more details:
Subclassing Controls
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);
I'm writing a Windows CE application in C++ directly applying the WINAPI. In this application I parse a text file, which may or may not be large and thus may or may not take a while to load; and as I will add functionality to load files across the wireless network, I figured it would be best to add a progress bar.
My aim is to display the progress bar in a modal dialog, thereby preventing the user from interacting with the main window. A thread is then created to perform the loading in the background, leaving the main thread to update the GUI.
However, using EndDialog() prevents me to return to the code which loads the file until the dialog has been closed. Obviously I want to show the dialog and then load the load, periodically updating the progress from the background thread. At this point I only know of two options to circumvent this:
Create the dialog using CreateDialog, modify the message handler to accommodate messages designated to the dialog, disable the main window and lastly create the background thread.
Create the background thread in a suspended initial state, create the dialog using DialogBoxParam passing along the thread ID, and when capturing the WM_INITDIALOG resume the thread.
Although any of these two would probably work (I'm leaning towards the second option), I'm curious about whether this is the way progress bars are supposed to be handled in a Windows environment -- or if there is a leaner, more clever way of doing it.
You don't have to do anything particularly tricky or unusual. Just create the modal dialog box with DialogBox(). In the WM_INITDIALOG handler of your dialog box procedure, create the background thread to load the file. As the loading progresses, send the PBM_SETPOS message to the progress bar control to update it.
When the loading completes, call EndDialog() to close the dialog box. However, EndDialog() must be called from within your dialog procedure. So to do that, you need to send a dummy message (e.g. WM_APP):
DialogBox(..., DlgProc);
// File loading is done and dialog box is gone now
...
INT_PTR CALLBACK DlgProc(HWND hwnd, UINT msg, LPARAM lparam, WPARAM wparam)
{
switch(msg)
{
case WM_INITDIALOG:
CreateThread(..., LoadingThread, ...);
return TRUE;
case WM_APP:
EndDialog(hwnd);
return TRUE;
...
}
return FALSE:
}
DWORD WINAPI LoadingThread(LPVOID param)
{
// Load the file
while(!done)
{
...
SendMessage(hwndProgressBar, PBM_SETPOS, progress, 0);
}
SendMessage(hwndDialogBox, WM_APP, 0, 0);
return 0;
}