I want to show standard "pointer" cursor instead of "text-selection cursor" (shown in the picture below) in RichEdit:
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:
- @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.
- @Jeaninez. I have already set the
ES_READONLY
property, it does not affect neither cursor, nor selection (the latter I solved by intercepting theEN_SELCHANGE
notifications). - @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.