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 を単独で試してみると (もちろん 2 番目の条件を変更しながら) 機能しますが、両方では機能しません。F11 を押している間、key() は Qt::Key_F11 と等しくなりません。私は窓を使用しています。

編集: ロギングでチェックした結果、Ctrl+Alt+F11 および Ctrl+Alt+F12 はキー イベントを送信しません (他の Ctrl+Alt+Fxx キーは送信します)。

4

1 に答える 1

2

うーん、私はそれを解決することができましたが、私は解決策に満足していません. 少なくとも謎はなく、機能します:)。

ホットキー Ctrl+Alt+F11 と Ctrl+Alt+F12 を受け取らなかった理由

それらはグローバルホットキーとして登録されました。私はこれを、スタックオーバーフローのメンバーである気分の仲間のActiveHotkeysプログラムを使用して見つけることができました (どうもありがとう!)。どのプログラムが特定のホットキーを登録したかを調べる文書化された方法はないようです (そして、私のシステムでは何もしませんでした)。この問題については、moodforaday のスレッドを参照してください。

ソリューション

前述のスレッドの回答の 1 つから、別の質問にたどり着きました。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 をチェックすることですが、私はそれを行うのが面倒です。:)

注意すべきことの 1 つは、フックから関数を呼び出すと、Qt イベント ループが処理を開始したばかりであるということです。つまり、関数から戻らない限り、UI がブロックされます (数秒間フリーズします)。私のようにダイアログを表示したい場合は、 の代わりにandexec()を呼び出し、ダイアログのウィンドウ モダリティをモーダルに設定します (コンストラクターで)。raise, activateWindowshow

必要に応じてUnHookWindowsHookExでフックの登録を解除できます (これは、フックを含むモジュールがアンロードされたときに発生します)。これを行うには、SetWindowsHookEx 呼び出しの戻り値を保存します。

于 2011-03-29T14:30:55.733 に答える