I am trying to create a context menu that pops up when you right click a RichEdit. I know how to create the context menu, but I don't know how to check for when the user right-clicks RichEdit.

This is what I have:

case WM_CREATE:
             {
                 // Create RichEdit Control
                 // SetEventMask to ENM_MOUSEEVENTS
             }
             break;
        case WM_NOTIFY:
             {
                 if(((LPNMHDR)lParam)->code == EN_MSGFILTER && ((LPNMHDR)lParam)->idFrom == ID_CTRL_RTB)
                 {
                     if(((MSGFILTER*)LOWORD(lParam))->msg == WM_RBUTTONDOWN) // Im tried NM_RDOWN, but MSDN says it's not supported
                     {
                         MsgBox("You right clicked it", "info", MB_OK); // replace with context menu
                     }
                 }
             }
             break;

The thing is that I can't get the WPARAM and LPARAM from the MSGFILTER structure from EN_MSGFILTER. Is there a more simple way to track mouse clicks?

Dani AI

Generated

A simpler, more robust approach than parsing low‑level mouse notifications is to handle the standard WM_CONTEXTMENU (MFC wraps this as OnContextMenu, as shown by ). WM_CONTEXTMENU is sent for right‑clicks and for keyboard invocations (SHIFT+F10). The lParam contains screen coordinates (or is -1 for keyboard), so use that point for menu placement or call GetCursorPos when lParam == -1.

When showing the popup, pass screen coordinates to TrackPopupMenu / TrackPopupMenuEx. Call SetForegroundWindow on the owner window before tracking the menu and then post a WM_NULL after the call; this sequence prevents focus/command routing problems that otherwise make menu commands behave oddly. If the menu items operate on the text under the pointer, convert the screen point to the RichEdit client, map the point to a character index, and set the selection (so copy/cut/etc. target the clicked text) before displaying the menu.

Use EN_MSGFILTER (the approach demonstrated) only when raw mouse events are required (for example, you need WM_RBUTTONDOWN specifically). If the parent never sees WM_CONTEXTMENU (some controls handle it internally), subclass the RichEdit and intercept WM_CONTEXTMENU or WM_RBUTTONUP, then forward/show the menu from there.

Quick troubleshooting checklist:

  • Extract coords with GET_X_LPARAM/GET_Y_LPARAM to avoid sign issues and remember they are screen coords.
  • Convert to control client coords with ScreenToClient before mapping to text.
  • Pass the control/owner HWND to TrackPopupMenu so commands route correctly.

Following these steps avoids fragile MSGFILTER parsing and gives consistent, expected context‑menu behavior for RichEdit controls.

Recommended Answers

All 3 Replies

I have done the similar thing in MFC ,
we can specify the right click option while tool tip
creation only .

OnContextMenu(CWnd* pWnd, CPoint point)
{
    VERIFY(mMainMenu.CreatePopupMenu());
    // Adding menu item
    mMainMenu.AppendMenu(MF_ENABLED,IDD_UPDATE,"UPDATE");
    .
    .
    .
    mMainMenu.TrackPopupMenu(TPM_RIGHTBUTTON ,point.x,point.y,this);
    mMainMenu.DestroyMenu();
}

What we can do is to get the Crect [ cpoint ] of richedit box on the dialog,
compare with the acutal piont then display the menu.
But i havent worked with win32 this is its done in MFC, hope this will help u.

The following should work ...

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
  case WM_CREATE:

  // ... create the richedit window here -> hWndRichEdit  
  // set event mask ...
  SendMessage(hWndRichEdit, EM_SETEVENTMASK, (WPARAM)0 (LPARAM)ENM_MOUSEEVENTS);
  break;

  case WM_NOTIFY:
  {
    const MSGFILTER * pF = (MSGFILTER *)lParam;

    if(pF->nmhdr.hWndFrom == hWndRichEdit)
    {
      if(pF->msg == WM_RBUTTONDOWN)
      {
        // got WM_RBUTTONDOWN from the richedit window
      }
    }
  }
  break;

  }

  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

The following should work ...

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch (uMsg)
  {
  case WM_CREATE:

  // ... create the richedit window here -> hWndRichEdit  
  // set event mask ...
  SendMessage(hWndRichEdit, EM_SETEVENTMASK, (WPARAM)0 (LPARAM)ENM_MOUSEEVENTS);
  break;

  case WM_NOTIFY:
  {
    const MSGFILTER * pF = (MSGFILTER *)lParam;

    if(pF->nmhdr.hWndFrom == hWndRichEdit)
    {
      if(pF->msg == WM_RBUTTONDOWN)
      {
        // got WM_RBUTTONDOWN from the richedit window
      }
    }
  }
  break;

  }

  return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

Thank you, thank you, thank you, thank you, THANK YOU!!! I have been busting my hump trying to figure this out. Thanks for the help. :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.