SendInput не выполняет щелчок мышью, если я не перемещаю курсор
SendInput не выполняет щелчок мышью, если я не перемещаю курсор.
Я был бы признателен за помощь в этом, поскольку я, кажется, не могу обернуть вокруг себя голову.
У меня есть программа, которая выполняет щелчок мышью на окне переднего плана, в котором я использую SendInput для эмуляции щелчка левой кнопкой мыши.
Проблема заключается в том, что если я переместил курсор на позицию щелчка, чем SendInput сделает клик, однако, если я не перемещаю курсор, чем без щелчка, я даже передаю x и y указывает на MouseInputData. Я хотел бы выполнить щелчок левой кнопкой мыши без необходимости перемещения курсора вообще.
Bellow - это класс, который у меня есть (он довольно простой и стремительный)
namespace StackSolution.Classes
{
public static class SendInputClass
{
[DllImport("user32.dll", SetLastError = true)]
static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);
[DllImport("user32.dll")]
static extern bool SetCursorPos(int X, int Y);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetCursorPos(out Point lpPoint);
[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
public SendInputEventType type;
public MouseKeybdhardwareInputUnion mkhi;
}
[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdhardwareInputUnion
{
[FieldOffset(0)]
public MouseInputData mi;
[FieldOffset(0)]
public KEYBDINPUT ki;
[FieldOffset(0)]
public HARDWAREINPUT hi;
}
[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT
{
public ushort wVk;
public ushort wScan;
public uint dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
}
struct MouseInputData
{
public int dx;
public int dy;
public uint mouseData;
public MouseEventFlags dwFlags;
public uint time;
public IntPtr dwExtraInfo;
}
[Flags]
enum MouseEventFlags : uint
{
MOUSEEVENTF_MOVE = 0x0001,
MOUSEEVENTF_LEFTDOWN = 0x0002,
MOUSEEVENTF_LEFTUP = 0x0004,
MOUSEEVENTF_RIGHTDOWN = 0x0008,
MOUSEEVENTF_RIGHTUP = 0x0010,
MOUSEEVENTF_MIDDLEDOWN = 0x0020,
MOUSEEVENTF_MIDDLEUP = 0x0040,
MOUSEEVENTF_XDOWN = 0x0080,
MOUSEEVENTF_XUP = 0x0100,
MOUSEEVENTF_WHEEL = 0x0800,
MOUSEEVENTF_VIRTUALDESK = 0x4000,
MOUSEEVENTF_ABSOLUTE = 0x8000
}
enum SendInputEventType : int
{
InputMouse,
InputKeyboard,
InputHardware
}
public static void ClickLeftMouseButton(int x, int y)
{
INPUT mouseInput = new INPUT();
mouseInput.type = SendInputEventType.InputMouse;
mouseInput.mkhi.mi.dx = x;
mouseInput.mkhi.mi.dy = y;
mouseInput.mkhi.mi.mouseData = 0;
//getting current cursor location
Point p;
if (GetCursorPos(out p))
SetCursorPos(x, y);
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
//returning cursor to previous position
SetCursorPos(p.X, p.Y);
}
}
}
Функция Same ClickLeftMouseButton не будет щелкать, если я удаляю позицию курсора таким образом.
public static void ClickLeftMouseButton(int x, int y)
{
INPUT mouseInput = new INPUT();
mouseInput.type = SendInputEventType.InputMouse;
mouseInput.mkhi.mi.dx = x;
mouseInput.mkhi.mi.dy = y;
mouseInput.mkhi.mi.mouseData = 0;
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
}
Спасибо заранее.
Ответы
Ответ 1
При использовании функции SendInput
необходимо учитывать несколько вещей.
Если вы не укажете флаг MOUSEEVENTF_ABSOLUTE
, тогда dx
и dy
(структура MouseInputData) являются относительными координатами текущей позиции мыши. Если вы укажете MOUSEEVENTF_ABSOLUTE
, то dx
и dy
будут абсолютными координатами между 0 и 65535. Поэтому, если ваши координаты x и y являются координатами экрана, вы должны использовать следующую функцию для расчета dx
и dy
:
enum SystemMetric
{
SM_CXSCREEN = 0,
SM_CYSCREEN = 1,
}
[DllImport("user32.dll")]
static extern int GetSystemMetrics(SystemMetric smIndex);
int CalculateAbsoluteCoordinateX(int x)
{
return (x * 65536) / GetSystemMetrics(SystemMetric.SM_CXSCREEN);
}
int CalculateAbsoluteCoordinateY(int y)
{
return (y * 65536) / GetSystemMetrics(SystemMetric.SM_CYSCREEN);
}
Кроме того, прежде чем отправлять события MOUSEDOWN и MOUSEUP через SendInput, вы должны переместить мышь на элемент управления, на который вы хотите нажать:
public static void ClickLeftMouseButton(int x, int y)
{
INPUT mouseInput = new INPUT();
mouseInput.type = SendInputEventType.InputMouse;
mouseInput.mkhi.mi.dx = CalculateAbsoluteCoordinateX(x);
mouseInput.mkhi.mi.dy = CalculateAbsoluteCoordinateY(y);
mouseInput.mkhi.mi.mouseData = 0;
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE |MouseEventFlags.MOUSEEVENTF_ABSOLUTE;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
mouseInput.mkhi.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
SendInput(1, ref mouseInput, Marshal.SizeOf(new INPUT()));
}
В приведенном выше коде предполагается, что x
и y
являются пиксельными координатами экрана. Вы можете вычислить эти координаты для кнопки (цели) в winform, используя следующий код:
Point screenCoordsCentre=
button1.PointToScreen(new Point(button1.Width/2, button1.Height/2));
Надеюсь, это поможет.