WPF: drawing own cursor - nontrivial problem

2020-07-30 06:58发布

问题:

i need to implement a cursor with some very specific features:

  • it has to be animated
    • because after n seconds it automatically clicks - so the animation is feedback for the user when the click will happen
  • it has to snap to some of our controls
  • it has to work outside of our application

the approaches so far:

  • render my WPF-control into a bitmap, make a cursor-struct out of it and use user32.dll/SetSystemCursor to set it
    • PRO
    • the cursor has no delay after the mouse since it's a real cursor
    • CON
    • snapping is quite hard, especially since we have absolute and relative inputdevices and i would have to reset the mouseposition all the time or use user32.dll/ClipCursor (System.Windows.Forms.Cursor.Clip does the same) but the snapped cursor is always shaking around the snapped position (tries to escape, get's reset again....)
    • the code i use throws strange exceptions after some random time - so my current code seems quite unstable
  • render my own cursor into a maximized, topmost, allowtransparent, windowstyle=none, invisible window and manually move the cursor after the mouse (like Canvas.SetLeft(cursor, MousePosition.X))
    • PRO
    • snapping can be (easily) done
    • CON
    • when the mouse clicks and hit's the cursor the cursor get's clicked and not the window beyond
    • polling the mouseposition in a dispatcher-background-loop all the time doesn't seem very beautiful to me

to solve the second approach my cursor would have to have at least one transparent pixel in the hotspot, so that the mouse can click through... that doesn't seem like a real solution to me...

any idea's anyone?

EDIT: some example-source to show the problems...:

example app & source to show the problem with snapping the mouse to a fixed position: ClipIt.rar

example app & source that fails after random time - setting a self-drawn cursor: TryOwnCur.rar

can be found under: http://sourcemonk.com/Cursor

回答1:

thanks to http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a3cb7db6-5014-430f-a5c2-c9746b077d4f

i can click through my self-drawn cursor which follows the mouse-position by setting the window style:none, and allowtransparent as i already did and then

public const int WS_EX_TRANSPARENT = 0x00000020;
  public const int GWL_EXSTYLE = (-20);

  [DllImport("user32.dll")]
  public static extern int GetWindowLong(IntPtr hwnd,
  int index);

  [DllImport("user32.dll")]
  public static extern int SetWindowLong(IntPtr hwnd,
  int index, int newStyle);

  public static void makeTransparent(IntPtr hwnd) {
     int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
     SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
  }

and call makeTransparent from OnSourceInitialized...