Search code examples
c#imagecursor

Changing cursor shape to have the copy cursor shape


I know that when doing drag-drop I can do something like

private void Form_DragOver(object sender, DragEventArgs e)
{
    e.Effect = DragDropEffects.Copy;
}

to make the cursor have a plus image meaning copy. I am just wondering if I can do this when I am not doing drag-drop (for example when the user clicks a specific place the cursor changes to this style until the user clicks somewhere else). I tried using Cursor = Cursors.<style> but it does not contain this. Any ideas ?


Solution

  • This is quite difficult to do unless you want to display a wait cursor. A special case, handled by the Application.UseWaitCursor property. The problem is that every control by itself affects the cursor shape, as selected by its Cursor property. A TextBox for example will insist on changing the shape to an I-bar.

    You are somewhat ahead by only wanting this to do between two clicks. Some trickery is possible in that case, you can capture the mouse when the button is clicked so that the cursor shape is solely controlled by the button. A hack is required when the user clicks the mouse again, that click will go to the same button and not whatever control is clicked. That needs to be fixed by synthesizing another click. This sample code gets this done:

        bool CustomCursorShown;
    
        private void button1_MouseUp(object sender, MouseEventArgs e) {
            if (button1.DisplayRectangle.Contains(e.Location)) {
                this.BeginInvoke(new Action(() => {
                    CustomCursorShown = true;
                    button1.Cursor = Cursors.Help;   // Change this to the cursor you want
                    button1.Capture = true;
                }));
            }
        }
    
        private void button1_MouseDown(object sender, MouseEventArgs e) {
            if (CustomCursorShown) {
                var pos = this.PointToClient(button1.PointToScreen(e.Location));
                var ctl = this.GetChildAtPoint(pos);
                if (ctl != null && e.Button == MouseButtons.Left) {
                    // You may want to alter this if a special action is required
                    // I'm just synthesizing a MouseDown event here...
                    pos = ctl.PointToClient(button1.PointToScreen(e.Location));
                    var lp = new IntPtr(pos.X + pos.Y << 16);
                    // NOTE: taking a shortcut on wparam here...
                    PostMessage(ctl.Handle, 0x201, (IntPtr)1, lp);
                }                 
            }
            button1.Capture = false;
        }
    
        private void button1_MouseCaptureChanged(object sender, EventArgs e) {
            if (!button1.Capture) {
                CustomCursorShown = false;
                button1.Cursor = Cursors.Default;
            }
        }
    
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private extern static IntPtr PostMessage(IntPtr hwnd, int msg, IntPtr wp, IntPtr lp);