Как распознать события KeyPress, используя Qt и X11events? - PullRequest
2 голосов
/ 04 мая 2011

Я работаю в проекте, который должен распознавать позиции физических клавиш, Control, Shift и Winkey. Мне нужно знать, где находится каждая из клавиш «Влево» или «Вправо» на клавиатуре.

Для этого мне нужно обработать X11events и WinEvents, используя Qt. Я сделал это довольно хорошо в Windows, забыв ужасную часть об Alt Gr, я пока не могу справиться. В Linux я пытался сделать то же самое:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#if WIN32
#include <windows.h>
#else
#include <X11/XKBlib.h>
#ifdef KeyPress
const int XKeyPress = KeyPress;
#undef KeyPress
#endif    
#endif

#include "main.h"
#include <QFile>
#include <QDebug>
#include <QX11Info>


#if WIN32
bool MainWindow::winEvent( MSG* msg, long* result )
{  
    if(msg->message == WM_KEYDOWN || msg->message == WM_HOTKEY)
    {   
        SHORT state;
        switch(msg->wParam)
        {

        case VK_CONTROL:  
            // the Alt Gr is handled using Ctrl+Alt+Shift (I Guess)
            state = GetKeyState(VK_SHIFT);
            if(state == TRUE)
                keyPressEvent(msg->wParam, "Key_AltGr");
            else{
                state = GetKeyState(VK_LCONTROL);
                if(state & VK_LCONTROL)
                    keyPressEvent(msg->wParam, "Key_ControlL");
                else
                    keyPressEvent(msg->wParam, "Key_ControlR");
            }
            break;            
        case VK_SHIFT:
            state = GetKeyState(VK_LSHIFT);
            if(state & VK_LSHIFT)
                keyPressEvent(msg->wParam, "Key_ShiftL");
            else
                keyPressEvent(msg->wParam, "Key_ShiftR");
            break;            
        case VK_MENU:// alt
            state = GetKeyState(VK_SHIFT);
            if(state == TRUE)
                keyPressEvent(msg->wParam, "Key_AltGr");
            break;

        case VK_SNAPSHOT:
            keyPressEvent(msg->wParam, "Key_Print");
            break;

        default:
            return false;  
        }

        return true;        
    } 
    return false;
}
#else
bool MainWindow::x11Event(XEvent *xe)
{   
    switch(xe->type)
    {
    case XKeyPress:
        switch (xe->xkey.keycode)
        {
        case 37://Control_L
            keyPressEvent(xe->xkey.keycode, "Key_ControlL");
            break;
        case 105://Control_R
            keyPressEvent(xe->xkey.keycode, "Key_ControlR");
            break;
        case 50://Shift_L
            keyPressEvent(xe->xkey.keycode, "Key_ShiftL");
            break;
        case 62://Shift_R
            keyPressEvent(xe->xkey.keycode, "Key_ShiftR");
            break;
        case 133://Super_L
            keyPressEvent(xe->xkey.keycode, "Key_SuperL");
            break;
        case 134://Super_R
            keyPressEvent(xe->xkey.keycode, "Key_SuperR");
            break;
        default:
            return false;
        }
        return true;
        break;
    }
    return false;
}
#endif

в методе x11Event, случай XKeyPress (в режиме отладки - 2) никогда не выполняется, но если вы посмотрите на:

grep KeyPress  /usr/include/X11/X.h 
#define KeyPressMask            (1L<<0)  
#define KeyPress        2

Константа верна, но тип никогда не равен 2. Если я изменю константу XKeyPress на 28, она будет выглядеть как

maiko@cits-d530:release$ grep 28  /usr/include/X11/X.h 
#define PropertyNotify      28
#define FirstExtensionError 128

хорошо работает.

Thx

1 Ответ

1 голос
/ 05 мая 2011

Я не мог знать, почему это не работает.Ни один x11events не вызывается после KeyPress, он вызывается только тогда, когда я перемещаю мышь, тогда все события, которые еще не сработали, запускаются.Для этого я получал все события одного типа и не мог сравнить тип каждого из них, потому что это был мусор.

Чтобы решить эту проблему, я реализовал QAbstractEventDispatcher в main.cpp, который является владельцемmainwindow.cpp (который является получателем от моих событий KeyPress) main.cpp

 QAbstractEventDispatcher *evInstance = QAbstractEventDispatcher::instance(0);
    evInstance->setEventFilter((QAbstractEventDispatcher::EventFilter) MainWindow::customEventFilter);

    MainWindow *w = new MainWindow(program.getLayoutFile(), program.getUnicode());
    w->show();
    a.exec();

, но метод customEventFilter должен быть статическим.Я изменил весь свой код для этого, но работает, customEventFilter может получать все системные события, в Linux или Windows.

Пока.

...