非激活窗口中响应鼠标滚动之理论篇
在最近工作中有一个优化交互的需求,分析后得知,其核心功能为能在非激活窗口中响应鼠标滚动消息,先就该需求进行前期方案验证。
同类产品实现
参照现有软件行为,操作系统为Win7
。以notepad++
,Chrome
两款软件为例。
- 当鼠标选中
notepad++
后,然后将鼠标转移到Chrome
界面后,上下滚动鼠标,Chrome
页面能够同步滚动。 - 当鼠标选中
Chrome
后,然后将鼠标转移到Notepad++
界面,上下滚动,Notepad++
不能同步滚动。
猜测是Chrome
对滚轮滚动消息进行了额外处理。既然现有软件支持该功能,那么在技术上就不是问题。接下来就是确定方案。在经过一番
搜索后,发现该需求的核心关键词是 scroll
, inactive
, hover
关联问题链接
- How to direct the mouse wheel input to control under cursor instead of focused?
- Windows上的焦点系统
- Mouse Wheel Scrolling not always working in Windows 10
- 微软鼠标指针交互文档
- On Windows 7, is there any way to make the scrollwheel's focus follow the mouse?
在Win10之前的版本,鼠标滚动会影响当前激活的窗口,而不影响鼠标当前悬停窗口。而Win10系统改变这种默认行为,当鼠标滚动时,会影响鼠标当前悬停窗口,而不是当前激活的窗口。该功能已经在Win10上得到验证,可通过以下来进行设置。
鼠标滚轮处理流程
在Windows系统上,焦点决定了由哪个窗口或者控件接收键盘输入信息,对于用户来说,最直观的感觉是,有光标闪动的窗口或者被高亮的控件,就有焦点。更进一步,这里的焦点仅仅控制键盘输入,鼠标输入与焦点没有直接关系。系统的焦点模型决定了鼠标是如何使得一个窗口获得焦点的,主要有以下三种模型:
-
click-to-focus
模型
鼠标点击的窗口可以获得焦点。这是Windows下最常见的一种模型,当用户点击鼠标时,鼠标当前位置下的窗口会被激活,并被置于所有窗口的最前面,可接受键盘输入。 -
focus-follow-mouse
模型鼠标当前位置下的窗口可以获取焦点。当鼠标移动到一个可以获得焦点的窗口范围内,用户无需点击窗口,即可激活该窗口,使得可以接收键盘输入。此时,该窗口不一定会置于最前方。当鼠标移出该窗口范围时,该窗口随之失去焦点。
-
sloppy-focus
模型
该模式与focus-follow-mouse
模型类似,不同之处在于,当鼠标移出该窗口范围时,该窗口不会失去焦点,直到鼠标移动到另外一个可以接收焦点的窗口时,输入焦点才会改变。
鼠标滚动消息是 WM_MOUSEWHEEL
,官方解释如下:
Sent to the active window when the mouse's horizontal scroll wheel is tilted or rotated.
The DefWindowProc function propagates the message to the window's parent.
There should be no internal forwarding of the message, since DefWindowProc propagates it up the parent chain until it finds a window that processes it.
A window receives this message through its WindowProc function.
默认情况下,鼠标滚轮消息会发往当前有焦点的窗口,默认的窗口处理过程会将该消息往上传递,直到该消息被处理为止。
可行的解决方案
由于在Win10系统下,默认鼠标滚轮对非激活窗口是生效的,但为了兼容性考虑,程序自身还是要额外处理。下面列出以下两类方案:
-
方案一
使用第三方软件,不搜不知道,一搜才知道有这么多的小软件可以满足该需求。- AlwaysWheelMouse,小巧免费的软件,可满足需求
- X-Mouse Button Control,允许重新配置鼠标行为.
- WizMouse, 允许你的鼠标在悬停窗口下工作
- taekwindow 在当前鼠标悬停窗口中使用滚轮,而不是当前焦点窗口。
-
方案二
自己搭轮子,利用鼠标钩子,将滚轮滚动消息传递给鼠标当前位置所在窗口即可。