1

I want to show standard "pointer" cursor instead of "text-selection cursor" (shown in the picture below) in RichEdit:

enter image description here

The only way I see now is to intercept WM_SETCURSOR message in my window, determine wether cursor is inside RichEdit control, and replace it with "normal" cursor. Besides it's not so cool, I want to keep a "hand" cursor, which appears when cursor points to a link.

Is there an easier method?

UPDATE: Some clarifications for comments:

  1. @Remy Lebeau. Actually I just want to display text with some formatting abilities: automatic words wrapping, different colors for some symbols inside the same text, hyperlinks, and may be - displaying images. And I want to get this text from the internet, display this text in a single control, also it's quitу comfortable to create such a text in RTF-editor, like WordPad. However the information shown in RichEdit is not intended to be edited or copied, and app design looks better without "text-selection" cursor. So, I think that RichEdit is what I need. But, of course, you can suggest something else.
  2. @Jeaninez. I have already set the ES_READONLY property, it does not affect neither cursor, nor selection (the latter I solved by intercepting the EN_SELCHANGE notifications).
  3. @Barmak Shemirani. Yes, I can process hyperlinks. Here is the code snippet I use now to handle cursor changing:
    // This method processes the WM_SETCURSOR message.
    LRESULT MainWindow::OnSetCursor(WPARAM wParam, LPARAM lParam) {
        auto h = (HWND)wParam;
        if (h == richEditHwnd) {
            return TRUE; // Prevents cursor changes by next processors
        }
        return DefWindowProc(mainWindowHandle, WM_SETCURSOR, wParam, lParam);
    }

UPDATE 2: As Barmak Shemirani pointed out in comment, the ENLINK notification may be caused by mouse events, so now I have almost working solution (however I don't understand exactly how it works):

The WM_SETCURSOR handler:

LRESULT MainWindow::OnSetCursor(WPARAM wParam, LPARAM lParam)
{
    auto h = (HWND)(wParam);
    if (rich.hwnd == h) {
        if (HIWORD(lParam) == WM_MOUSEMOVE || HIWORD(lParam) == WM_LBUTTONDOWN || HIWORD(lParam)== WM_LBUTTONDBLCLK) {
            DefWindowProc(windowHandle, WM_SETCURSOR, wParam, lParam);
            auto cursor = LoadCursor(NULL, IDC_ARROW);
            SetClassLongPtr(rich.hwnd, GCLP_HCURSOR, (LONG_PTR)cursor);
            return true;
        }
    }                

    return DefWindowProc(windowHandle, WM_SETCURSOR, wParam, lParam);
}

The EM_LINK notification handler:

    auto enLink = (ENLINK*)lParam;
    if (enLink->msg == WM_LBUTTONUP) {
        std::wstring linkId(enLink->chrg.cpMax - enLink->chrg.cpMin, L'0');
        TEXTRANGE textRange{enLink->chrg, (LPTSTR)linkId.data()};
        SendMessage(nmHeader->hwndFrom, EM_GETTEXTRANGE, NULL, reinterpret_cast<LPARAM>(&textRange));
        ProcessLinkClick(enLink, linkId);
    }
    else if (enLink->msg == WM_MOUSEMOVE || enLink->msg == WM_LBUTTONDBLCLK || enLink->msg == WM_LBUTTONDOWN) {
        auto cursor = LoadCursor(NULL, IDC_HAND);
        SetClassLongPtr(enLink->nmhdr.hwndFrom, GCLP_HCURSOR, (LONG_PTR)cursor);
        return TRUE;
    }

    return 0;

This code works properly for WM_MOUSEMOVE and WM_LBUTTONDOWN LPARAM arguments, but fails on WM_LBUTTONDBLCLK argument.

UPDATE 3: It seems that I rushed with previous code - it somehow blocks the WM_LBUTTONUP message for EM_LINK notification, so I cann't properly handle clicks on link.

qloq
  • 689
  • 1
  • 5
  • 15
  • 1
    Why do you want this? Displaying a text cursor when the mouse is over a text input field is standard UI behavior, and is what users expect. Why do you want to change that? – Remy Lebeau Nov 04 '21 at 16:49
  • Maybe you want to add the style `ES_READONLY`. It would make sense to have the hand cursor over hyperlink in a read-only richedit control. Have you managed hyperlink redirection yet? I should be a similar method. Show the code, or at least part of the code that you are using. – Barmak Shemirani Nov 04 '21 at 17:54
  • According to your description, whether you want to make the richedit not to select? If so , I suggest you could try to use [EM_SETREADONLY message](https://learn.microsoft.com/en-us/windows/win32/controls/em-setreadonly) to set the read-only style of the edit control. – Jeaninez - MSFT Nov 05 '21 at 02:29
  • Commenters are not notified when you put @user in the question. I meant what do you have in `WM_NOTIFY` – Barmak Shemirani Nov 05 '21 at 12:01

1 Answers1

0

This is a comment, it doesn't answer the question

Don't override WM_SETCURSOR, let RichEdit handle it and "Hand" cursor should show automatically for hyperlinks.

You can override the cursor and force it to use the "Arrow" cursor. But richedit will no longer show the "Hand" cursor for hyperlinks (because of the override) This override can be done as follows:

hcursor = LoadCursor(nullptr, MAKEINTRESOURCE(IDC_ARROW));
...
case WM_SETCURSOR:
{
    if (hrichedit == (HWND)wparam) { SetCursor(hcursor); return TRUE; }
    break;
}

Otherwise we have to find out when mouse is over hyperlink. I don't know how to do that smoothly.

In theory we can catch WM_NOTIFY messages for mousemove, when we go in/out of the link, but I had trouble getting that right.

Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77