Reputation: 5933
I want to extend the functionality of a third party application which uses keyboard shortcuts for use on a touch screen monitor. My plan to achieve this was to make an on screen keyboard to feed keystrokes (virtual) to the application and to change the window style to embed it into the keyboard.
As the application (Mach3) supports extending the functionality with plugins this is how I wanted to achieve my goal.
For the embedding I modified the code from here so that on loading mach3, the application dialog is immediately embedded into my dialog.
For the keyboard functionality I used code from here to give the window the WS_EX_NOACTIVATE
style and handle being moved correctly.
The problem that I have is that when I give focus to another window (for instance notepad) and press a button to generate a keypress, the keypress is received correctly by the other application, however when I give the focus to the embedded window and press a button, the focus is shifted to the button and no keypress is received by the child dialog.
How do I prevent the focus from being changed like this? Is this a simple thing I'm missing or do I need to drastically change my approach?
I would post some code, but there is rather a lot of it and I'm not sure which bits would be the most relevant to solving this problem.
Upvotes: 0
Views: 949
Reputation: 5933
I figured out the cause of my problem, which now allows me to create an embedded dialog with the parent dialog acting as an on screen keyboard.
firstly as commented above I needed to make some changes to my keyboard code, specifically the overridden OnNcLButtonDown
which the article says should be:
void COnScreenKeyboardDlg::OnNcLButtonDown(UINT nHitTest, CPoint point)
{
if (!m_hForegroundWnd)
{
// store current foreground window
m_hForegroundWnd = ::GetForegroundWindow();
// temporarily make this dialog an activatable window
ModifyStyleEx(WS_EX_NOACTIVATE,0);
// make this dialog foreground
SetForegroundWindow();
}
CDialog::OnNcLButtonDown(nHitTest, point);
}
but should actually be:
void CWrapperDialog::OnNcLButtonDown(UINT nHitTest, CPoint point) {
SetForegroundWindow();
CDialog::OnNcLButtonDown(nHitTest, point);
}
secondly the article says to override OnMouseMove
with:
void COnScreenKeyboardDlg::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_hForegroundWnd)
{
// make the previous foreground window active
::SetForegroundWindow(m_hForegroundWnd);
// make this dialog non-activating
ModifyStyleEx(0,WS_EX_NOACTIVATE);
// set it to NULL to mark that we do not need to do this again
m_hForegroundWnd = NULL;
}
CDialog::OnMouseMove(nFlags, point);
}
the comment below "corrects" this to:
void CWrapperDialog::OnMouseMove(UINT nFlags, CPoint point) {
::SetActiveWindow(0);
CDialog::OnMouseMove(nFlags, point);
}
however I found that with this code I would get flashing from the focus changing whenever I moved the mouse, so I omitted it entirely.
Lastly the keyboard example used DoModal
to create the dialog, whereas I was using Create
I created a wrapper function I could call with AfxBeginThread
:
UINT CWrapperDialog::ThreadDoModal(LPVOID pParam){
CWrapperDialog* dlg;
dlg = ((CWrapperDialog*)pParam);
dlg->DoModal();
return 0;
}
and called it:
dlg = new CWrapperDialog;
AfxBeginThread(dlg->ThreadDoModal, dlg);
and now the messages are being passed correctly.
Thanks to o_weisman for the tip regarding the changes to the example as this made a massive difference.
Upvotes: 1