惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
宝玉的分享
宝玉的分享
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Vulnerabilities – Threatpost
博客园_首页
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
C
Cyber Attacks, Cyber Crime and Cyber Security
罗磊的独立博客
V
Visual Studio Blog
Know Your Adversary
Know Your Adversary
Hacker News - Newest:
Hacker News - Newest: "LLM"
美团技术团队
L
LINUX DO - 最新话题
The Last Watchdog
The Last Watchdog
博客园 - 三生石上(FineUI控件)
T
Tor Project blog
云风的 BLOG
云风的 BLOG
N
Netflix TechBlog - Medium
MyScale Blog
MyScale Blog
The GitHub Blog
The GitHub Blog
有赞技术团队
有赞技术团队
I
InfoQ
Last Week in AI
Last Week in AI
V2EX - 技术
V2EX - 技术
量子位
S
Secure Thoughts
L
LangChain Blog
The Hacker News
The Hacker News
H
Help Net Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
小众软件
小众软件
K
Kaspersky official blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Google Online Security Blog
Google Online Security Blog
I
Intezer
Vercel News
Vercel News
Hacker News: Ask HN
Hacker News: Ask HN
Cisco Talos Blog
Cisco Talos Blog
Google DeepMind News
Google DeepMind News
S
Securelist
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
Help Net Security
Help Net Security
Martin Fowler
Martin Fowler
爱范儿
爱范儿
Y
Y Combinator Blog
C
Check Point Blog

博客园 - 游民一族

VR发展的最大障碍在于内容? 无法修改Form尺寸的解决方法 [ATL/ActiveX]全屏显示ActiveX控件 近期业余生活以及计划(持续更新) 远程控制之屏幕截取 小结 Javascript: IE中命名函数直接量的Bug? - 游民一族 - 博客园 ASP.NET AJAX Client Library: 更繁?更简? ASP.NET动态创建控件之绝境求生 喜讯,公司换宽屏液晶显示器了 分享:基于UDP协议实现可靠的数据传输 C#线程:只要任何一个线程在运行,程序就不退出?! 基于Web的仿WF工作流设计器 [ASP.NET]ASP.NET 2.0中Membership的UserID问题 [ASP.NET AJAX]谨记给UpdatePanel中动态添加的控件赋ID VS 2005 BUG: 新增JScript文件编码问题引起乱码? [ASP.NET]如何灵活定制皮肤/页面:布局设计器介绍 过滤ASP.NET输出HTML中的无用空格 在JavaScript中实现命名空间 [C#]NHibernate处理多帐套问题
[C#]mouse_event模拟点击时坐标参数无效?!
游民一族 · 2007-06-29 · via 博客园 - 游民一族

实现远程屏幕控制必不可少的函数之一就是mouse_event(或者SendInput),这个函数可以用来模拟鼠标移动、单击、双击等功能,但是描述这个函数的文档可谓少之又少,几段雷同的代码转来转去就是没有一些深入讨论的,MSDN中描述也语焉不详。在昨天试验中发现一个问题,希望有研究的“同志”能够帮我解答,^_^

在如下模拟鼠标单击的代码中,我希望在相对屏幕左上角(10, 10)的位置点击一下:

1 int dx = 10 * 65535 / Screen.PrimaryScreen.Bounds.Width;
2 int dy = 10 * 65535 / Screen.PrimaryScreen.Bounds.Height;
3 
4 mouse_event((int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), dx, dy, 0, IntPtr.Zero);
5 mouse_event((int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), dx, dy, 0, IntPtr.Zero);

无论从哪个角度看,上面这段代码也是没啥问题的,过程相当简单,首先进行坐标变换,然后两次调用mouse_event模拟鼠标按下和弹起,然而,代码的运行效果却出乎我的意料,程序并没有在(10, 10)的位置模拟鼠标单击事件,而是在当前位置触发鼠标单击!

经过多次验证,发现对于鼠标点击而言,dx、dy这两个参数好像不起作用,无论对这两个参数设置什么值,鼠标点击事件永远在当前位置触发!

猜测:为什么会这样呢?一个比较合理的解释是为了避免在界面上给用户造成混淆,从而禁止了在非鼠标当前位置处触发鼠标单击事件!具体原因不详!!!

引申:由于不能在任意位置触发鼠标点击事件,假如我有这么一个需要:鼠标不移动,在(10,10)位置点击一下!那我们应该怎么办呢?在上面假设成立的情况下我们是无法直接实现这个需求的,下面提供一个间接的方法:

 1 POINT p = new POINT();
 2 GetCursorPos(out p);
 3 
 4 try
 5 {
 6     ShowCursor(false);
 7     SetCursorPos(1010);
 8 
 9     mouse_event((int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), 000, IntPtr.Zero);
10     mouse_event((int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), 000, IntPtr.Zero);
11 }
12 finally
13 {
14     SetCursorPos(p.X, p.Y);
15     ShowCursor(true);
16 }
17 


在上面的代码中,通过隐藏鼠标,最终将鼠标位置移动到最初位置并显示解决这个问题,因为速度很快,用户几乎不会察觉!

P.S. 假如哪位对mouse_event这个函数比较熟悉的话,望不吝赐教!

完整示例代码://UPDATE: 代码折叠功能有问题,我选择“全部折叠”后居然无法展开了,奇怪!!!

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication2
{
    
public partial class Form1 : Form
    
{
        [DllImport(
"User32")]
        
public extern static void mouse_event(int dwFlags, int dx, int dy, int dwData, IntPtr dwExtraInfo);

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

        [DllImport(
"User32")]
        
public extern static bool GetCursorPos(out POINT p);

        [DllImport(
"User32")]
        
public extern static int ShowCursor(bool bShow);

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


        [Flags]
        
public enum MouseEventFlags
        
{
            Move        
= 0x0001,
            LeftDown    
= 0x0002,
            LeftUp      
= 0x0004,
            RightDown   
= 0x0008,
            RightUp     
= 0x0010,
            MiddleDown  
= 0x0020,
            MiddleUp    
= 0x0040,
            Wheel       
= 0x0800,
            Absolute    
= 0x8000
        }


        
public Form1()
        
{
            InitializeComponent();
        }


        
private void Test1_Click(object sender, EventArgs e)
        
{
            
int dx = 10 * 65535 / Screen.PrimaryScreen.Bounds.Width;
            
int dy = 10 * 65535 / Screen.PrimaryScreen.Bounds.Height;

            mouse_event((
int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), dx, dy, 0, IntPtr.Zero);
            mouse_event((
int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), dx, dy, 0, IntPtr.Zero);
        }


        
private void Test2_Click(object sender, EventArgs e)
        
{
            POINT p 
= new POINT();
            GetCursorPos(
out p);

            
try
            
{
                ShowCursor(
false);
                SetCursorPos(
1010);

                mouse_event((
int)(MouseEventFlags.LeftDown | MouseEventFlags.Absolute), 000, IntPtr.Zero);
                mouse_event((
int)(MouseEventFlags.LeftUp | MouseEventFlags.Absolute), 000, IntPtr.Zero);
            }

            
finally
            
{
                SetCursorPos(p.X, p.Y);
                ShowCursor(
true);
            }

        }

    }

}