public static void SendMouseInput( double x, double y, int data, SendMouseInputFlags flags )
{
//CASRemoval:AutomationPermission.Demand( AutomationPermissionFlag.Input );
int intflags = (int) flags;
if( ( intflags & (int)SendMouseInputFlags.Absolute ) != 0 )
{
int vscreenWidth = SafeNativeMethods.GetSystemMetrics( SafeNativeMethods.SM_CXVIRTUALSCREEN );
int vscreenHeight = SafeNativeMethods.GetSystemMetrics( SafeNativeMethods.SM_CYVIRTUALSCREEN );
int vscreenLeft = SafeNativeMethods.GetSystemMetrics( SafeNativeMethods.SM_XVIRTUALSCREEN );
int vscreenTop = SafeNativeMethods.GetSystemMetrics( SafeNativeMethods.SM_YVIRTUALSCREEN );
// Absolute input requires that input is in 'normalized' coords - with the entire
// desktop being (0,0)...(65535,65536). Need to convert input x,y coords to this
// first.
//
// In this normalized world, any pixel on the screen corresponds to a block of values
// of normalized coords - eg. on a 1024x768 screen,
// y pixel 0 corresponds to range 0 to 85.333,
// y pixel 1 corresponds to range 85.333 to 170.666,
// y pixel 2 correpsonds to range 170.666 to 256 - and so on.
// Doing basic scaling math - (x-top)*65536/Width - gets us the start of the range.
// However, because int math is used, this can end up being rounded into the wrong
// pixel. For example, if we wanted pixel 1, we'd get 85.333, but that comes out as
// 85 as an int, which falls into pixel 0's range - and that's where the pointer goes.
// To avoid this, we add on half-a-"screen pixel"'s worth of normalized coords - to
// push us into the middle of any given pixel's range - that's the 65536/(Width*2)
// part of the formula. So now pixel 1 maps to 85+42 = 127 - which is comfortably
// in the middle of that pixel's block.
// The key ting here is that unlike points in coordinate geometry, pixels take up
// space, so are often better treated like rectangles - and if you want to target
// a particular pixel, target its rectangle's midpoint, not its edge.
x = ( ( x - vscreenLeft ) * 65536 ) / vscreenWidth + 65536 / ( vscreenWidth * 2 );
y = ( ( y - vscreenTop ) * 65536 ) / vscreenHeight + 65536 / ( vscreenHeight * 2 );
intflags |= UnsafeNativeMethods.MOUSEEVENTF_VIRTUALDESK;
}
UnsafeNativeMethods.INPUT mi = new UnsafeNativeMethods.INPUT();
mi.type = UnsafeNativeMethods.INPUT_MOUSE;
mi.union.mouseInput.dx = (int) x;
mi.union.mouseInput.dy = (int)y;
mi.union.mouseInput.mouseData = data;
mi.union.mouseInput.dwFlags = intflags;
mi.union.mouseInput.time = 0;
mi.union.mouseInput.dwExtraInfo = new IntPtr( 0 );
//Console.WriteLine("Sending");
if( UnsafeNativeMethods.SendInput( 1, ref mi, Marshal.SizeOf(mi) ) == 0 )
throw new Win32Exception(Marshal.GetLastWin32Error());
}