Question

J'ai ajouté un remplacement pour le keyPressEvent de mon widget principal :

void MainWindow::keyPressEvent(QKeyEvent* e)
{
    if (e->key() == Qt::Key_F11)
    {
        if (e->modifiers() & Qt::AltModifier && e->modifiers() & Qt::ControlModifier)
        {
            // do stuff
        }
    }
}

Le problème c'est que ça ne marche pas.Si j'essaie AltModifier ou ControlModifier seul, cela fonctionne (en changeant la deuxième condition bien sûr), mais pas pour les deux.Le key() ne sera pas égal à Qt::Key_F11 tant que j'appuie sur F11.J'utilise Windows.

Modifier:vérifié avec la journalisation et le résultat est que Ctrl+Alt+F11 et Ctrl+Alt+F12 n'envoient pas d'événement de clé (contrairement aux autres touches Ctrl+Alt+Fxx le font).

Était-ce utile?

La solution

Oook, donc j'ai réussi à le résoudre même si je ne suis pas vraiment satisfait de la solution.Au moins il n'y a pas de mystère et ça marche :).

La raison pour laquelle je n'ai pas reçu les raccourcis clavier Ctrl+Alt+F11 et Ctrl+Alt+F12

Ils ont été enregistrés comme raccourcis clavier globaux.J'ai réussi à le découvrir en utilisant le Raccourcis actifs programme du collègue membre de stackoverflow moodforaday (merci beaucoup pour cela !).Apparemment, il n'existe aucun moyen documenté de le savoir. lequel le programme a enregistré un raccourci clavier particulier (et il n'a rien fait sur mon système).Voir le fil de discussion de moodforaday sur le problème.

La solution

L'une des réponses dans le fil de discussion susmentionné m'a amené à une autre question.La réponse d'Efotinis était absolument parfaite pour moi.Je n'avais aucune expérience dans la configuration de crochets de clavier de bas niveau, mais ce n'était pas aussi difficile qu'il y paraît.Pour l'avenir, voici comment j'ai procédé dans mon application Qt :

Dans ma fenêtre principale.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);

Dans mon mainwindow.cpp :

// setting up the hook in the constructor
SetWindowsHookEx(WH_KEYBOARD_LL,
                     LowLevelKeyboardProc,
                     NULL,
                     0);

Le code d'accroche (principalement issu de la réponse d'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);
}

Comme vous pouvez le voir, nous obtenons le pointeur vers la fenêtre de l'application à partir de l'objet global QApplication.Nous utilisons Dynamic_cast donc, dans la fenêtre active, il ne s'agit pas d'une instance de MainWindow, nous obtiendrons un pointeur NULL.

Si vous vous demandez pourquoi les appels GetAsyncKeyState sont vérifiés pour < 0, c'est parce que cette fonction renvoie avec MSB défini si la clé est enfoncée.Et lorsque le MSB est défini, le nombre SHORT est négatif (sur les plateformes x86/x64 et compatibles).Si jamais Windows est porté sur une plate-forme où les entiers signés sont représentés différemment, ce code pourrait être interrompu.La manière tout à fait appropriée serait de créer un masque de 16 bits et de l'utiliser pour vérifier le MSB, mais je suis paresseux de le faire.:)

Une chose à noter est que lorsque vous appelez une fonction depuis votre hook, la boucle d'événements Qt vient de commencer son traitement.Cela signifie que jusqu'à ce que vous ne reveniez pas de votre fonction, cela bloquera l'interface utilisateur (la gelant pendant quelques secondes).Si vous vouliez afficher une boîte de dialogue comme je l'ai fait, au lieu de exec(), appel raise, activateWindow et show, tout en définissant la modalité de fenêtre de la boîte de dialogue sur modal (dans son constructeur peut-être).

Vous pouvez désenregistrer le hook avec DécrocherWindowsHookEx si vous le souhaitez (ce qui se produit lorsque le module contenant le hook est déchargé).Pour ce faire, enregistrez la valeur de retour de l’appel SetWindowsHookEx.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top