C# SendInput 模拟鼠标操作的实现方法
发布时间:2022-03-15 00:07:25
刚刚开始学习C#,想自己做一个网页游戏的挂。游戏里面有收钱的动作,一个建筑物一个建筑物的点,很累啊。于是想用C#模拟鼠标操作替我收钱,想着学习这个对以后的测试工作也有帮助,于是有了动力。学习过程也是曲折的,因为网上搜了半天资料很少。该游戏是Flash的,用sendmessage不行,因为取不到里面的对象。查到有些介绍Mouse_Event的文章,但是msdn上说已经过时。于是查到了SendInput函数。
废话少说,上代码:
首先看下 Win API 中SendInput函数描述:
UINT WINAPI SendInput(
__in UINT nInputs,
__in LPINPUT pInputs,
__in int cbSize
);
对应的C#代码:
[DllImport("user32.dll")]
public static extern UInt32 SendInput(UInt32 nInputs,Input[] pInputs, int cbSize);
其中参数pInputs是的数组类型,数组元素INPUT结构,所以我们下面还要在C#中定义对应的INPUT结构或者对象。INPUT结构中主要是定义你需要的鼠标或者键盘等操作。nInputs指明pInputs数组长度。cbSize指明INPUT结构的大小。
定义INPUT结构,下面是Win API 中INPUT结构描述:
typedef struct tagINPUT {
DWORD type;
union {
MOUSEINPUT mi;
KEYBDINPUT ki;
HARDWAREINPUT hi;
} ;
} INPUT, *PINPUT;
对应的C#代码
[StructLayout(LayoutKind.Explicit)]
public struct Input
{
[FieldOffset(0)]public Int32 type;
[FieldOffset(4)]public MouseInput mi;
[FieldOffset(4)]public tagKEYBDINPUT ki;
[FieldOffset(4)]public tagHARDWAREINPUT hi;
}
上面看到,还有MOUSEINPUT,KEYBDINPUT,HARDWAREINPUT结构需要定义。下面直接贴出代码啦。
Win API中描述:
typedef struct tagMOUSEINPUT { LONG dx; LONG dy; DWORD mouseData; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } MOUSEINPUT, *PMOUSEINPUT;
typedef struct tagKEYBDINPUT { WORD wVk; WORD wScan; DWORD dwFlags; DWORD time; ULONG_PTR dwExtraInfo; } KEYBDINPUT, *PKEYBDINPUT;
typedef struct tagHARDWAREINPUT { DWORD uMsg; WORD wParamL; WORD wParamH; } HARDWAREINPUT, *PHARDWAREINPUT;
C#中对应代码:
[StructLayout(LayoutKind.Sequential)]
public struct MouseInput
{
public Int32 dx;
public Int32 dy;
public Int32 Mousedata;
public Int32 dwFlag;
public Int32 time;
public IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagKEYBDINPUT
{
Int16 wVk;
Int16 wScan;
Int32 dwFlags;
Int32 time;
IntPtr dwExtraInfo;
}
[StructLayout(LayoutKind.Sequential)]
public struct tagHARDWAREINPUT
{
Int32 uMsg;
Int16 wParamL;
Int16 wParamH;
}
我主要是模拟鼠标,所以只需定义鼠标的flag值:
const int MouseEvent_Absolute = 0x8000;
const int MouserEvent_Hwheel = 0x01000;
const int MouseEvent_Move = 0x0001;
const int MouseEvent_Move_noCoalesce = 0x2000;
const int MouseEvent_LeftDown = 0x0002;
const int MouseEvent_LeftUp = 0x0004;
const int MouseEvent_MiddleDown = 0x0020;
const int MouseEvent_MiddleUp = 0x0040;
const int MouseEvent_RightDown = 0x0008;
const int MouseEvent_RightUp = 0x0010;
const int MouseEvent_Wheel = 0x0800;
const int MousseEvent_XUp = 0x0100;
const int MousseEvent_XDown = 0x0080;
c#中模拟鼠标操作的代码:
for (i = X; i <= X+width; i += 450)
//X为Flash窗口的左上角的x轴绝对坐标值。屏幕左上角坐标是(0,0)。width是Flash窗口宽度。
{
for (j = Y; j <= Y +height; j+=150) //Y为Flash窗口的左上角的y轴绝对坐标值。height是Flash窗口高度。
{
MouseInput myMinput = new MouseInput();
myMinput.dx = i;
myMinput.dy = j;
myMinput.Mousedata = https://www.jb51.net/cx361/archive/2011/12/11/0;
myMinput.dwFlag = MouseEvent_Absolute | MouseEvent_Move | MouseEvent_LeftDown | MouseEvent_LeftUp;
myMinput.time = 0;
Input[] myInput = new Input[1];
myInput[0] = new Input();
myInput[0].type = 0;
myInput[0].mi = myMinput;
UInt32 result = SendInput((uint)myInput.Length, myInput, Marshal.SizeOf(myInput[0].GetType()));
if (result == 0)
{
MessageBox.Show("fail");
}
}
}
知识点:将像素坐标转化为绝对坐标:
API中MouseInput结构中的dx,dy含义是绝对坐标,是相对屏幕的而言的,屏幕左上角的坐标为(0,0),右下角的坐标为(65535,65535)。而我们在C#中获得的对象(Frame,button,flash等)的坐标都是像素坐标,是跟你当前屏幕的分辨率相关的。假如你的显示器分辨率是1024*768,那么屏幕左上角的像素坐标是(0,0),右下角坐标为(1024,768)。转换函数如下:
dx = x * (65335/ScreenWidth) //x,y为像素坐标。
dy = y * (65335/ScreenHeight)//ScreenWidth和ScreenHeight,其实是当前显示器的分辨率,获得方法是ScreenWidth=Screen.PrimaryScreen.WorkingArea.Width;
ScreenHeight=Screen.PrimaryScreen.WorkingArea.Height;
猜你喜欢
- 通过本文你可以用非常简短的代码替代业务逻辑中的判null校验,并且很容易的在出现空指针的时候进行打日志或其他操作。注:如果对Java8新特性
- 这是自己写的简单的解析pcap文件,方便读取pcap文件,大家参考使用吧InputStream is = DataParser.class.
- 一个Java程序的执行要经过编译和执行(解释)这两个步骤,同时Java又是面向对象的编程语言。当子类和父类存在同一个方法,子类重写了父类的方
- java控制台输入有如下几个方法1、JDK 1.4 及以下版本读取的方法JDK 1.4 及以下的版本中要想从控制台中输入数据只有一种办法,即
- 一、介绍搜索了关于spring boot+vue的前后端分离实践项目很多,但是对于最基础登录功能的博客却是几年前的了。于是学习了好几个大神的
- 前言『 * 』其实源于设计模式中的代理模式,而代理模式就是使用代理对象完成用户请求,屏蔽用户对真实对象的访问。举个最简单的例子,比如我们想
- 本文实例讲述了C#实现回文检测的方法。分享给大家供大家参考。具体分析如下:回文:称正读和反读都相同的字符序列为“回文”,如“abba”、“a
- 做项目的时候需要对拿到的数据进行“清洗”,比如剔除一些不可能存在的身份证号码。查阅了网上的身份证号码验证算法,自己也总结一下。(一)18身份
- 本文实例讲述了JavaMail实现邮件发送的方法。分享给大家供大家参考。具体如下:下载 activation.jar 和 mail.jar配
- 目录登陆界面的实现登陆界面代码Login类login的监听类 LoginListener聊天界面运行图Client类代码Server代码登陆
- 本文实例讲述了java实现图片裁切的工具类。分享给大家供大家参考,具体如下:package com.yanek.util;import ja
- 需求当游戏显示3d场景及其UI的时候。玩家左右晃动手机的时候,UI界面会随之左右偏移。上下晃动的时候,3D场景会随之上下偏移。手机停止晃动的
- 汇总:1. 冒泡排序每轮循环确定最值;public void bubbleSort(int[] nums){ in
- 在说struts2的线程安全之前,先说一下,什么是线程安全?这是一个网友讲的。如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会
- 1.后台参数校验Spring Validation验证框架对参数的验证机制提供了@Validated(Spring JSR-303规范,是标
- @Value获取yml和properties配置参数Yml:#定时任务配置 application:
- 引言前一段有幸参与到一个智能家居项目的开发,由于之前都没有过这方面的开发经验,所以对智能硬件的开发模式和技术栈都颇为好奇。智能可燃气体报警器
- 我们的spring cloud微服务一般是打成jar包发布的,Linux下启动jar包和windows下一样,都是java -jar 包名,
- Mybatis获取参数值的两种方式:${},#{}${}本质:字符串拼接,注意:单引号要加上#{}:本质:占位符赋值一、 Mybatis获取
- 1.try-catch异常处理说明Java提供try和catch块来处理异常,try块用于包含可能出错的代码。catch块用于处理try块中