来自子控件的键盘消息
Posted
技术标签:
【中文标题】来自子控件的键盘消息【英文标题】:Keyboard messages from child controls 【发布时间】:2013-06-04 18:22:17 【问题描述】:我目前正在开发一个使用 WIN32 API 的用户界面 DLL。 DLL 必须适用于多种平台、XP、WIN CE 等。我已设法合并停靠、锚定等,但似乎有关于所有者绘制按钮的问题。我可以绘制按钮的正确状态,焦点,点击,默认。但是,我无法收到关键通知。如果用户按下回车键,我特别想对当前具有焦点的按钮执行单击操作。
请注意,我使用的是 Windows 消息循环而不是对话消息循环。我使用 windows 挂钩来挂钩窗口创建并将用户数据设置为“指向”我的控件实例。如果我在主消息循环中测试 WM_KEYDOWN,我可以获得按钮控件实例的句柄,并将消息转发到相关控件。不幸的是,我正在处理大量遗留代码,这可能不是一个理想的解决方案。
所以,我的问题是什么是最好的前进方式。子类化按钮控件的窗口过程是可行的选择还是有更简单的方法?
非常感谢。
【问题讨论】:
如果窗口有焦点,它应该接收键输入,而不需要自定义循环。你用 Spyxx 调查过吗? 我同意,但我猜按钮控件在内部处理按键。我需要基本上确保如果按钮具有焦点并且用户按下回车键,则调用“OnClick”处理程序。 如果您使用现有的控件类,您不能只是子类化窗口过程来拦截您的消息吗? 这有点出乎我的意料,我只是想知道是否有更简单的方法。子类化是如此痛苦:-) 好吧,子类化窗口 proc 只是调用 GetWindowLong(GWLP_WNDPROC) 来捕获现有的 proc 和 SetWindowLong(GWLP_WNDPROC) 来包装你的钩子。 【参考方案1】:上面的cmets是正确的。具有焦点的按钮应该获取关键信息。但是按钮不(自己)响应 Enter —— 它们响应 Space。听起来您缺少的是典型的对话框键盘导航,例如 Tab 键移动焦点和 Enter 激活“默认”按钮。
如果您有一个典型的 Windows 消息泵,并且您希望键盘行为通常与对话框相关联,那么您需要在消息循环中使用 IsDialogMessage API。这意味着您的窗口本质上是一个“无模式对话框”。
【讨论】:
感谢阿德里安的回复。问题是主窗口就是这样,一个窗口而不是一个对话框。如前所述,我必须使用大量遗留代码。我猜 IsDialogMessage 仅在主循环是对话消息循环而不是标准 winmain 循环时才适用? 抱歉,我阅读了您建议的链接。似乎您实际上可以与任何窗口一起使用。也许这是我需要研究的路线。 是的,您可以在任何窗口中使用它。您只需要跟踪您希望键盘行为用于哪个窗口(或多个窗口),因为您需要将窗口句柄传递给函数。 好的,所以我猜在我的主消息循环中,我得到了焦点窗口并使用 IsDialogMessage。抱歉,就像我说的那样,我开发原始 WIN32 代码已经很多年了。 不,有焦点的窗口很可能是一个像按钮一样的控件。对于 IsDialogMessage,您需要包含窗口的句柄,这可能是您的应用程序的“主”窗口。【参考方案2】:看起来标准窗口 proc 子类化应该可以解决问题。详情请见http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx。
【讨论】:
谢谢斯科特。我不得不问,如果我对 Button 控件进行子类化并使用 CallWindowProc,我的子类化按钮是否仍会使用主题等。目前不是问题,但也许一旦我处理 Windows 7/8 等问题。我只问,因为我相信以后的 Windows 版本使用不同的方法进行子类化。 绝对 - 你的钩子应该是非侵入性的,只观察和处理 WM_KEYDOWN 等。 好的,最后一个问题 :-) 什么时候最好插入我的 WNDPROC,在父通知 WM_CREATE 之后,在我的 CBT 挂钩程序等中。谢谢 :-) 您可以在您期望开始接收 kbd 输入之前的任何明确时间执行此操作 - WM_CREATE 似乎是合理的。您可能还希望您的钩子 proc 也自行卸载,例如监视 WM_DESTROY,以通过 SetWindowLong 恢复原始 proc。 啊,是的,好点子。谢谢斯科特,我会尝试你的建议。谁会想到捕捉一个按键需要这么多努力:-)以上是关于来自子控件的键盘消息的主要内容,如果未能解决你的问题,请参考以下文章