Question

I'm doing a (custom drawn) custom contol in C# (Windows.Forms). Mouse cursor shape should depends on what part of my custom control is currently under cursor. (Let me call it "dynamic cursor": I mean that cursor depends not only on what Control is under the cursor, but also on mouse coordinates.)

When using WinAPI, I've thought that WM_SETCURSOR should be used as a proper way:

//pseusocode
if(uMsg == WM_SETCURSOR) {
    if((HWND)wParam == hwnd) {
        POINT point;
        GetCursorPos(&point);
        ScreenToClient(hwnd, &point);
        if(point.Y < ...) SetCursor(...);
        else if(point.Y < ...) SetCursor(...);
        else SetCursor(...);
        return true;
    }
    else return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

So, in C#, I hoped I I'll do smth like this:

protected override void OnNeedToSetCursor(NeedToSetCursorEventArgs e) {
    if(...) Cursor.Current = ...;
    else if(...) Cursor.Current = ...;
    else Cursor.Current = ...;
}

However, there is no such event or overridable method in Control.

Thus, the question is: What is a proper way to implement such "dynamic" cursor in WinForms?

  1. Should I just override OnMouseMove:

    protected override void OnMouseMove(MouseEventArgs e) {
        if(e.Y < ...) Cursor.Current = ...;
        else if(e.Y < ...) Cursor.Current = ...;
        else Cursor.Current = ...;
    
        base.OnMouseMove(e);
    }
    
  2. Or should I fallback to overriding WndProc:

    protected override void WndProc(ref Message m) {
        if(m.Msg == 0x0020/*WM_SETCURSOR*/) {
            if(...) Cursor.Current = ...;
            else if(...) Cursor.Current = ...;
            else Cursor.Current = ...;
    
            m.Result = new IntPtr(-1);
        }
        else base.WndProc(ref m);
    }
    

P.S.:

Please don't answer something like: "choose yourself" or "I more like this way". Because this is not matter of individual preference, this is matter of correctness.

If both ways are correct, please say "Both ways are correct". If only one way is correct, please explain why other way is incorrect. If both methods "will work", but one of them has some advantages/disadvantages (for example: "mouse-move way has greater performance overhead", or "WM_MOUSEMOVE message is not dedicated for that, thus using mouse-move way will set cursor shape too late; i.e. when mouse moves (125,19)->(125,20)->(125,21) and I set cursor shape to NS_SIZE in (125,20) it will change only in (125,21)"), please tell that.

P.P.S.: I'm disappointed in this site. What idiot could ever think that this question is opinion-based? Has he read "P.S."? Has he read the correct answer?

Was it helpful?

Solution

The correct answer is:

Only WM_SETCURSOR (but not OnMouseMove) can be used in this case.

Using Cursor.Current = ... in OnMouseMove will cause persistent cursor flickering.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top