问题描述

表象

拾取元素时出现“穿透”,通过 WindowsAPI 拾取目标控件元素信息时,鼠标拾取元素的同时还执行了目标控件上的操作,这种情况是不允许的。(PS:通过单击进行拾取,常规情况下已做了屏蔽,不会执行目标控件的操作)

里象

经过分析和测试,得出结论。误操作的控件绑定的不是 Click事件 而是 MouseUp事件

分析屏蔽操作漏洞

分析屏蔽操作

在正确捕获到目标元素后会取消 CallNextHookEx事件 的执行,从而达到单击时屏蔽目标控件操作的目的。

分析捕获操作

目的是为了捕获“单击操作”,但 WindowsApi 只有 MouseDown 和 MouseUp事件。于是将两次都算作单击事件,并做了些许优化。即两次事件的间隔时间小于200ms则第二次事件执行时直接 return。

分析目标控件执行原因

对于绑定了 Click事件 的控件在第二次捕获操作后直接return, CallNextHookEx 检测不到完整的Click操作直接等于屏蔽效果。
对于绑定了 MouseUp事件 的控件在第二次捕获后直接return, CallNextHookEx 刚好可以检测到MouseUp事件就继续执行。
顺着此思路,第二次捕获后 return 时取消 CallNextHookEx事件 即可。

小插曲

觉得别人的想法有点“画蛇添足”,毕竟先捕获两次在屏蔽一次还出了问题,就想进行优化。换一种思路,若尝试只捕获一次,是否就不存在此问题?

第一次尝试理解出错,捕获了 MouseDown事件,以为会屏蔽 MouseUp事件。结果没捕获 MouseUp事件 导致目标控件的 MouseUp事件 直接执行了。
反过来捕获 MouseUp 就可以了。

为什么说我是小丑呢?

一开始觉得我这种写法还挺好,结果存在巨大的漏洞,即目标控件绑定了MouseDown事件我这种方式又会出现“穿透”。别人的写法虽然冗余但不存在此问题。

其他

初学时还有另一种想法:即都不执行 CallNextHookEx 事件会怎样,结果鼠标移动事件都无法触发,导致鼠标无法移动

单一捕获判断条件

 if (wParam == WM_LBUTTONDOWN)
 if (wParam == WM_LBUTTONUP)
鼠标移动512 ox200
鼠标按下513 0x201
鼠标弹起514 0x202
WM_LBUTTONDOWN 鼠标按下
WM_LBUTTONUP 鼠标弹起
捕获条件

捕获

 MouseHookProc(int nCode, int wParam, IntPtr lParam) 

CallNextHookEx 

 int CallNextHookEx( int idHook, int nCode, int wParam, IntPtr lParam) 

测试过程

测试用例:创建一个含三种事件的Java应用和C#应用(问题暴露在一个Java应用上,平常处理Windows平台的应用较多)

  • 推测一:两种应用分别来测试,究竟与平台是否相关联。通过测试发现与平台关联性不大
  • 推测二:是否和Web端的事件冒泡类似。通过一些测试发现二者并不想通
  • 推测三:控件注册的事件不一样,通过按住鼠标不放,能够捕获且不触发事件,大致推测与绑定的事件相关
  • 推测四:我点在了哪里?应用还是遮盖层,程序原本设计的有遮盖层,算是干扰项。通过质询同事了解到我们并没有点在遮盖层上。

由于一开始不知道系统是如何屏蔽原目标控件事件的,给问题分析带来很大的难度