При работе с P/Invoke функциями Windows API первое, что надо сделать - это почитать документацию, внимательно. Второе - надо следить за тем, что структура маршалируется правильно.
Монитор может гаснуть от того, что Windows воспринимает ваш ввод неверно, например как какой-нибудь жест мышью (любое непредскажуемое поведение), который может даже экран перевернуть вверх ногами, я уж не знаю, как у вас настроена система.
У меня есть готовый код для формирования ввода в SendInput, и для клавиатуры, и для мыши.
internal static class NativeMethods
{
[Flags]
public enum KeyboardFlags : uint
{
None = 0,
/// <summary>
/// KEYEVENTF_EXTENDEDKEY = 0x0001 (If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).)
/// </summary>
ExtendedKey = 1,
/// <summary>
/// KEYEVENTF_KEYUP = 0x0002 (If specified, the key is being released. If not specified, the key is being pressed.)
/// </summary>
KeyUp = 2,
/// <summary>
/// KEYEVENTF_UNICODE = 0x0004 (If specified, wScan identifies the key and wVk is ignored.)
/// </summary>
Unicode = 4,
/// <summary>
/// KEYEVENTF_SCANCODE = 0x0008 (Windows 2000/XP: If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero. This flag can only be combined with the KEYEVENTF_KEYUP flag. For more information, see the Remarks section.)
/// </summary>
ScanCode = 8,
}
[Flags]
public enum MouseFlags : uint
{
/// <summary>
/// Specifies that movement occurred.
/// </summary>
Move = 0x0001,
/// <summary>
/// Specifies that the left button was pressed.
/// </summary>
LeftDown = 0x0002,
/// <summary>
/// Specifies that the left button was released.
/// </summary>
LeftUp = 0x0004,
/// <summary>
/// Specifies that the right button was pressed.
/// </summary>
RightDown = 0x0008,
/// <summary>
/// Specifies that the right button was released.
/// </summary>
RightUp = 0x0010,
/// <summary>
/// Specifies that the middle button was pressed.
/// </summary>
MiddleDown = 0x0020,
/// <summary>
/// Specifies that the middle button was released.
/// </summary>
MiddleUp = 0x0040,
/// <summary>
/// Windows 2000/XP: Specifies that an X button was pressed.
/// </summary>
XDown = 0x0080,
/// <summary>
/// Windows 2000/XP: Specifies that an X button was released.
/// </summary>
XUp = 0x0100,
/// <summary>
/// Windows NT/2000/XP: Specifies that the wheel was moved, if the mouse has a wheel. The amount of movement is specified in mouseData.
/// </summary>
VerticalWheel = 0x0800,
/// <summary>
/// Specifies that the wheel was moved horizontally, if the mouse has a wheel. The amount of movement is specified in mouseData. Windows 2000/XP: Not supported.
/// </summary>
HorizontalWheel = 0x1000,
/// <summary>
/// Windows 2000/XP: Maps coordinates to the entire desktop. Must be used with MOUSEEVENTF_ABSOLUTE.
/// </summary>
VirtualDesk = 0x4000,
/// <summary>
/// Specifies that the dx and dy members contain normalized absolute coordinates. If the flag is not set, dxand dy contain relative data (the change in position since the last reported position). This flag can be set, or not set, regardless of what kind of mouse or other pointing device, if any, is connected to the system. For further information about relative mouse motion, see the following Remarks section.
/// </summary>
Absolute = 0x8000,
}
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public ushort virtualKey;
public ushort scanCode;
public KeyboardFlags flags;
public uint timeStamp;
public IntPtr extraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int deltaX;
public int deltaY;
public int mouseData;
public MouseFlags flags;
public uint time;
public IntPtr extraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public uint message;
public ushort wParamL;
public ushort wParamH;
}
[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
[FieldOffset(0)]
public MOUSEINPUT mouse;
[FieldOffset(0)]
public KEYBDINPUT keyboard;
[FieldOffset(0)]
public HARDWAREINPUT hardware;
}
public enum InputType : int
{
Mouse = 0,
Keyboard = 1,
Hardware = 2
}
public struct INPUT
{
public InputType type;
public InputUnion union;
}
[DllImport("user32.dll")]
public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
}
Даже с XML комментариями.
Далее, давайте перепишем ваш метод, исправив ошибки. Главная ошибка - это то что вы передаете какое-то число 100 в поле time. Оно не служит для задержки, а несет в себе информацию для приложения, когда же было произведено нажатие клавиши - Time stamp.
time
Type: DWORD
The time stamp for the event, in milliseconds. If this parameter is 0, the system will provide its own time stamp.
То есть вам нужно передавать туда 0.
А для задержки между нажатиями нужно выполнять ожидание у себя в приложении явно, например Thread.Sleep(100) или даже лучше await Task.Delay(100). Но давайте для начала без задержек.
public static void ClickMouse(int x, int y)
{
INPUT[] inputs = new INPUT[3];
inputs[0] = new INPUT
{
type = InputType.Mouse,
union = new InputUnion
{
mouse = new MOUSEINPUT
{
deltaX = x,
deltaY = y,
flags = MouseFlags.Move
}
}
};
inputs[1] = new INPUT
{
type = InputType.Mouse,
union = new InputUnion
{
mouse = new MOUSEINPUT
{
flags = MouseFlags.LeftDown
}
}
};
inputs[2] = new INPUT
{
type = InputType.Mouse,
union = new InputUnion
{
mouse = new MOUSEINPUT
{
flags = MouseFlags.LeftUp
}
}
};
SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
}
Ничего лишнего. И кстати, SendInput имеет возвращаемое значение.
Return value
Type: UINT
The function returns the number of events that it successfully inserted into the keyboard or mouse input stream. If the function returns zero, the input was already blocked by another thread.
То есть по этому числу можно определить, сколько инпутов из массива было успешно обработано.
InputUnion UInputType type- я конечно могу угадать их содержание, но я не могу угадать их содержание именно в вашем коде. Как вы поняли, что в формате структур все настолько хорошо, что решили их не показывать? – aepot Feb 26 '21 at 06:59