具有多个修饰符的KeyPress在QWidget中不起作用

时间:2011-03-28 16:41:17

标签: windows qt qkeyevent

我为主要小部件的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键则执行此操作)。

1 个答案:

答案 0 :(得分:2)

Oook,所以我设法解决了它,虽然我对解决方案并不满意。至少没有神秘感,它有效:)。

我没有收到热键Ctrl + Alt + F11和Ctrl + Alt + F12

的原因

他们被注册为全球热键。我设法使用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, activateWindowshow,同时将对话框的窗口模态设置为模态(可能在其构造函数中)。 / p>

如果需要,可以取消注册UnHookWindowsHookEx的钩子(当卸载包含钩子的模块时会发生这种情况)。为此,请保存SetWindowsHookEx调用的返回值。