0

我为我的主要小部件的 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。我正在使用窗户。

编辑:检查日志,结果是 Ctrl+Alt+F11 和 Ctrl+Alt+F12 不发送键事件(而其他 Ctrl+Alt+Fxx 键发送)。

4

1 回答 1

2

哎呀,所以我设法解决了它,尽管我对解决方案并不完全满意。至少没有什么神秘的,它的工作原理:)。

我没有收到快捷键 Ctrl+Alt+F11 和 Ctrl+Alt+F12 的原因

它们被注册为全局热键。我设法使用 stackoverflow 成员 moodforaday 的ActiveHotkeys程序找到了这一点(非常感谢!)。显然没有记录的方法可以找出哪个程序注册了特定的热键(并且它在我的系统上没有做任何事情)。请参阅moodforaday 关于该问题的主题

解决方案

上述线程中的一个答案使我想到了另一个问题。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 调用是否为 < 0,这是因为如果键按下,此函数会返回并设置 MSB。并且当设置 MSB 时,SHORT 数为负数(在 x86/x64 和兼容平台上)。如果 Windows 被移植到有符号整数表示不同的平台,则此代码可能会中断。绝对正确的方法是创建一个 16 位掩码并使用它来检查 MSB,但我懒得这样做。:)

需要注意的一点是,当您从钩子调用函数时,Qt 事件循环才刚刚开始处理。这意味着直到你没有从你的函数返回,它会阻塞 UI(冻结它几秒钟)。如果您想像我一样显示一个对话框,而不是exec()调用raise, activateWindowand show,同时将对话框的窗口模式设置为模式(可能在其构造函数中)。

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

于 2011-03-29T14:30:55.733 回答