Reputation: 11615
I am trying to automatically draw in a program similar to paint by simulating mouse movement and clicks with user32.dll in Windows 7.
Here's what I have and how I use it:
[DllImport("user32.dll")]
static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
[Flags]
public enum MouseEventFlags
{
LEFTDOWN = 0x00000002,
LEFTUP = 0x00000004,
MIDDLEDOWN = 0x00000020,
MIDDLEUP = 0x00000040,
MOVE = 0x00000001,
ABSOLUTE = 0x00008000,
RIGHTDOWN = 0x00000008,
RIGHTUP = 0x00000010
}
public void LeftMouseDown()
{
mouse_event((int)(MouseEventFlags.LEFTDOWN), Cursor.Position.X, Cursor.Position.Y, 0, 0);
}
public void LeftMouseUp()
{
mouse_event((int)(MouseEventFlags.LEFTUP), Cursor.Position.X, Cursor.Position.Y, 0, 0);
}
foreach (var contour in contours)
{
LeftMouseDown();
foreach (var point in contour)
{
var x = point.X + offsetX;
var y = point.Y + offsetY;
Cursor.Position = new Point(x, y);
//LeftMouseDown();
System.Threading.Thread.Sleep(2);
}
LeftMouseUp();
}
What I'm trying to simulate is the mouse being clicked and held, moved around to a bunch of points in each contour
and then let up before moving on to the next contour
.
The problem, is that this just holds the mouse button down for the first movement and then lets it up.
How can I keep the mouse left click down when the mouse is being moved around programatically?
I am trying to simulate drawing in a third party app. (Microsoft LINQ's Whiteboard, the IM client.)
Upvotes: 2
Views: 2621
Reputation: 12430
A late response, but I think the mistake you have is in calling mouse_event
. Basically, mouse_event
reports relative mouse movement (when without MOUSEEVENTF_ABSOLUTE
) but you pass absolute position thus making it act wrongly. Also, you should move the cursor to the position to press down the mouse button before performing mouse down.
So here's my fix:
// I changed a bit of the method signature, but that doesn't really matter
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
static extern void mouse_event(MouseEventFlags flags, uint dx, uint dy, uint delta, IntPtr extraInfo);
[Flags]
enum MouseEventFlags : uint
{
Absolute = 0x8000,
LeftDown = 0x0002,
LeftUp = 0x0004,
MiddleDown = 0x0020,
MiddleUp = 0x0040,
Move = 0x0001,
RightDown = 0x0008,
RightUp = 0x0010,
Wheel = 0x0800,
XDown = 0x0080,
XUp = 0x0100,
HWheel = 0x1000,
}
public void LeftMouseDown()
{
// Simulate left down, notice that RELATIVE movement is 0
mouse_event(MouseEventFlags.LeftDown, 0, 0, 0, IntPtr.Zero);
}
public void LeftMouseUp()
{
// Simulate left up, notice that RELATIVE movement is 0 too
mouse_event(MouseEventFlags.LeftUp, 0, 0, 0, IntPtr.Zero);
}
And when moving mouse...
foreach (var contour in contours)
{
// simulate mouse down AFTER cursor is moved to the first point (IMPORTANT!)
var x = contour[0].X + offsetX;
var y = contour[0].Y + offsetY;
Cursor.Position = new Point(x, y);
LeftMouseDown();
foreach (var point in contour)
{
x = point.X + offsetX;
y = point.Y + offsetY;
Cursor.Position = new Point(x, y);
System.Threading.Thread.Sleep(2);
}
// cursor is already at the final position
LeftMouseUp();
}
And a side-note, via some simple testing, setting Cursor.Position
does generate WM_MOUSEMOVE
message.
Upvotes: 1
Reputation: 942020
Summarizing the comment trail: this has not the expected result because the code only simulates mouse clicks, not mouse motion. Moving the cursor with Cursor.Position directly changes the cursor position, bypassing the Windows input event queue. So doesn't generate any notifications (WM_MOUSEMOVE messages) to the window that has the focus.
Fix by adding a MouseMove() method to the helper class that uses mouse_event() with MouseEventFlags.MOVE
Upvotes: 2