2

I've got this code:

[DllImport("user32.dll")]
static extern void mouse_event(uint dwFlags, uint dx, uint dy, uint dwData, UIntPtr dwExtraInfo);

[Flags]
public enum MouseEventFlags
{
    Move = 0x0001,
    LeftDown = 0x0002,
    LeftUp = 0x0004,
    RightDown = 0x0008,
    RightUp = 0x0010,
    MiddleDown = 0x0020,
    MiddleUp = 0x0040,
    Absolute = 0x8000
}

public void SimMouseEvent(MouseEventFlags e, int x, int y)
{
    mouse_event((uint)e, (uint)x, (uint)y, 0, UIntPtr.Zero);
}

public void SimLeftClick(int x, int y)
{
    SimMouseEvent(MouseEventFlags.LeftUp | MouseEventFlags.RightUp, x, y);
}

My form looks like this:

When you click "Button" it runs this:

private void button3_Click(object sender, RoutedEventArgs e)
{
    SimLeftClick(50, 50);
}

And on my Window I also have this:

private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    MessageBox.Show("click");
}

When I click the window it says "click" as expected, but when I click "Button" it doesn't seem to do anything.

Are the coordinates absolute, or relative? What about with multiple monitors? Do they only work on the focused application?

I would expect that 50,50 to either hit my window somewhere and trip the "click" handler or click on some random window because it missed my app completely and focus that instead... why isn't anything happening?

mpen
  • 272,448
  • 266
  • 850
  • 1,236

2 Answers2

2

You handle a mouse button down message, but send a mouse button up message. A click needs to be button down followed by the same button up.

The coordinates are ignored, because you didn't pass the Move flag.

Try reading the documentation.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • I looked at that, but couldn't figure it out. I think I had it as LeftDown|LeftUp but then messed it up somewhere along the line. Seems to work now. Thanks! – mpen Jan 30 '12 at 01:00
  • To be fair, the documentation is horrendously awful; it doesn't say that `MOUSEEVENTF_MOVE` is needed. – Ian Boyd Jan 30 '12 at 03:50
  • @Ian: "If the mouse has moved, indicated by `MOUSEEVENTF_MOVE` being set, *`dx`* and *`dy`* hold information about that motion." – Ben Voigt Jan 30 '12 at 04:04
  • @BenVoigt: "dx [in] Type: DWORD The mouse's absolute position along the x-axis or its amount of motion since the last mouse event was generated, depending on the setting of MOUSEEVENTF_ABSOLUTE. Absolute data is specified as the mouse's actual x-coordinate; relative data is specified as the number of mickeys moved. A mickey is the amount that a mouse has to move for it to report that it has moved." – Ian Boyd Jan 30 '12 at 16:43
  • @Ian: But mainly I was assuming that a .NET developer didn't know about the Win32 API documentation, and was probably getting the p/invoke signature from either pinvoke.net or some blog, either of which would have even less information than the MSDN page I linked. – Ben Voigt Jan 30 '12 at 16:57
1

Fixed, with Ben's suggestions.

public void SimLeftClick(int x, int y)
{
    var scr = Screen.PrimaryScreen.Bounds;
    SimMouseEvent(MouseEventFlags.LeftDown | MouseEventFlags.LeftUp | MouseEventFlags.Move | MouseEventFlags.Absolute,
        (int)(x / (double)scr.Width * 65535),
        (int)(y / (double)scr.Height * 65535));
}
mpen
  • 272,448
  • 266
  • 850
  • 1,236