windows - KeyPress med flere modifikatorer, der ikke fungerer i QWidget

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har tilføjet en tilsidesættelse af min vigtigste widget s keyPressEvent:


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


Problemet er, at det ikke virker. Hvis jeg prøver AltModifier eller ControlModifier alene, virker det (mens du ændrer den anden betingelse selvfølgelig), men ikke for dem begge. Nøglen () vandt 't svarende til Qt :: Key\_F11 mens jeg trykker på F11. Jeg bruger m windows.


Rediger : Markeret med logføring, og resultatet er, at Ctrl + Alt + F11 og Ctrl + Alt + F12 ikke sender en nøglehændelse (mens andre Ctrl + Alt + Fxx-taster gør).

Bedste reference


Oook, så jeg formåede at løse det, selvom jeg ikke er helt tilfreds med løsningen. I hvert fald er der intet mysterium, og det virker :).


Grunden til, at jeg ikke fik hurtigtasterne Ctrl + Alt + F11 og Ctrl + Alt + F12



De blev registreret som globale genvejstaster. Det lykkedes mig at finde ud af dette ved hjælp af ActiveHotkeys-programmet for medspilleren stackoverflow member moodforaday (mange tak for det!). Tilsyneladende er der ingen dokumenteret måde at finde ud af hvilket -program der registrerede en bestemt genvejstast (og det gjorde ikke noget på mit system). Se moodforadays tråd om problemet. [8] [[


Løsningen



Et af svarene i ovennævnte tråd førte mig til et andet spørgsmål. Efotinis 'svaret var helt perfekt for mig. Jeg havde ikke erfaring med at oprette lavtstående tastatur kroge, men det var næsten ikke så svært som det lyder. For fremtidens skyld er det her, hvordan jeg gjorde det i min Qt ansøgning :


I min 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);


I min mainwindow.cpp:


// setting up the hook in the constructor
SetWindowsHookEx(WH\_KEYBOARD\_LL,
                     LowLevelKeyboardProc,
                     NULL,
                     0);


Krogkoden (for det meste fra efotinis 'svar):


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);
}


Som du kan se, får vi markøren til programvinduet fra det globale QApplication-objekt. Vi bruger dynamic\_cast, så i det aktive vindue sker der ikke at være en MainWindow eksempel vi ville få en NULL pointer.


Hvis du undrer dig over, hvorfor GetAsyncKeyState-opkald kontrolleres for < 0, det er fordi denne funktion vender tilbage med MSB-sæt, hvis nøglen er nede. Og når MSB er indstillet, er SHORT-nummeret negativt (på x86/x64 og kompatible platforme). Hvis vinduer nogensinde bliver portet til en platform, hvor signeret heltal er repræsenteret forskelligt, denne kode kan bryde. Den helt rigtige måde ville være at oprette en 16-bit maske og bruge det til at tjekke MSB, men jeg er doven til at gøre det. :)


En ting at bemærke er, at når du kalder en funktion fra din krog, har Qt-eventsløjfen lige begyndt at behandle. Det betyder at indtil du ikke kommer tilbage fra din funktion, vil den blokere brugergrænsefladen (indefrysning af det i nogle sekunder). Hvis du vil vise en dialog som jeg gjorde, i stedet for exec(), ring raise, activateWindow]] og show, mens du indstiller vinduesmodaliteten af ​​dialogen til modal (i sin konstruktor måske).


Du kan afregistrere krogen med UnHookWindowsHookEx, hvis du vil (som sker, når modulet, der indeholder krogen, er losset). For at gøre dette skal du gemme returværdien af ​​SetWindowsHookEx-opkaldet. [11]