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

news2024/11/26 21:55:25

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

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出生,广州工作,广东人,硕士毕业,其它的可以私聊)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/872237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

简单线性回归:预测事物间简单关系的利器

文章目录 &#x1f340;简介&#x1f340;什么是简单线性回归&#xff1f;&#x1f340;简单线性回归的应用场景使用步骤&#xff1a;注意事项&#xff1a; &#x1f340;代码演示&#x1f340;结论 &#x1f340;简介 在数据科学领域&#xff0c;线性回归是一种基本而强大的统…

Failed to start LVS and VRRP High Availability Monitor.

Keepalive启动报错&#xff0c;Fail to start LVS and VRRP High Availability Monitor. 解决方法 &#xff1a; cd /etc/keepalived/cp keepalived.conf.sample keepalived.conf vim keepalived.conf //找到这个模块并修改接口名称 vrrp_instance VI_1 {state MASTERinterfac…

Jeecg-boot JDBC任意代码执行漏洞

漏洞描述 JeecgBoot是一款开源的企业级低代码平台&#xff0c;提供了表单、视图、流程等一键生成代码功能&#xff0c;目前在GitHub具有 35.5k star。 在V3版本中&#xff0c;由于未对JDBC连接字符串进行限制&#xff0c;未授权的攻击者可配置恶意的连接字符串&#xff0c;通…

岛屿的最大面积(力扣)递归 JAVA

给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&#xff09;包围着。 岛屿的面积是岛上值为 1 的…

Redis的数据结构到底是一种什么样的结构?

有了上一篇NoSQL的基础&#xff0c;我们也都知道了Redis就是一种典型的NoSql&#xff0c;那我们就先简简单单的介绍一下Redis&#xff1a; Redis是什么&#xff1f; Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的使用ANSI C语言编写的高性能键值存储系统…

Kalman Filter VS Particle Filter

概率图模型 时间 -------->动态模型 动态模型有下面三种&#xff1a; 如果状态是离散的&#xff0c;就是我们上一节提到了Hidden Markov Model (HMM)&#xff1b; 如果状态是连续的&#xff0c;如果状态之间的关系是线性的&#xff0c;就是Linear Dynamic System (Kalman …

【第二阶段】kotlin语言的匿名函数与具名函数

fun main() {//匿名函数val niminginfoniming("kotlin",20,{"$it"})println(niminginfo)//具名函数 理解&#xff1a;showResult:(String)->String):StringshowResultImpl(result:String):Stringval juminginfoniming("c ",20,::showResultI…

【jvm】类加载器的分类

目录 一、说明二、示例2.1 代码2.2 截图 一、说明 1.jvm支持两种类型的类加载器&#xff0c;分别是引导类加载器&#xff08;bootstrap classloader&#xff09;和自定义类加载器&#xff08;user-defined classloader&#xff09; 2.自定义类加载器一般指的是程序中由开发人员…

Python 中被忽视的核心功能

这篇文章主要介绍了一些在 Python 编程中可能被忽视的核心功能&#xff0c;包括默认参数、海象运算符、*args 和 **kwargs 的使用、变量交换、str 与 repr 的区别、可迭代对象的扩展解包、多个上下文管理器的使用、Python 调试器、collections.Counter 的使用、itertools 的使用…

Mysql高阶第一章 主从架构的复现

这里写目录标题 前言第一章 找到主数据库和从数据库对应的虚拟机1.1 查对应虚拟机IP1.2 rpm 查找数据库是否安装1.3 查找数据库详细配置信息 第二章 启动主从复制2.1 SHOW SLAVE STATUS\G;2.2 Slave_IO_Running: No2.3 解决方案2.3.1 进入slave中输入&#xff0c;停止从库同步&…

WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制

WebRTC音视频通话-新增或修改SDP中的码率Bitrate限制参数 之前搭建ossrs服务&#xff0c;可以查看&#xff1a;https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话&#xff0c;可以查看&#xff1a;https://blog.csdn.net/gloryFlo…

PHP实践:分布式场景下的Session共享解决方案实现

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年6月CSDN上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责…

(1)window配置微软商店中的Ubuntu,及错误解决方法

&#xff08;1&#xff09;首先&#xff0c;在微软商店中搜索“Ubuntu”&#xff0c;下载你喜欢的版本(此处) &#xff08;2&#xff09;设置适用于window的Linux子系统&#xff0c;跟着红色方框走 点击“确定”之后&#xff0c;会提示你重启电脑&#xff0c;按要求重启电脑即可…

【算法题解】53. 计封闭岛屿的数目

这是一道 中等难度 的题 https://leetcode.cn/problems/number-of-closed-islands/ 题目 二维矩阵 grid 由 0 0 0&#xff08;土地&#xff09;和 1 1 1 &#xff08;水&#xff09;组成。岛是由最大的 4 4 4 个方向连通的 0 0 0 组成的群&#xff0c;封闭岛是一个 完全 由…

使用shift关键字,写一个带二级命令的脚本(如:docker run -a -b -c中的run)

省流&#xff1a;shift关键字 探索思路 最近有一个小小的需求&#xff0c;写一个类似于docker run -a -b -c这样的脚本&#xff0c;这个脚本名为doline&#xff0c;它本身可以执行&#xff08;doline -a -b -c&#xff09;&#xff0c;同时又带有几个如run、init、start这样的…

【Pytroch】基于K邻近算法的数据分类预测(Excel可直接替换数据)

【Pytroch】基于K邻近算法的数据分类预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.数学公式3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果 1.模型原理 K最近邻&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;是一种简单但常用的机器…

python编程基础与案例集锦,python编程入门经典

大家好&#xff0c;本文将围绕python编程基础与案例集锦展开说明&#xff0c;python编程入门与案例详解是一个很多人都想弄明白的事情&#xff0c;想搞清楚python入门程序例子需要先了解以下几个事情。 【程序1】 题目&#xff1a;输入一行字符&#xff0c;分别统计出其中英文字…

【c++】七夕快到了却还没对象?手把手教你new一个出来!

前言 本章给大家带来的是C内存管理。在C语言阶段&#xff0c;我们经常使用malloc&#xff0c;calloc&#xff0c;realloc&#xff0c;free进行内存管理。但是&#xff0c;C语言的内存管理存在很多缺陷&#xff0c;会对程序的稳定性和安全性造成影响。 不过&#xff0c;C语言的…

cubemx hal stm32 舵机 可减速 任意位置停止 驱动代码

CubeMX配置 对于 STM32 F407VE 这里的84是来自APB1那路2倍频得到&#xff1a; 代码部分 两个舵机都是180度的 servo.c #include "servo.h" #include "tim.h" #include "stdio.h"__IO uint32_t g_SteerUWT[2] {0}; uint16_t g_SteerDeg[…

开发一个RISC-V上的操作系统(七)—— 硬件定时器(Hardware Timer)

目录 往期文章传送门 一、硬件定时器 硬件实现 软件实现 二、上板测试 往期文章传送门 开发一个RISC-V上的操作系统&#xff08;一&#xff09;—— 环境搭建_riscv开发环境_Patarw_Li的博客-CSDN博客 开发一个RISC-V上的操作系统&#xff08;二&#xff09;—— 系统引导…