2

I have this code:

BOOL CChristianLifeMinistryStudentMaterialDlg::PreTranslateMessage(MSG* pMsg)
{
    BOOL    bNoDispatch, bDealtWith;

    bDealtWith = FALSE;

    if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('I')))
    {
        if (EncodeText(pMsg->hwnd, _T("i")))
        {
            // Eat it.
            bNoDispatch = TRUE;
            bDealtWith = TRUE;
        }
    }
    else if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('B')))
    {
        if (EncodeText(pMsg->hwnd, _T("b")))
        {
            // Eat it.
            bNoDispatch = TRUE;
            bDealtWith = TRUE;
        }
    }

    if (!bDealtWith)
        bNoDispatch = CDialogEx::PreTranslateMessage(pMsg);

    return bNoDispatch;
}

Originally, I had 3 CEdit controls on my dialog. When you used this key press it performed an action as above on the selection in the edit controls.

I changed the controls from CEdit to CComboBox. They are editable type. I adjusted EncodeText to use GetEditSel and SetEditSel.

Only problem is now when I am editing text in the combo box. I select some of the text and press CTRL + I and nothing happens. The PTM of my dialog is not getting intercepted.

Visual Example

In this CEdit control I can select text:

Select Text

Then I use one of the hot keys, eg: CTRL + B and it still works:

Results for CEdit

But, when I select some text in the editable CComboBox and use the same hot key:

Use hot key on CComboBox

In this case it is not working.

I have assumed it is because technically I am inside a embedded "Edit" control of the combo. How do I still detect the hot keys now that I am using selected text inside a combo?

Community
  • 1
  • 1
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

2 Answers2

2

Not sure I like the WM_KEYDOWN hack. If you have real hot keys, I suggest you handle them correctly:

BEGIN_MESSAGE_MAP(CEncodedCombBox, CCombBox)
    ON_WM_HOTKEY()
END_MESSAGE_MAP()

void CEncodedCombBox::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
    if (nHotKeyId == idForHotKey_I)
        HandleCode(_T("i"));
    else if (nHotKeyId == idForHotKey_B)
        HandleCode(_T("b"));
}

void CEncodedCombBox::HandleCode(CString strCode)
{
    DWORD dwSel = GetEditSel();

    CMeetingScheduleAssistantApp::EncodeText(strText, strCode, LOWORD(dwSel), HIWORD(dwSel));
    SetWindowText(strText);
    SetEditSel(LOWORD(dwSel), HIWORD(dwSel) + 7);
}
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
l33t
  • 18,692
  • 16
  • 103
  • 180
  • Thanks. Interesting. But I can't see how I can use a hotkey approach here because the action must be performed on one of 4 edit/combo controls. But you have introduced my to a good concept I could use elsewhere. – Andrew Truckle Oct 19 '17 at 09:16
  • OK: Some questions: Do I have to use the 0x virtual key codes or can I use `_TINT(_T('X'))`. Do they end up the same values? Is one more efficient? Also, for the key ID values, is it Ok to just start at 1? – Andrew Truckle Oct 19 '17 at 09:54
  • The IDs have to be unique for a specific window. I believe you can start at 1. Using the value of the character is probably not as good (e.g. what if you later decide to add another 'X' bound hot key like Ctrl+Shift+X?. – l33t Oct 19 '17 at 10:48
  • Not sure I follow you. This is how I am registering my hotkeys: https://pastebin.com/TAhR8Dfg That OK? – Andrew Truckle Oct 19 '17 at 11:05
  • I suppose that's ok. However, in an `OnHotKey` handler it will be kind of tricky to get hold of the IDs to match. Not sure how you have implemented stuff, but maybe you can compare the `nHotKeyId` with `m_hWnd` (since you register the hotkey with window handles)? – l33t Oct 19 '17 at 11:11
  • Ah, maybe cross wires here. I have adopted your concept of hot keys elsewhere in my editor, for where they truly are hotkeys. But for the remaining key presses (as per my original question) I have stayed with PTM and the correct handle comparison. I had to because we only want those key sequences to fire for specific controls. I can't see we can do that with hotkeys. Don't worry. Thanks for teaching me a concept. – Andrew Truckle Oct 19 '17 at 11:26
0

I ended up creating a new class CEncodedCombBox, derived from CComboBox, like this:

// EncodedComboBox.cpp : implementation file
//

#include "stdafx.h"
#include "Meeting Schedule Assistant.h"
#include "EncodedComboBox.h"


// CEncodedComboBox

IMPLEMENT_DYNAMIC(CEncodedComboBox, CComboBox)

CEncodedComboBox::CEncodedComboBox()
{

}

CEncodedComboBox::~CEncodedComboBox()
{
}


BEGIN_MESSAGE_MAP(CEncodedComboBox, CComboBox)
END_MESSAGE_MAP()



// CEncodedComboBox message handlers


BOOL CEncodedComboBox::PreTranslateMessage(MSG* pMsg)
{
    BOOL    bNoDispatch, bDealtWith;
    DWORD   dwSel = GetEditSel();
    CString strCode = _T(""), strText;

    GetWindowText(strText);

    bDealtWith = FALSE;

    if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('I')))
    {
        strCode = _T("i");

        bNoDispatch = TRUE;
        bDealtWith = TRUE;
    }
    else if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('B')))
    {
        strCode = _T("b");

        bNoDispatch = TRUE;
        bDealtWith = TRUE;
    }

    if (bDealtWith)
    {
        CMeetingScheduleAssistantApp::EncodeText(strText, strCode, LOWORD(dwSel), HIWORD(dwSel));
        SetWindowText(strText);
        SetEditSel(HIWORD(dwSel) + 7, HIWORD(dwSel) + 7);
    }

    if (!bDealtWith)
        bNoDispatch = CComboBox::PreTranslateMessage(pMsg);

    return bNoDispatch;
}

As you can see, it includes a PreTranslateMessage and it works:

Hot keys now work

If there is a better way then I welcome your comments or answer.

Update

I had to test against the edit control handle and not to combo box handle for my own CDialog to work:

if (::GetParent(hWnd) == m_cbMaterialAssignment1.GetSafeHwnd())

No derived combo class needed any more.

Community
  • 1
  • 1
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • When this works. Set a breakpoint in your new PreTranslateMessage function. Continue debugging when a message arrives and your new PreTranslateMessage continues routing... You should finally step into the PreTranslateMessage of the dialog. When this works, it doesn't explain why the PreTranslateMessage in the dialog doesn't work. – xMRi Oct 19 '17 at 05:58
  • @xMRi I can't continue debugging because it says that `wincore.cpp` not found. – Andrew Truckle Oct 19 '17 at 07:51
  • A message in the debug output? That doesn't matter. You can always debug, as long as you have debug symbols for your code. This is just a warning, that you can't debug into the windows core... Debugging is essential... – xMRi Oct 19 '17 at 08:00
  • @xMRi Sorry, but I can't work out what you are asking me to do. I can set the break point. But then you said to continue debugging. I used F10 and that is where I got that message. Confused. – Andrew Truckle Oct 19 '17 at 08:15
  • PreTranslateMessage is called in a sequence: Starting from the window that should receive the message each parent get the message offered until one window says, I handle it, or there is no parent window any more... so when PTM is called now, It must work in the dialog too! That is what I want to tell you. Stepping out from PTM should lead you into the MFC core. Do you have the symbols loaded for the MFC. look into the Debug Windows under modules.If not get the PDB files for the MFC. You may need to define a symbol server. – xMRi Oct 19 '17 at 08:19
  • @xMRi I assume I do not have the symbols because the moment I step out of the PTM I get that message. Also, I get my PTM to return `TRUE` if you look to signal it is dealt with so I guess it would not cascade it back to the `CDialog` parent anyway. As for symbols, just checked my VC options for "Debug \ Symbols" and the options is unticked. – Andrew Truckle Oct 19 '17 at 08:25
  • Allow the symbols be loaded. That allows you to debug the MFC core. Interessting is a message where PTM return FALSE: Your dialog PTM MUST be called. – xMRi Oct 19 '17 at 08:35