翻译《The Old New Thing》- What’s with this MSH_MOUSEWHEEL message?

103 篇文章 0 订阅
53 篇文章 1 订阅

What's with this MSH_MOUSEWHEEL message? - The Old New Thing (microsoft.com)icon-default.png?t=N7T8https://devblogs.microsoft.com/oldnewthing/20080806-00/?p=21353

Raymond Chen 2008年06月06日


MSH_MOUSEWHEEL 消息是怎么回事?

        硬件团队正在研发一种鼠标滚轮设备,并需要一种方法让应用程序支持这种鼠标。一种方法是说:“我们将开始销售这种带滚轮的鼠标,但在下一代Windows发布之前,没有任何应用程序可以使用它。”当然,这意味着要等到Windows NT 4发布,而谁也不知道那会是什么时候。此外,这意味着人们必须升级Windows才能利用他们的新鼠标。可以想象,他们对“等几年”的计划并不满意。

        在此期间,他们为应用程序响应鼠标滚轮提出了一种临时机制。于是引入了zmouse.h头文件及其注册消息MSH_MOUSEWHEEL。当你安装滚轮鼠标驱动程序时,它会监听硬件的滚轮事件,并在鼠标滚轮转动时发布这个新消息,应用程序只需响应WM_MOUSEWHEEL消息(如果运行在支持该消息的Windows版本上)或MSH_MOUSEWHEEL消息(如果运行在不支持该消息的旧版Windows上)。不幸的是,这两个消息的行为不同,所以不是简单地编写:

if (uMsg == WM_MOUSEWHEEL || uMsg == g_msgWheel) {
  // 处理滚轮事件
}

(下面几段总结了MSDN中已经明确的内容;如果已经知道这些消息的工作原理,可以跳过。)

        首先,让我们看看WM_MOUSEWHEEL。这个消息被传递到拥有焦点的窗口(在SetFocus的意义上)。如果窗口过程不处理这个消息,只是将其传递给DefWindowProc函数,那么DefWindowProc函数会将这个消息转发给窗口的父窗口。通过这种方式,WM_MOUSEWHEEL消息自动地从焦点窗口“向外冒泡”到父窗口链,直到有人最终处理这个消息(或者根本没有被处理)。

        另一方面,MSH_MOUSEWHEEL消息从外部向内部工作。它被传递到前景窗口(在SetForegroundWindow的意义上)。如果窗口过程不想处理这个消息,它可以将消息转发给它选择的子窗口,直到其中一个返回TRUE表示消息已被处理,或者直到没有更多的候选者。

        我将以表格形式总结这些差异,因为人们似乎非常喜欢表格。

WM_MOUSEWHEELMSH_MOUSEWHEEL
传播方向内向外外向内
传播机制DefWindowProcSendMessage
处理自动手动:应用程序检查从子窗口返回的值以确定接下来要做什么
如果已处理的返回值TRUE
如果未处理的返回值DefWindowProcFALSE

        注意WM_MOUSEWHEEL更简单,内向外的传播机制保留了其他消息(如WM_CONTEXTMENUWM_SETCURSOR)的精神。

        为什么MSH_MOUSEWHEEL不能以相同的方式进行?

        首先,MSH_MOUSEWHEEL没有修改DefWindowProc函数的特权。毕竟,引入这个消息的整个目的,是因为我们正试图向一个早于鼠标滚轮的旧操作系统添加滚轮支持。换句话说,如果我们能修改DefWindowProc来处理MSH_MOUSEWHEEL消息,那么我们一开始就不需要MSH_MOUSEWHEEL消息;我们只需要修改DefWindowProc来处理WM_MOUSEWHEEL消息。

        前一段中的论点是一个令人沮丧的常见问题。面对问题X和变通方法Y,有人会问:“为什么不用方法Z?”然而,如果你看看方法Z,你会发现它受到与问题X完全相同的问题。

这里有一个“困惑的变通方法”的真实世界例子:

“由于I-90桥关闭了,我不能乘坐550公交车从贝尔维尤到安全球场。相反,我将乘坐230到雷德蒙德,然后换乘545。”

——嗯,那很傻。为什么不乘坐245到东门,然后换乘554呢?这样更快。

“嗯,554也使用I-90桥。”

        好的,所以你不能更改DefWindowProc,但为什么不至少从内向外传播MSH_MOUSEWHEEL而不是从外向内呢?

        从焦点窗口开始的假设是你可以找出焦点窗口是什么,但如果你注意到了《每个Win32程序员都应该知道的五件事》,你就会知道每个线程都有自己的焦点窗口。(不是吹毛求疵的真,但足够真。)因此,当注入MSH_MOUSEWHEEL消息的帮助程序调用GetFocus时,它只会得到自己的焦点窗口,而不是控制前景窗口的线程的焦点窗口。(记住,我们谈论的是1996年,远在GetGUIThreadInfo函数发明之前。历史爱好者可以更多地了解鼠标滚轮的发明者。)由于内部向外是不可能的,这基本上就迫使了外部向内部。

        现在你知道鼠标滚轮消息是如何工作的,你可以解释这位客户看到的行为:

我注意到WM_MOUSEWHEEL消息被传递到了错误的子窗口。 我有一个父窗口和两个子窗口。 即使我把鼠标指针移动到子窗口1上, WM_MOUSEWHEEL却发送到了子窗口2。

  • 14
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x0007

可不可奖励我吃只毛嘴鸡 馋😋

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值