【发布时间】:2012-03-13 14:56:08
【问题描述】:
我有一个 Winforms 应用程序,它的面板中有两个 PDF 查看器(非托管 C++)。
我希望为项目处理提供应用程序范围的热键(打开、保存、关闭、...),即使用户关注托管的 PDF 查看器也可以使用。
我设法通过 Winapi 和 RegisterHotKey 实现了这一点,但客户不喜欢那些是系统范围的(例如,它们禁用了相同的 MS Word 热键)
我确实尝试在表单的激活/停用事件上禁用和启用全局热键,但是即使我不离开自己的应用程序也会出现这些事件,例如在顶部菜单条目或对话框上。
对于应用程序范围的热键是否有其他解决方案,即使焦点在托管应用程序上也可以工作?
解决方案:
在主窗体中,我处理这样的激活和停用事件:
public void PDFPicker_Activated(object sender, EventArgs e)
{
var foregroundHwnd = GUI.winapiwrap.GetForegroundWindow();
if (foregroundHwnd==this.Handle || this.OwnedForms.Any(form => form.Handle==foregroundHwnd))
{
if (!this.hotkeys.Any())
{
registerHotkeys();
this.Text = "Hotkeys just registered";
}
}
}
public void PDFPicker_Deactivate(object sender, EventArgs e)
{
var foregroundHwnd = GUI.winapiwrap.GetForegroundWindow();
if (foregroundHwnd == this.Handle || this.OwnedForms.Any(form => form.Handle == foregroundHwnd))
{
}
else
{
unregisterHotkeys();
this.Text = "Hotkeys off";
}
}
然后在对话框中,它位于 OwnedForms 数组中,我只调用这个:
private void QuestionPostingPanel_Activated(object sender, EventArgs e)
{
parent.PDFPicker_Activated(sender, e);
}
private void QuestionPostingPanel_Deactivate(object sender, EventArgs e)
{
parent.PDFPicker_Deactivate(sender, e);
}
如果有更多这样的对话框,我会继承 AbstractDialog : Form,添加这两个事件函数和对父级的引用,然后从这个 AbstractDialog 继承所有这些。
在注册/注销 GlobalHotkeys 时,当我尝试并行执行此操作时,这对我来说是个问题 - 全局热键绑定到一个线程。
【问题讨论】:
-
如果您的应用程序不是活动窗口,您不能检查活动应用程序并且不处理按键吗?或者使用一些计时器轮询来检查活动窗口,如果您的应用程序不是活动窗口,则禁用键盘快捷键。
-
第一个会禁用其他应用程序的热键...