CDialog DoModal (dialog opens with keyboard focus, but not mouse focus) - mfc

I have a CDialog window (CDrafter) which contains a CRichEditCtrl control.
I overrided CDrafter::PreTranslateMessage and CDrafter::OnNotify to allow me to click on special words in the RichTextEdit with the mouse, which in turn opens another dialog (MyDialog).
*NOTE: I did this as I didn't like the limitations of the EN_LINK styling.*
So within the CDrafter::PreTranslateMessage i have:
It just determines where and which word was clicked (nothing more) (waits for OnNotify to do something with it).
So within the CDrafter::OnNotify I have:
BOOL CSTANAGMessageDrafterDlg::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
BOOL r = CDialog::OnNotify(wParam, lParam, pResult);
//if (::PreTranslateMessage found a word clicked on ) {
MyDialog dialog;
dialog.DoModal();
//}
//Awesome my dialog opened and I can start editing the form (via the keyboard) no problems.
//BUG: There is a problem as the mouse curser is still showing the
// move carpet position icon as if it is still focused on the RichTextEdit control.
// If I click the mouse anywhere (in the MyDialog, or within the parent dialog)
// the mouse icon, and focus correctly changes to MyDialog, then I can click OK or CANCEL.
return r;
}
I have tried the calling "CDialog::OnNotify(wParam, lParam, pResult)" after the MyDialog::DoModal - still see same issue.
The MyDialog::DoModal is called within the same thread as the parent dialog.
I would expect to be able to do the following:
click on word, and MyDialog opens, click on MyDialog::Cancel button and the dialog closes.
But there is a problem as this is my sequence:
click on word, and MyDialog opens, click on MyDialog::Cancel button (it doesn't work - only the mouse icon changes), click on MyDialog::Cancel button and the dialog closes
I need to (initially click) the mouse in order to get any mouse control within the newly opened dialog. i.e. the mouseover event on buttons, etc. does nothing until I (click).

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)

Catch OnMouseMove messages for edit control in a window created by createdialog?

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

focus lost after double click in tree view

We use in several place a CTreeCtrl (TreeView) and accept a double click to open dialogs related to the double clicked node.
The opened dialog looses the focus after being opened, since the tree view seems to force to be focussed at the end of the double click handling.
Our scenario:
the user double clicks onto a node
the tree view gets focused and selects an item in its tree
the tree view containing window receives the NM_DBLCLK notification for the tree view and reacts on the double click by opening a dialog or a MDI child window in our MDI environment
the opened dialog/MDI child window gets focused after being opened
the tree view gets focused again
Even if we use in (3) (the notification handler) the result field returning a non zero value to prevent the rest of the default handling, (5) happens and the tree view gets focused again, the item selected again.
I'd really appreciate any hint about a way to resolve this issue, since it is really annoying, that a just opened dialog or window looses its focus right after opening.
Thanks in advance!
This behavior won't occur if you create a modal dialog box, because parent window is immediately disabled and dialog gains focus. But with mode-less dialog, flicker may occur, and dialog loses focus.
For mode-less dialog, use PostMessage or SetTimer so that the mode-less dialog is opened after TreeView message is processed. Example:
#define WM_USER_MSG1 WM_USER + 1
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_MESSAGE(WM_USER_MSG1, create_dialog)
...
END_MESSAGE_MAP()
void CMyWnd::OnDblClick(NMHDR*, LRESULT* pResult)
{
PostMessage(WM_USER_MSG1, 0, 0);
*pResult = 0;
}
LRESULT CMyWnd::create_dialog(WPARAM, LPARAM)
{
if(!m_dlg.GetSafeHwnd())
m_dlg.Create(IDD_DIALOG_X, this);
m_dlg.ShowWindow(SW_SHOW);
return 0;
}

C++ Win32API WM_KEYDOWN and buttons

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;
}

Display context menu over MFC application mainframe menubar

I have VC++ MFC app and I need to display a context menu over CMainFrame menubar. I added a handler for WM_CONTEXTMENU in CMainFrame and I am able to display my context menu over the toolbar (also the window title) but the handle does not get invoked when I right click in the menubar
Using the Spy++ utility and right clicking on the client, toolbar or caption regions of a typical application results in the following message trace information:
<02620> 005503AE P WM_RBUTTONDOWN fwKeys:MK_RBUTTON xPos:1048 yPos:7
<02621> 005503AE P WM_RBUTTONUP fwKeys:0000 xPos:1048 yPos:7
<02622> 005503AE S WM_CONTEXTMENU hwnd:005503AE xPos:1174 yPos:63
But right clicking on the menu produces no corresponding trace information in the Spy++ message window. So it looks to me like this is standard Windows behaviour.
I suspect Windows is generating the WM_CONTEXTMENU message in response to the WM_RBUTTONDOWN and WM_RBUTTONUP messages and since these are not generated when you right click on the menu, no popup context menu is displayed.
But if you really want this behaviour, what you could do is trap the WM_NCRBUTTONDOWN client mouse message and inside this message handler post your own WM_CONTEXTMENU message to the frame window.
Thanks for pointing me in the right direction. I was able to do it by handling WM_NCRBUTTONUP message and inside the handler check whether the point is on the menu bar.
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CONTEXTMENU()
ON_WM_NCRBUTTONUP()
END_MESSAGE_MAP()
void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point) {
// do not display our popup menu for title bar, etc
CRect rcClient;
GetClientRect(rcClient);
ClientToScreen(rcClient);
if (rcClient.PtInRect(point))
PopupMenu(point);
else
__super::OnContextMenu(pWnd, point);
}
void CMainFrame::OnNcRButtonUp(UINT nHitTest, CPoint point) {
if (nHitTest == HTMENU)
PopupMenu(point);
CFrameWnd::OnNcRButtonUp(nHitTest, point);
}
int CMainFrame::PopupMenu(CPoint &point) {
// display popup menu
....
}