代码控制鼠标光标移动并点击和代码模拟键盘按下(C#)

前面介绍过通过代码的方式模拟键盘按下,博文如下:

C#通过代码的方式模拟键盘按下_c# 模拟键盘输入_zxy2847225301的博客-CSDN博客

这个博文是通过win32的keybd_event实现,可能会未来的window版本中被淘汰(不是我说的,看到老外一篇文章中说的)

本文的内容参考自:

How to Send Inputs using C# - CodeProject

本文的主要核心是利用了win32的函数SendInput,将会实现并演示如下的效果:

演示效果1:   点击按钮,然后模拟键盘输入,把输入的内容显示到文本框上

演示效果2:   点击按钮,然后控制鼠标光标移动(对角线移动)

演示效果3:   点击按钮,然后控制鼠标光标移动到演示效果1中的那个按钮的位置上,并实现点击,接着就会看到效果1中的效果(模拟键盘输入,把输入的内容显示到文本框上)

本文测试环境:

vistual studio 2017

.net framework 4.0

winform

步骤如下:

1   新建winform项目,.net framework选4.0,名为SendInputDemo,并新建类Win32SendInputApi并编辑如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace SendInputDemo
{
    public class Win32SendInputApi
    {
        /// <summary>
        /// 键盘输入参数
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct KeyboardInput
        {
            public ushort wVk;
            public ushort wScan;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        /// <summary>
        /// 鼠标输入参数
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct MouseInput
        {
            public int dx;
            public int dy;
            public uint mouseData;
            public uint dwFlags;
            public uint time;
            public IntPtr dwExtraInfo;
        }

        /// <summary>
        /// Hardware输入参数,Hardware不知道是什么设备,应该类似于传感器输入之类的设备(usb输入或者串口输入)
        /// </summary>
        [StructLayout(LayoutKind.Sequential)]
        public struct HardwareInput
        {
            public uint uMsg;
            public ushort wParamL;
            public ushort wParamH;
        }

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

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


        [Flags]
        public enum InputType
        {
            Mouse = 0,  //鼠标
            Keyboard = 1,//键盘
            Hardware = 2
        }

        /// <summary>
        /// 键盘状态
        /// </summary>
        [Flags]
        public enum KeyEventF
        {
            KeyDown = 0x0000,   //键盘按下
            ExtendedKey = 0x0001,  //不懂,看名字像追加键
            KeyUp = 0x0002,    //键盘抬起
            Unicode = 0x0004,  //不懂
            Scancode = 0x0008  //不懂
        }
        /// <summary>
        /// 鼠标参数类型
        /// </summary>
        [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
        }

        [DllImport("user32.dll", SetLastError = true)]
        public static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);

        [DllImport("user32.dll")]
        public  static extern IntPtr GetMessageExtraInfo();





        /// <summary>
        /// 获取鼠标的坐标
        /// </summary>
        /// <param name="lpPoint"></param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool GetCursorPos(out POINT lpPoint);

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

        /// <summary>
        /// 设置鼠标的位置
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        [DllImport("User32.dll")]
        public static extern bool SetCursorPos(int x, int y);

    }
}

2  winform的UI布局如下:

 

3  实现演示效果1:   点击按钮,然后模拟键盘输入,把输入的内容显示到文本框上

'触发键盘按下'按钮的代码逻辑如下:

public partial class Form1 : Form
{
        public Form1()
        {
            InitializeComponent();
            this.btnPress.Click += new System.EventHandler(this.btnPress_Click);
        }

        /// <summary>
        /// 触发键盘按下按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnPress_Click(object sender, EventArgs e)
        {
            this.txtKeyInput.Focus();
            Input[] inputs = new Input[]
                                {
                                    new Input
                                    {
                                        type = (int)InputType.Keyboard,
                                        u = new InputUnion
                                        {
                                            ki = new KeyboardInput
                                            {
                                                wVk = 0,
                                                wScan = 0x02, // 数字1
                                                dwFlags = (uint)(KeyEventF.KeyDown | KeyEventF.Scancode),
                                                dwExtraInfo = Win32SendInputApi.GetMessageExtraInfo()
                                            }
                                        }
                                    }
                                  };

            Win32SendInputApi.SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));
            this.txtKeyInput.Focus();
        }
        
}

运行效果如下:

每点一次按钮,就录入一个1

键盘的16进制编码可以参考这个网址:Keyboard scancodes: Keyboard scancodes

如上图中的01代表键盘上的ESC键,02 数字键1或者!键(在笔记本键盘上,这两个键是公用的),相信你能看懂后面编码对应的按钮含义了

 

 

4  实现演示效果2:   点击按钮,然后控制鼠标光标移动(对角线移动)

 '设置鼠标的位置'按钮的代码逻辑如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using static SendInputDemo.Win32SendInputApi;

namespace SendInputDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.btnSetCurPosition.Click += new System.EventHandler(this.btnSetCurPosition_Click);
        }

        /// <summary>
        /// 设置鼠标的位置按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSetCurPosition_Click(object sender, EventArgs e)
        {
            
            for (int i = 0; i <150; i+=20)
            {
                POINT lpPoint;
                Win32SendInputApi.GetCursorPos(out lpPoint);
                Win32SendInputApi.SetCursorPos(lpPoint.X + i, lpPoint.Y +i);
                Thread.Sleep(100);
            }
        }
    }
}

上面的逻辑是:获取到当前鼠标光标的位置,然后赋予鼠标光标新的位置,每次设置睡眠100毫秒才能看到效果

运行效果:

可以看到鼠标光标在按钮"设置鼠标的位置"上点击后,鼠标光标逐渐以对角线的方式往右下角移动

5  实现演示效果3:   点击按钮,然后控制鼠标光标移动到演示效果1中的那个按钮的位置上,并实现点击,接着就会看到效果1中的效果(模拟键盘输入,把输入的内容显示到文本框上)

'设置鼠标的位置并按模拟鼠标点击'的代码逻辑如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using static SendInputDemo.Win32SendInputApi;

namespace SendInputDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            this.btnPress.Click += new System.EventHandler(this.btnPress_Click);
            this.btnSetCurPosition.Click += new System.EventHandler(this.btnSetCurPosition_Click);
            this.btnMouseClick.Click += new System.EventHandler(this.btnMouseClick_Click);
        }

        /// <summary>
        /// 设置鼠标的位置并按模拟鼠标点击按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnMouseClick_Click(object sender, EventArgs e)
        {
            //PointToScreen为btnPress控件转屏幕坐标
            Point pointScreen =this.btnPress.PointToScreen(new Point(0,0));
            //Point pointScreen =this.btnPress.PointToScreen(new Point(0,0))可以换成
            //这样的写法Point pointScreen = this.PointToScreen(new Point(btnPress.Location.X, btnPress.Location.Y));
            Win32SendInputApi.SetCursorPos(pointScreen.X+10, pointScreen.Y+1);
            Input[] inputs = new Input[]
            {
                new Input
                {
                    type = (int) InputType.Mouse,
                    u = new InputUnion
                    {
                        mi = new MouseInput
                        {
                            dx =pointScreen.X+10,
                            dy =pointScreen.Y+1,
                            dwFlags = (uint)(MouseEventF.LeftDown), //鼠标左键按下
                            dwExtraInfo = Win32SendInputApi.GetMessageExtraInfo()
                        }
                    }
                },
                new Input
                {
                    type = (int) InputType.Mouse,
                    u = new InputUnion
                    {
                        mi = new MouseInput
                        {
                            dx =pointScreen.X+10,
                            dy =pointScreen.Y+1,
                            dwFlags = (uint)(MouseEventF.LeftUp),  //鼠标左键抬起
                            dwExtraInfo = Win32SendInputApi.GetMessageExtraInfo()
                        }
                    }
                }
            };

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

        }
    }
}

想要在'触发键盘按下'按钮(名为btnPress)触发自动按钮逻辑,就得通过PointToScreen把控件的坐标转换为计算机桌面的坐标(以前做Unity 3D的时候经常看到这种骚操作),然后把转换后的坐标作为鼠标光标的位置,最后通过模拟鼠标左键按下和抬起,一定要鼠标按下和抬起一起使用才有效,因为鼠标按下和抬起同时完成才算实现鼠标按下的逻辑。

运行效果如下图:

 

好了,本文的内容到此结束(Tips:在线招个亲,最近家里逼得太急了,老铁有亲戚朋友啥的适龄未婚、活的女的都可以介绍哈,本人情况:男,1993出生,广州工作,广东人,硕士毕业,其它的可以私聊)

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
模拟鼠标键盘 注意:不支持Windows 8 / 8.1。 Interceptor是Windows键盘驱动程序的包装器(包装http://oblita.com/Interception)。 使用驱动程序,Interceptor可以模拟按键和鼠标点击... 使用DirectX的游戏,通常不接受使用SendInput()的击键 Windows的受保护区域,如Windows登录屏幕或UAC调暗屏幕 任何应用程序 因为驱动程序模拟击键和鼠标单击,所以目标窗口必须处于活动状态(即,在发送击键和鼠标点击时,不能在另一个窗口上执行多任务)。 如何使用 下载并构建此项目并在项目中引用其DLL。 下载'interception.dll',这是一个由驱动程序作者编写的独立库。将它放在与可执行文件相同的目录中。这是必需的。 从作者的网页下载并安装“install-interception.exe”。安装后重新启动计算机。 在您的代码中,要加载驱动程序,请调用(阅读下面的代码注释;您必须设置过滤模式以捕获按键事件或发送按键操作!): Input input = new Input(); // Be sure to set your keyboard filter to be able to capture key presses and simulate key presses // KeyboardFilterMode.All captures all events; 'Down' only captures presses for non-special keys; 'Up' only captures releases for non-special keys; 'E0' and 'E1' capture presses/releases for special keys input.KeyboardFilterMode = KeyboardFilterMode.All; // You can set a MouseFilterMode as well, but you don't need to set a MouseFilterMode to simulate mouse clicks // Finally, load the driver input.Load(); 做你的东西。 input.MoveMouseTo(5, 5); // Please note this doesn't use the driver to move the mouse; it uses System.Windows.Forms.Cursor.Position input.MoveMouseBy(25, 25); // Same as above ^ input.SendLeftClick(); input.KeyDelay = 1; // See below for explanation; not necessary in non-game apps input.SendKeys(Keys.Enter); // Presses the ENTER key down and then up (this constitutes a key press) // Or you can do the same thing above using these two lines of code input.SendKeys(Keys.Enter, KeyState.Down); Thread.Sleep(1); // For use in games, be sure to sleep the thread so the game can capture all events. A lagging game cannot process input quickly, and you so you may have to adjust this to as much as 40 millisecond delay. Outside of a game, a delay of even 0 milliseconds can work (instant key presses). input.SendKeys(Keys.Enter, KeyState.Up); input.SendText("hello, I am typing!"); /* All these following characters / numbers / symbols work */ input.SendText("abcdefghijklmnopqrstuvwxyz"); input.SendText("1234567890"); input.SendText("!@#$%^&*()"); input.SendText("[]\\;',./"); input.SendText("{}|:\"?"); // And finally input.Unload(); 笔记: BadImageFormatException如果您没有为解决方案中的所有项目(包括此项目)使用正确的体系结构(x86或x64),则可能会获得。因此,您可能必须下载此项目的源代码才能将其重建为正确的体系结构。这应该很简单,构建过程应该没有错误。 您必须从http://oblita.com/Interception下载'interception.dll' 。 如果你已经完成了以上所有操作(正确安装了拦截驱动程序,将interception.dll放在你的项目文件夹中),你仍然无法发送击键: 驱动程序有一个限制,即它不能在不接收至少一次击键的情况下发送击键。这是因为驱动程序不知道键盘是哪个设备ID,因此它必须等待接收击键以从击键中推断出设备ID。 总之,在发送击键之前,请始终按键盘一次。点按任意键。然后你可以发送击键。这不适用于接收击键,因为通过接收击键,您当然已经按下了一个键。 MoveMouseTo()和MoveMouseBy()完全忽略键盘驱动程序。它使用System.Windows.Forms.Position来设置和获取游标的位置(它为下面的各个函数调用标准的Win32 API)。 原因是,在探索键盘驱动程序的鼠标移动功能时,我注意到它没有按像素单位移动光标,而是似乎通过加速移动光标。当我想将光标移动到某个位置时,这会不断产生不一致的值。因为Win32游标设置API通常不被游戏等阻止,所以我发现只需调用这些标准API即可,而无需使用驱动程序。请注意,这仅适用于设置光标位置。拦截光标仍然可以正常工作。例如,您可以使用Interceptor反转鼠标的x和y轴。
WinAPI-Wrapper 模拟鼠标点击 用于模拟鼠标移动点击、窗口操作等的Windows API包装器类。 API 下面是一些可用的方法的总结。有更多的方法和类,比下面列出的要多,但目的是要大致了解包装器能做什么。要查看关于特定方法的详细信息和参数的详细信息,请查看代码本身,因为它的注释很好。 Mouse.cs public static void LeftClick(); public static void RightClick(); public static void MiddleClick(); public static void LeftDown(); public static void LeftUp(); public static void RightDown(); public static void RightUp(); public static void MiddleDown(); public static void MiddleUp(); public static void Move(int x, int y); public static void LeftDrag(Point point1, Point point2, int interval, int lag); Window.cs public static bool DoesExist(string windowTitle); public static IntPtr Get(string windowTitle); public static IntPtr GetFocused(); public static void SetFocused(IntPtr hWnd); public static bool IsFocused(IntPtr hWnd); public static void Move(IntPtr hWnd, int x, int y); public static void Resize(IntPtr hWnd, int width, int height); public static void Hide(IntPtr hWnd); public static void Show(IntPtr hWnd); public static Rectangle GetDimensions(IntPtr hWnd); public static Size GetSize(IntPtr hWnd); public static Point GetLocation(IntPtr hWnd); public static string GetTitle(IntPtr hWnd); public static void SetTitle(IntPtr hWnd, string title); public static void Maximize(IntPtr hWnd); public static void Minimize(IntPtr hWnd); public static void Normalize(IntPtr hWnd); public static Bitmap Screenshot(IntPtr hWnd); public static void RemoveMenu(IntPtr hWnd); public static void Close(IntPtr hWnd); public static void DisableCloseButton(IntPtr hWnd); public static void DisableMaximizeButton(IntPtr hWnd); public static void DisableMinimizeButton(IntPtr hWnd); public static void EnableMouseTransparency(IntPtr hWnd); public static Point ConvertToWindowCoordinates(IntPtr hWnd, int x, int y); public static Point GetCoordinateRelativeToWindow(IntPtr hWnd); Desktop.cs public static Bitmap Screenshot(); public static void HideTaskBar(); public static void ShowTaskBar(); public static int GetWidth(); public static int GetHeight(); 使用 在windows api文件夹中编译代码会产生一个.dll文件。任何引用这个.dll的ccode都可以使用包装器。
以下是使用MPU6050控制鼠标移动C#代码示例: ```csharp using System; using System.IO.Ports; using System.Windows.Forms; namespace MPU6050MouseControl { public partial class Form1 : Form { private SerialPort port; private int centerX; private int centerY; private int sensitivity = 2; public Form1() { InitializeComponent(); port = new SerialPort("COM3", 9600); // 请根据实际情况设置串口号和波特率 port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived); port.Open(); centerX = Screen.PrimaryScreen.Bounds.Width / 2; centerY = Screen.PrimaryScreen.Bounds.Height / 2; } private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) { string data = port.ReadLine(); string[] values = data.Split(','); if (values.Length == 3) { int x = Convert.ToInt32(values[0]) * sensitivity; int y = Convert.ToInt32(values[1]) * sensitivity; int z = Convert.ToInt32(values[2]) * sensitivity; Cursor.Position = new System.Drawing.Point(Cursor.Position.X + x, Cursor.Position.Y - y); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { port.Close(); } } } ``` 上面的代码首先初始化了一个串口对象,并在串口接收数据时解析数据并将其转换为鼠标移动的信息。然后,代码鼠标移动到计算出的位置。你可以根据需要修改代码中的灵敏度值来调整鼠标移动速度。最后,当窗口关闭时,代码关闭串口连接。请注意,这只是一个简单的示例,你需要根据你的实际需求进行修改和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zxy2847225301

测试使用

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值