KeyPress с несколькими модификаторами, не работающими в QWidget - PullRequest
0 голосов
/ 28 марта 2011

Я добавил переопределение для ключа основного виджета 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, то это сработает (конечно, при изменении второго условия), но не для них обоих. Ключ () не будет равен Qt :: Key_F11, пока я нажимаю F11. Я использую Windows.

Редактировать : проверено ведение журнала, и результат состоит в том, что Ctrl + Alt + F11 и Ctrl + Alt + F12 не отправляют ключевое событие (в отличие от других клавиш Ctrl + Alt + Fxx).

1 Ответ

2 голосов
/ 29 марта 2011

Ок, так что мне удалось решить это, хотя я не совсем доволен решением. По крайней мере, нет никакой тайны, и это работает:).

Причина, по которой я не получил горячие клавиши Ctrl + Alt + F11 и Ctrl + Alt + F12

Они были зарегистрированы как глобальные горячие клавиши. Мне удалось выяснить это с помощью программы ActiveHotkeys , которую он получил от участника stackoverflow moodforaday (большое спасибо за это!). По-видимому, не существует документированного способа узнать , какая программа зарегистрировала конкретную горячую клавишу (и она ничего не сделала в моей системе). См. Ветку moodforaday о проблеме .

Решение

Один из ответов в вышеупомянутой теме привел меня к другому вопросу . Ответ Эфотиниса был абсолютно идеальным для меня. У меня не было опыта с настройкой низкоуровневых зацепок клавиатуры, но это было не так сложно, как кажется. Ради будущего, вот как я это сделал в своем приложении 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);

Код хука (в основном из ответа эфотиниса):

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 проверяются на

Следует отметить , что когда вы вызываете функцию из ловушки, цикл обработки событий Qt только что начал обработку. Это означает, что до тех пор, пока вы не вернетесь из своей функции, он будет блокировать пользовательский интерфейс (останавливая его на несколько секунд). Если вы хотите показать диалог, как я, вместо exec(), вызовите raise, activateWindow и show, в то время как для модальности окна диалога задайте модальное значение (возможно, в его конструкторе).

Вы можете отменить регистрацию ловушки с помощью UnHookWindowsHookEx , если хотите (что происходит, когда модуль, содержащий ловушку, выгружается). Для этого сохраните возвращаемое значение вызова SetWindowsHookEx.

...