0
votes

I'm working on an application that smoothens the movement of the mouse cursor so one could draw pretty curvy lines using an ordinary mouse in drawing apps (such as MS Pain, SAI, etc.). However, I wouldn't like my application to actually move the mouse cursor because its position is used in the smoothening process. That means I'd have to make the drawing app ignore the actual position of the mouse cursor and provide it with the position of the fake, smoothily moving mouse cursor.

Do you have any ideas on accomplishing that?


My idea was to get the target window's handler, disable it (because it disables input, so when I move my mouse, Windows won't announce it to the window), send a WM_LBUTTONDOWN, series of WM_MOUSEMOVEs, and WM_LBUTTONUP message, then enable the window again in order to get the desired result.

I quickly put some code together, but it didn't function properly. Then I noticed something odd. I took away the code which disabled the window, as well as the WM_MOUSEMOVE messages. The remaining code was supposed to do a simple click inside the target window. However, in most cases, it didn't. When I tried to click on MSPaint's canvas with it, nothing happened, but the SendMessage returned 0. But when I tried to click inside the VS2013 or the Google Chrome window, it worked perfectly. (So now what?)

The simplified code was the following:

[DllImport("user32.dll", EntryPoint = "FindWindowA", SetLastError = true)]
static extern IntPtr FindWindow(IntPtr lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(IntPtr hWnd, int msg, int WParam, int LParam);

void ClickInsideAnotherWindow(string windowTitle, Point clickPos)
{
    IntPtr hWnd = FindWindow(IntPtr.Zero, windowTitle);

    //MSDN said:
    //The low-order word specifies the x-coordinate of the cursor.
    //The high-order word specifies the y-coordinate of the cursor.  
    //
    //The following line of code does the trick by shifting 
    //the Y coordinate by 16 and ORing it with the X coordinate.

    int lParam = ((clickPos.Y << 16) | clickPos.X);

    SendMessage(hWnd, 0x0201, 0, lParam);
    System.Threading.Thread.Sleep(10); //Wait 10ms, just to be sure...
    SendMessage(hWnd, 0x0202, 0, lParam);

    //0x201 is equivalent to WM_LBUTTONDOWN, while
    //0x202 is equivalent to WM_LBUTTONUP
}


So I would like to send mouse events to a window manually, while it ignores the real cursor position.

I'm coding mostly in C#, but if it's easier to get this working in C++, I'll use it (and probably make a dll, if that's the case). I'm sorry if I was hard to follow, I tried to explain this as best as I could.

Please help me solve this!

1
You are asking for a time machine. One that can predict which way the user is going to move his mouse. That doesn't make sense. You can only smooth a curve after you obtained the raw one. - Hans Passant
@HansPassant No, not really. You probably didn't understand my problem. There is a point slowly crawling itself towards my cursor :) (I already have that part working, it's simple linear interpolation) I don't want to predict anything, I just want to use that point as a virtual cursor instead of the 'real' one. - Techie

1 Answers

0
votes

When using Send/PostMessage, some window must be at foreground, some window must have focus.

In some application with DirectX or something with special screen drawing method, the window must below the mouse pointer. Just below, not foreground.

I don't know this is exactly why.

You may have a try AttachThreadInput and SetForegroundWindow/SwitchToThisWindow and SetFocus, with some of the three combination, it should work.