Natywne eventy klawiatury pod linuksem w Qt - potrzeba bo nie działa poprawnie QKeyEvent::isAutoRepeat()

0

Czołem Bracia i Siostry w kodzie

Zwracam się do Was z prośbą w wskazówkę jak dobrać się do natywnych eventów od klawiatury pod linuksem z poziomu Qt. To, że będę potrzebował użyć klasy QAbstractNativeEventFilter, i zainstalować go czy to na QApplication, czy konkretnym widgecie to wiem. Czego nie wiem, to co ja tam spośród źródeł Qt potrzebuję doinkludować, i jaka jest definicja ala windowsowe MSG w linukse dla eventu od klawiatury.

A cały cyrk dlatego, iż pod linuksem Qt dało d**y, i nieprawidłowo zwraca wartość QKeyEvent::isAutoRepeat() - https://bugreports.qt.io/browse/QTBUG-57335
Mam więc opcje:

  1. użyć nativeEventFiltera; w sumie opcja wydaje się najsensowniejsza bo co jak co, ale systemowe eventy od klawiatury to muszą działać poprawnie.
  2. samemu rozkmninić jakieś rozpoznawanie czy nastąpiło powtórzenie. Tutaj nie ułatwia sprawy fakt, iż na windowsie dostaje się 32 eventy na sekundę, a na linuksie 30 według wskazań QStyleHints::keyboardAutoRepeatRate()
  3. poprawić źródła Qt, i przekompilować bibliotekę; jednak to rozwiązanie jest tak bardzo do d**y że nie ma co się nad nim rozwodzić.

Chyba, że jest coś jeszcze?

Qt 5.15.2, a linux Ubuntu jakby co.

2

Obczaję dokładniej wieczorem/jutro, ale zacząłbym tu https://www.freedesktop.org/wiki/Software/libevdev/
Jeżeli to ma działać na linuxie na Xach tylko, to spoglądnij jeszcze tu: https://gist.github.com/javiercantero/7753445
EDIT: popatrzyłem w dokumentację QT, w przykładach dla linuxa podają XCB, czyli to:
https://xcb.freedesktop.org/tutorial/events/

Sprawdziłem u siebie na desktopie:

#include <QAbstractNativeEventFilter>
#include <xcb/xcb.h>
#include <QDebug>

class CustomNativeEventFilter : public QAbstractNativeEventFilter
{
public:
  bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override
  {
    /*
        to będzie różne w zależności od platformy
        to xcb_* jest dla Xservera
        także wyprintuj, potem trzeba googlować.
    */
    if (eventType == "xcb_generic_event_t") {
      xcb_generic_event_t* ev = static_cast<xcb_generic_event_t*>(message);
      if (ev->response_type == XCB_KEY_PRESS) {
        qDebug() << "key press";
        auto kev = static_cast<xcb_key_press_event_t*>(message);
        qDebug() << "Keycode " << kev->detail;
        return kev->detail == 38; //ignorowanie klawisza [A]
      }
    }
    return false
  }
};

A podłącza się toto do głównej pętli zdarzeń:
QAbstractEventDispatcher::instance()->installNativeEventFilter(&filter);
https://doc.qt.io/qt-5/qabstracteventdispatcher.html

EDIT2:
z tego co widzę: autorepeat trzeba sobie ręcznie "policzyć" z przychodzacych zdarzeń, vide: https://codereview.qt-project.org/c/qt/qtbase/+/236053/8/src/plugins/platforms/xcb/qxcbkeyboard.cpp#1530

Biorąc pod uwagę ilość pracy do tego potrzebnej, rekompilacja QT z poprawką wcale musi być taką złą opcją, bo efektywnie możesz zrobić to samo ;)

Możesz jeszcze na to spojrzeć: https://blog.robertelder.org/detect-keyup-event-linux-terminal/
oraz na to:
https://stackoverflow.com/questions/31616651/xcb-ignoring-repeated-keys

Ale generalnie wychodzi na to, że przy auto-repeat generowany jest event release razem z eventem press i ich timestamp jest po prostu zgodny.
Z moich eksperymentów (ustawiłem się na słuchanie tylko klawisza "a"):

[typ] [keycode] [timestamp] [call count]
key press keycode  38   3517844   0  //tu nacisnąłem
key release keycode  38   3518344   0 //to jest fejk już
key press keycode  38   3518344   1 
key release keycode  38   3518374   1
key press keycode  38   3518374   2
key release keycode  38   3518404   2
key press keycode  38   3518404   3
key release keycode  38   3518435   3
key press keycode  38   3518435   4
key release keycode  38   3518465   4
key press keycode  38   3518465   5
key release keycode  38   3518495   5
key press keycode  38   3518495   6
key release keycode  38   3518527   6
key press keycode  38   3518527   7
key release keycode  38   3518557   7
key press keycode  38   3518557   8
key release keycode  38   3518587   8
key press keycode  38   3518587   9
key release keycode  38   3518618   9
key press keycode  38   3518618   10
key release keycode  38   3518620   10 //tu puściłem

Przy czym: nie wiem jak wszystko zachowa się dal innego backendu niż XCB. Napisz jak się dowiesz czy masz inny, to będziemy kombinować.

1

Dzięki Bracie @alagner , póki co udało mi się stworzyć działający projekt na podstawie powyższego kodu. Z prób jakie przeprowadziłem wynika:

  1. Dla tapowania klawisza przychodzi press1 i release1, press2 i release2 itd. W tym wypadku release1 i press2 mają ten sam sequence, ale różne timestampy.
  2. Dla wciśnięcia i przytrzymania przycisku release1 i press2 mają taki sam zarówno timestamp, jak i sequence. Muszę jeszcze obczaić co się dzieje po puszczeniu przycisku.

Powyższe powinno wystarczyć do rozpoznania autorepeata. Jakbym jeszcze miał jakieś problemy rzecz jasna nie omieszkam się Cię tutaj znów poprosić, ale póki co łap ptaszka.

1 użytkowników online, w tym zalogowanych: 0, gości: 1