我为主要小部件的keyPressEvent添加了覆盖:
void MainWindow::keyPressEvent(QKeyEvent* e)
{
if (e->key() == Qt::Key_F11)
{
if (e->modifiers() & Qt::AltModifier && e->modifiers() & Qt::ControlModifier)
{
// do stuff
}
}
}
问题在于它不起作用。如果我单独尝试AltModifier或ControlModifier它可以工作(当然,在改变第二个条件时),但不能同时使用它们。当我按下F11时,key()将不等于Qt :: Key_F11。我正在使用Windows。
编辑:使用日志记录进行检查,结果是Ctrl + Alt + F11和Ctrl + Alt + F12不发送键事件(而其他Ctrl + Alt + Fxx键则执行此操作)。
答案 0 :(得分:2)
Oook,所以我设法解决了它,虽然我对解决方案并不满意。至少没有神秘感,它有效:)。
他们被注册为全球热键。我设法使用stackoverflow成员moodforaday的ActiveHotkeys程序找到了这个(非常感谢它!)。显然没有记录的方法来找出哪个程序注册了一个特定的热键(并且它在我的系统上没有做任何事情)。请参阅moodforaday's thread about the issue。
上述帖子中的一个答案让我another question。 Efotinis的回答对我来说绝对是完美的。我没有设置低级键盘挂钩的经验,但它听起来并不像听起来那么困难。为了将来的缘故,以下是我在Qt应用程序中的使用方法:
在我的mainwindow.h中:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
// ... code
private:
void tryLogin();
friend LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
};
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam);
在我的mainwindow.cpp中:
// setting up the hook in the constructor
SetWindowsHookEx(WH_KEYBOARD_LL,
LowLevelKeyboardProc,
NULL,
0);
钩子代码(主要来自efotinis的答案):
LRESULT CALLBACK LowLevelKeyboardProc(int code, WPARAM wparam, LPARAM lparam)
{
KBDLLHOOKSTRUCT* kllhs = reinterpret_cast<KBDLLHOOKSTRUCT*>(lparam);
if (code == HC_ACTION)
{
if (wparam == WM_KEYDOWN && kllhs->vkCode == VK_F12 &&
(GetAsyncKeyState(VK_MENU) < 0 && GetAsyncKeyState(VK_CONTROL) < 0))
{
MainWindow* w = dynamic_cast<MainWindow*>(qApp->activeWindow());
if (NULL != w)
{
w->tryLogin(); // this should not be blocking!
return 1;
}
}
}
return CallNextHookEx(0, code, wparam, lparam);
}
如您所见,我们从全局QApplication对象获取指向应用程序窗口的指针。我们使用dynamic_cast所以在活动窗口中碰巧不是MainWindow实例,我们会得到一个NULL指针。
如果您想知道为什么检查GetAsyncKeyState调用&lt; 0,这是因为如果键关闭,此函数将返回MSB设置。当设置MSB时,SHORT编号为负(在x86 / x64和兼容平台上)。如果windows被移植到一个平台,其中有符号整数的表示方式不同,则此代码可能会中断。绝对正确的方法是创建一个16位掩码并使用它来检查MSB,但我很懒。 :)
需要注意的一件事是是当你从钩子中调用一个函数时,Qt事件循环才刚刚开始处理。这意味着在您不从函数返回之前,它将阻止UI(将其冻结几秒钟)。如果你想显示一个像我一样的对话框而不是exec()
,请调用raise, activateWindow
和show
,同时将对话框的窗口模态设置为模态(可能在其构造函数中)。 / p>
如果需要,可以取消注册UnHookWindowsHookEx的钩子(当卸载包含钩子的模块时会发生这种情况)。为此,请保存SetWindowsHookEx调用的返回值。