如何使用C#发送输入

使用代码 (Using the Code)

We will be using the SendInput function in user32.dll. We will not use keybd_event and mouse_event as they are outdated, which means they might not work correctly in future versions of Windows.

我们将在user32.dll中使用SendInput函数。 我们将不再使用keybd_eventmouse_event,因为它们已经过时,这意味着它们可能在将来的Windows版本中无法正常工作。

DirectInput is an API for collecting user input from a user, via input devices (keyboard, mouse, etc.). Depending on some flags that we will discuss later, we can send virtual scan codes or hardware scan codes. Virtual scan codes might be ignored by DirectInput, meaning that our inputs will not be executed. Hardware scan codes are more like pressing a key manually.

DirectInput是一种API,用于通过输入设备(键盘,鼠标等)从用户收集用户输入。 根据稍后将讨论的某些标志,我们可以发送虚拟扫描代码或硬件扫描代码。 虚拟输入法可能会被DirectInput忽略,这意味着我们的输入将不会被执行。 硬件扫描代码更像是手动按下键。

The SendInput function takes three parameters, the number of inputs, an array of INPUT for the inputs we want to send, and the size of our INPUT struct. The INPUT struct includes an integer that indicates the type of input and a union for the inputs that will be passed. If you want to read more about unions, check out this wiki.

SendInput函数采用三个参数:输入数量,要发送的输入的INPUT数组以及INPUT结构的大小。 INPUT结构包含一个指示输入类型的整数和将要传递的输入的并集。 如果您想了解有关工会的更多信息,请查看 Wiki。

First, let's implement the input structs KEYBDINPUT, MOUSEINPUT, and HARDWAREINPUT.

首先,让我们实现输入结构KEYBDINPUTMOUSEINPUTHARDWAREINPUT

输入结构 (Input Structs)

键盘结构 (KEYBDINPUT Struct)

We will use Sequential StructLayout to force the members to be in sequential order because we will pass the struct to unmanaged code. wVk is a virtual key code. wScan is the scan code of the key we want to press. More details about the scan codes can be found here. dwFlags are the flags about the input (KeyUp, ExtendKey, Unicode, ScanCode). Please read the remarks section here for more information about the flags. We will see them in action later. time is a timestamp of the input, if it is set to 0, then the system provides its own timestamp. dwExtraInfo provides additional information about the keystroke, it is obtained using the GetMessageExtraInfo function.

我们将使用StructLayout强制成员按顺序排列,因为我们会将struct传递给非托管代码。 wVk是虚拟键码。 wScan是我们要按的键的扫描代码。 有关扫描代码的更多详细信息,请参见此处dwFlags是关于输入(标志KeyUpExtendKeyUnicodeScanCode )。 请阅读此处的“备注”部分以获取有关标志的更多信息。 我们稍后将看到它们的实际应用。 time是输入的时间戳,如果将其设置为0 ,则系统提供其自己的时间戳。 dwExtraInfo提供了有关按键的其他信息,可以使用GetMessageExtraInfo函数获得它。

[StructLayout(LayoutKind.Sequential)]
public struct KeyboardInput
{
    public ushort wVk;
    public ushort wScan;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

鼠标输入结构 (MOUSEINPUT Struct)

dx is the absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the x coordinate of the mouse; relative data is specified as the number of pixels moved. dy is the same as dx but for the y-axis. If dwFlags contains MOUSEEVENTF_WHEEL or MOUSEEVENTF_HWHEEL, then mouseData specifies the amount of wheel movement. A positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA which is 120. dwFlags are a set of bit flags that specify various aspects of mouse movements and button clicks. We will look at the flags later. time is a timestamp of the input, if it is set to 0, then the system provides its own timestamp. dwExtraInfo is an additional value associated with the mouse event. It is obtained using the GetMessageExtraInfo function.

dx是鼠标的绝对位置,或者是自上一次鼠标事件生成以来的运动量,具体取决于dwFlags成员的值。 绝对数据指定为鼠标的x坐标; 相对数据指定为移动的像素数。 dydx相同,但y轴为。 如果dwFlags包含MOUSEEVENTF_WHEELMOUSEEVENTF_HWHEEL ,则mouseData指定滚轮移动量。 正值表示轮子向前旋转,远离用户; 负值表示方向盘朝着用户向后旋转。 一个轮点击被定义为WHEEL_DELTA其是120 dwFlags是一组指定的鼠标移动和按钮点击的各个方面的位标志。 我们将在稍后查看标志。 time是输入的时间戳,如果将其设置为0 ,则系统提供其自己的timestampdwExtraInfo是与鼠标事件关联的附加值。 它是使用GetMessageExtraInfo函数获得的。

[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
    public int dx;
    public int dy;
    public uint mouseData;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

硬件输入结构 (HARDWAREINPUT Struct)

uMsg is the message generated by the input hardware. wParamL is the low-order word of the lParam parameter for uMsg. wParamH is the high-order word of the lParam parameter for uMsg.

uMsg是输入硬件生成的消息。 wParamLlParam的低位字 uMsg参数。 wParamHlParam的高阶词 uMsg参数。

[StructLayout(LayoutKind.Sequential)]
public struct HardwareInput
{
    public uint uMsg;
    public ushort wParamL;
    public ushort wParamH;
}

InputUnion (InputUnion)

InputUnion is the union parameter in the INPUT struct. It contains the input data for the mouse, keyboard, or hardware.

InputUnionINPUT struct的并集参数。 它包含鼠标,键盘或硬件的输入数据。

[StructLayout(LayoutKind.Explicit)]
public struct InputUnion
{
    [FieldOffset(0)] public MouseInput mi;
    [FieldOffset(0)] public KeyboardInput ki;
    [FieldOffset(0)] public HardwareInput hi;
}  

输入结构 (The INPUT Struct)

Used by SendInput to store information for synthesizing input events such as keystrokes, mouse movement, and mouse clicks. type is the type of the input event. It specifies which input struct will be used from the union. The values are:

SendInput用于存储用于合成输入事件的信息,例如击键,鼠标移动和鼠标单击。 type是输入事件的类型。 它指定将从联合使用哪个输入struct 。 值是:

  • 1 for MOUSEINPUT

    1用于MOUSEINPUT

  • 2 for KEYBDINPUT

    2用于KEYBDINPUT

  • 3 for HARDWAREINPUT

    3用于HARDWAREINPUT

For this, we can use the InputType enum, which we will look at later.

为此,我们可以使用InputType enum ,我们将在后面进行讨论。

public struct Input
{
    public int type;
    public InputUnion u;
}

标志 (Flags)

An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type (int, uint, byte, etc.). By default, the associated constant values of enum members are of type int; they start with zero and increase by one following the definition text order.

枚举类型 (或枚举类型 )是由基础整数数值类型( intuintbyte等)的一组命名常量定义的值类型。 默认情况下, enum成员的关联常量值类型为int ; 它们从零开始,并按照定义文本顺序增加一。

If you want an enumeration type to represent a combination of choices, define enum members for those choices such that an individual choice is a bit field. That is, the associated values of those enum members should be the powers of two. Then, you can use the bitwise logical operators | or & to combine choices or intersect combinations of choices, respectively.

如果希望枚举类型表示选项的组合,请为这些选项定义enum成员,以使单个选项成为位字段。 也就是说,这些enum成员的关联值应为2的幂。 然后,您可以使用按位逻辑运算符|&分别组合选择或相交选择的组合。

The [Flags] attribute indicates that an enumeration can be treated as a bit field; that is, a set of flags.

[Flags]属性指示可以将枚举视为位字段; 即一组标志。

输入类型 (InputType)

InputType is a simple enum for the different input types used in the INPUT struct.

InputType是一个简单的enum ,用于INPUT struct使用的不同输入类型。

[Flags]
public enum InputType
{
    Mouse = 0,
    Keyboard = 1,
    Hardware = 2
}

关键事件标志 (Key Event Flags)

KeyEventF has the flags used by the KEYBDINPUT struct.

KeyEventF具有KEYBDINPUT struct使用的标志。

[Flags]
public enum KeyEventF
{
    KeyDown = 0x0000,
    ExtendedKey = 0x0001,
    KeyUp = 0x0002,
    Unicode = 0x0004,
    Scancode = 0x0008
}

鼠标事件标志 (Mouse Event Flags)

MouseEventF has the flags used by the MOUSEINPUT struct.

MouseEventF具有MOUSEINPUT struct使用的标志。

[Flags]
public enum MouseEventF
{
    Absolute = 0x8000,
    HWheel = 0x01000,
    Move = 0x0001,
    MoveNoCoalesce = 0x2000,
    LeftDown = 0x0002,
    LeftUp = 0x0004,
    RightDown = 0x0008,
    RightUp = 0x0010,
    MiddleDown = 0x0020,
    MiddleUp = 0x0040,
    VirtualDesk = 0x4000,
    Wheel = 0x0800,
    XDown = 0x0080,
    XUp = 0x0100
}

DLL导入 (DLL Imports)

The DllImport attribute indicates that the exposed method is from an unmanaged dynamic linked library (DLL).

DllImport属性指示公开的方法来自非托管动态链接库(DLL)。

互通性 (Interoperability)

Interoperability enables you to preserve and take advantage of existing investments in unmanaged code. Code that runs under the control of the common language runtime (CLR) is called managed code, and code that runs outside the CLR is called unmanaged code. COM, COM+, C++ components, ActiveX components, and Microsoft Windows API are examples of unmanaged code.

互操作性使您可以保留和利用非托管代码中的现有投资。 在公共语言运行时(CLR)的控制下运行的代码称为托管代码 ,而在CLR外部运行的代码称为非托管代码 。 COM,COM +,C ++组件,ActiveX组件和Microsoft Windows API是非托管代码的示例。

The .NET Framework enables interoperability with unmanaged code through platform invoke services, the System.Runtime.InteropServices namespace, C++ interoperability, and COM interoperability (COM interop).

.NET Framework通过平台调用服务, System.Runtime.InteropServices命名空间,C ++互操作性和COM互操作性(COM互操作)来实现与非托管代码的互操作性。

调用 (PInvoke)

Platform invoke is a service that enables managed code to call unmanaged functions that are implemented in dynamic link libraries (DLLs), such as those in the Microsoft Windows API.

平台调用是一项服务,使托管代码可以调用在动态链接库(DLL)中实现的非托管函数,例如Microsoft Windows API中的那些。

导入SendInput函数 (Importing the SendInput Function)
[DllImport("user32.dll", SetLastError = true)]
private static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);

导入GetMessageExtraInfo函数 (Importing the GetMessageExtraInfo Function)
[DllImport("user32.dll")]
private static extern IntPtr GetMessageExtraInfo();

放在一起 (Putting It All Together)

发送键盘输入 (Sending Keyboard Input)

First, we create an array of Input where the ... inputs will be stored. For each input, we set the type to InputType.Keyboard and in a KeyboardInput object, we specify the details. In the first input, we set the scancode to 0x11(W), set the KeyDown and Scancode flags. This means that we will use the scancode of the key we want to use (in that case W) and press it down. The second input is the same, but instead of pressing the button down, it is released. After the inputs are set, we send them using the SendInput function.

首先,我们创建一个Input数组,其中将存储...输入。 对于每个输入,我们将类型设置为InputType.Keyboard并在KeyboardInput对象中指定详细信息。 在第一个输入中,我们将扫描代码设置为0x11 (W),设置KeyDownScancode标志。 这意味着我们将使用要使用的键的扫描代码(在这种情况下为W),然后按下它。 第二个输入是相同的,但是没有按下按钮,而是释放了它。 设置输入后,我们使用SendInput函数发送它们。

Input[] inputs = new Input[]
{
    new Input
    {
        type = (int)InputType.Keyboard,
        u = new InputUnion
        {
            ki = new KeyboardInput
            {
                wVk = 0,
                wScan = 0x11, // W
                dwFlags = (uint)(KeyEventF.KeyDown | KeyEventF.Scancode),
                dwExtraInfo = GetMessageExtraInfo()
            }
        }
    },
    new Input
    {
        type = (int)InputType.Keyboard,
        u = new InputUnion
        {
            ki = new KeyboardInput
            {
                wVk = 0,
                wScan = 0x11, // W
                dwFlags = (uint)(KeyEventF.KeyUp | KeyEventF.Scancode),
                dwExtraInfo = GetMessageExtraInfo()
            }
        }
    }
};

SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));

By sending two sets of inputs with 2 seconds interval, we can do this:

通过发送间隔为2秒的两组输入,我们可以做到这一点:

Image 1

发送鼠标输入 (Sending Mouse Input)

For each input, we set the type to InputType.Mouse and in a MouseInput object, we specify the details. dx is how much the mouse will move relatively on the x-axis. dy is how much it will move on the y-axis. Here, we will move the mouse 100 units down and 100 units to the right, then left click. The second input will release the LMB. After the inputs are set, we send them using the SendInput function.

对于每个输入,我们将类型设置为InputType.Mouse并在MouseInput对象中指定详细信息。 dx是鼠标在x轴上相对移动的量。 dy是它将在y轴上移动多少。 在这里,我们将鼠标向下移动100个单位,向右移动100个单位,然后单击鼠标左键。 第二个输入将释放LMB。 设置输入后,我们使用SendInput函数发送它们。

Input[] inputs = new Input[]
{
    new Input
    {
        type = (int) InputType.Mouse,
        u = new InputUnion
        {
            mi = new MouseInput
            {
                dx = 100,
                dy = 100,
                dwFlags = (uint)(MouseEventF.Move | MouseEventF.LeftDown),
                dwExtraInfo = GetMessageExtraInfo()
            }
        }
    },
    new Input
    {
        type = (int) InputType.Mouse,
        u = new InputUnion
        {
            mi = new MouseInput
            {
                dwFlags = (uint)MouseEventF.LeftUp,
                dwExtraInfo = GetMessageExtraInfo()
            }
        }
    }
};

SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));

Image 2

奖金:获取/设置鼠标绝对坐标 (BONUS: Getting/Setting Absolute Mouse Coordinates)

获取绝对鼠标坐标 (Getting Absolute Mouse Coordinates)

Using the GetCursorPos function, we can easily get the current mouse coordinates. It returns a bool indicating if it is successful and takes a POINT struct reference where the coordinates will be contained.

使用GetCursorPos函数,我们可以轻松获取当前鼠标坐标。 它返回一个bool指示是否成功,并获取一个POINT struct引用,该坐标将包含坐标。

[DllImport("user32.dll")]
public static extern bool GetCursorPos(out POINT lpPoint);

[StructLayout(LayoutKind.Sequential)]
public struct POINT
{
    public int X;
    public int Y;
}

It is used like this:

它的用法如下:

GetCursorPos(out POINT point);
Console.WriteLine(point.X);
Console.WriteLine(point.Y);

设置鼠标绝对坐标 (Setting Absolute Mouse Coordinates)

Using the SetCursorPos function, we can easily set the current mouse coordinates. It returns a bool indicating if it is successful and takes two integers for the x coordinate and y coordinate.

使用SetCursorPos函数,我们可以轻松设置当前鼠标坐标。 它返回一个bool指示是否成功,并为x坐标和y坐标取两个整数。

[DllImport("User32.dll")]
public static extern bool SetCursorPos(int x, int y);

It is used like this:

它的用法如下:

SetCursorPos(100, 100);

翻译自: https://www.codeproject.com/Articles/5264831/How-to-Send-Inputs-using-Csharp

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值