0

I am trying to implement ctrl+A in note edit control :m_editNoteTypeView" which is instance of cEdit inside class NoteDialog. My note edit is created like below.

NoteDialog::initDialog()
{
    m_editNoteTypeView.CreateEx(::GetWindowLong(m_editSubject.m_hWnd, GWL_EXSTYLE), "edit", "", dwStyle | ES_READONLY, CRect(0, 0, 0, 0), this, 0);
    m_editNoteTypeView.SetSel(0,-1,TRUE);
}

NoteDialog class is derived from another class named Sdialog which is finally derived from CDialog.

I have defined PreTranslateMessage(MSG* pMsg) in SDialog but control is not going to PreTranslateMessage ,hence my I am unable to check which key I am pressing on keboard when I am typing on note edit.

bool Sdialog::PreTranslateMessage(MSG* pMsg)
{
    if (GetFocus() == this) 
    {
        if (pMsg->message == WM_CHAR)
        {
            if ((LOWORD(pMsg->wParam) & VK_CONTROL) == VK_CONTROL)
            {
                //SetSel(0, -1);
            }
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164

1 Answers1

1

return type for PreTranslateMessage should be BOOL, otherwise you get a compile error in MFC.

if (pMsg->message == WM_CHAR)
    if ((LOWORD(pMsg->wParam) & VK_CONTROL) == VK_CONTROL)
        {...}

WM_CHAR message doesn't carry VK_CONTROL in wParam.

To intercept Ctrl + A:

  • Wait for WM_KEYDOWN message
  • Check for A key
  • Check if Ctrl key is pushed down

Thus:

BOOL Sdialog::PreTranslateMessage(MSG* pMsg)
{
    static int i = 0;
    CString s;

    if(pMsg->message == WM_KEYDOWN)
    {
        if(GetKeyState(VK_CONTROL) & 0x8000)
        {
            if(pMsg->wParam == 'A')
            {
                ...
            }
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}

In addition you could add these helper macros:

// Handy functions
#define IsCTRLpressed()  ( GetKeyState(VK_CONTROL) & 0x8000 )
#define IsSHIFTpressed()  ( GetKeyState(VK_SHIFT) & 0x8000 )
//15 = sizeof(SHORT) * 8 - 1
//0000 0000 0000 0001 = 1
//1000 0000 0000 0000 = 15 << 1

Then it can be as simple as:

if (IsCTRLpressed() &&
    pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('A')))
{
    // Do whatever

    // Eat it.
    bNoDispatch = TRUE;
    bDealtWith = TRUE;
}

Keep in mind that you have to decide if you still want to run the base implementation. If you actually handle the message yourself and deal with it then you should return TRUE. Otherwise, let the base class handle it.

Example:

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

    bDealtWith = FALSE;

    if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('A')))
    {
        // Deal with it

        // Eat it.
        bNoDispatch = TRUE;
        bDealtWith = TRUE;
    }

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

    return bNoDispatch;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
  • @AndrewTruckle I think that meant to be `0x8000 = 15 << 1` , not `0x1E = 1 << 15` – Barmak Shemirani Nov 19 '17 at 16:46
  • The code was taken from the CodeProject `CGridCtrl` class data files by Chris Maunder. – Andrew Truckle Nov 19 '17 at 17:29
  • @AndrewTruckle I wrote it wrong again even in the edit. I meant to write `(GetKeyState(VK_CONTROL) & (15 << 1))`, but that's still unnecessarily confusing, just use `GetKeyState(VK_CONTROL) & 0x8000` or `GetKeyState(VK_CONTROL) < 0` this checks the high order bit, as stated in documentation. `1 << (sizeof(SHORT)*8 - 1)` is wrong. – Barmak Shemirani Nov 19 '17 at 20:31
  • Sure. I won’t argue it. The point is you can put that check in a simple macro or inline method that is easier to read and thus only one place to maintain code. No worries. – Andrew Truckle Nov 19 '17 at 22:37
  • Thanks for your answer. – Bijay Kumar Nov 20 '17 at 09:16
  • Thanks a lot for your answer. I have modified the code and tried the same but issue here is when I try to debug, the control flow doesn't reach the preTranslateMessage method inside Sdialog.cpp. – Bijay Kumar Nov 20 '17 at 09:23
  • 1
    In your first code sample you are using `GetAsyncKeyState()` but later you switch to `GetKeyState()`. The latter is the correct one to use as you want the [keys state at the time the input message was send, instead of the keystate at this very instant](https://blogs.msdn.microsoft.com/oldnewthing/20041130-00/?p=37173). – zett42 Nov 20 '17 at 10:05
  • Also, there is absolutely no need for macros here. Instead we can write `inline bool IsCTRLpressed() { return (GetKeyState(VK_CONTROL) & 0x8000) != 0); }`. – zett42 Nov 20 '17 at 10:25
  • `preTranslateMessage`... @BijayKumar In your question and comments you are using the wrong case, if your code is `bool preTranslateMessage` then it's not going to receive any message. – Barmak Shemirani Nov 20 '17 at 18:59
  • 2
    @BijayKumar Such errors can easily be detected at compile time by adding the [`override` specifier](http://en.cppreference.com/w/cpp/language/override) to the declaration of your function in the header file. The compiler will complain if there is a signature mismatch between your function and the function of the base class you want to override. One of the best additions of C++11 which should always be used. – zett42 Nov 20 '17 at 19:18