LINUX.ORG.RU

[Qt] Как следить за движением мыши, глобально

 


0

0

Суть такова: пишу программу, что-то типа оперных жестов или khotkeys, но не совсем. Программе надо следить за движением курсора мыши и в зависимости от этих движений предпринимать некоторые действия и выдавать некоторые сообщения. Как можно такое сделать?

Пока единственное, что придумал - это вызывать по таймеру QCursor::pos(), но это плохое решение, хотя бы потому, что оно будет сильно хавать батарейку на ноутах. Гораздо интереснее было бы не опрашивать мышь, а получать от неё события, типа QWidget::mouseMoveEvent(), но не для конкретного виджета, а глобально. Это реально?

Если Qt такого не умеет, как вообще такое сделать кроссплатформенно?

anonymous

на мышкину кнопку поставить моторчик с кулачком

vilfred ☆☆
()

man XQueryPointer

хотя незнаю как там с получением всех нужных аргументов для этой функции в Qt.

Andru ★★★★
()
Ответ на: комментарий от Andru

> man XQueryPointer

Я ж говорю, не хочется опрашивать позицию курсора 50 раз в секунду, хочется, чтобы события сами прилетали, куда надо.

anonymous
()
Ответ на: комментарий от anonymous

>>Я ж говорю, не хочется опрашивать позицию курсора 50 раз в секунду, хочется, чтобы события сами прилетали, куда надо.

блин, сглупил че-то, т.к. задумался о своем 8) В мыслях всплыло зацикливание XNextEvent, и выбивание координат по MotionNotify...

Если же нужно "чтоб само прилетело", то увы никаких callback'ов я так и не обнаружил, когда писал одну свою либу... Получать данные приходится только ручками.

Andru ★★★★
()

Попробуй вот так:

class SpyMouse: public QObject {
  Q_OBJECT;

  protected:
    bool eventFilter(QObject* obj, QEvent* event);
};

bool SpyMouse::eventFilter(QObject* obj, QEvent* event) {
  if(event->type() == QEvent::MouseMove) {
     // Сделать всё зашибись

    return true;
  } else {
    return QObject::eventFilter(obj, event);
  }
}

[...]

int main(int argc, char* argv) {
  [...]

  SpyMouse* sm = new SpyMouse(qApp);
  qApp->installEventFilter(sm);

  [...]
}


Потом отпишись, мне самому интересно.

Merlin86
()

Если не найдёшь такую функцию, опрашивай 1000 раз в секунду (или даже реже), для иышки хватит и процессор грузить не будет.

Legioner ★★★★★
()

кроссплатформенно одним кодом - только проверяя постоянно координаты
курсора. Можно не 1000 раз в секунду, но хотя бы 200.

Не кроссплатформенно можно оборачивать в #ifdef-ы и для кажой ОС
писать ОS-specific код. Для Linux можно попробовать:

#include <QApplication>
#include <QFile>
#include <QSocketNotifier>
#include <QDebug>
#include <QCursor>

#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>

class My : public QObject
{
    Q_OBJECT

    public:
        My() : QObject()
        {
            /*
             *  можно также попробовать /dev/input/mice при неудаче.
             *  совсем хорошо - вынуть устройство из HAL-а.
             *
             *  не забывем, что права на устройство могуть быть 600,
             *  поэтому на нашу программу придётся ставить
             *
             *  chown root:root prog
             *  chmod +s prog
             *
             *  и в программе делать setuid
             */
            file = new QFile("/dev/psaux", this);

            if(!file->open(QIODevice::ReadOnly))
                qCritical("Cannot open mouse device");

            sn = new QSocketNotifier(file->handle(), QSocketNotifier::Read, this);

            connect(sn, SIGNAL(activated(int)), this, SLOT(slotMouseEvent()));

            // как-тот так... (или getenv("UID"))
            //
            // struct passwd *pwd = getpwnam(getenv("USER"));
            // if(pwd) setuid(pwd->pw_uid);
        }

    private slots:
        void slotMouseEvent()
        {
            char c;
            file->read(&c, 1);

            // не забываем, что сюда приходят также и нажатия клавиш
            // ...

            qDebug() << QCursor::pos();
        }

    private:
        QFile *file;
        QSocketNotifier *sn;
};

int main(int argc, char **argv)
{
    QApplication app(argc, argv);

    My my;

    return app.exec();
}

#include "main.moc"

alex_custov ★★★★★
()
Ответ на: комментарий от Legioner

> Если не найдёшь такую функцию, опрашивай 1000 раз в секунду (или даже реже), для иышки хватит и процессор грузить не будет.

Грузить не будет, но не даст процессору перейти в спящее состояние, даже если мышью никто не елозит. Для ноута это критично - энергопотребление в режиме покоя резко вырастет.

Известный syndaemon так поступает, и на моём быдло-HP 530 это поделие хавает лишние 1.3 ватта - около 10% от всей потребляемой мощности, если верить ACPI.

anonymous
()

А по-моему, единственный способ заставить иксовый клиент получать чужие мышиные события — это сделать XGrabPointer (ну или qApp->desktop()->grabMouse() для Qt). KHotKeys примерно так и поступает. Но при этом остальные клиенты перестанут получать свои события (по-русски говоря, мышкой ничего нажиматься не будет). Разве что самому посылать мышиные события с помощью XTestFakeMotionEvent, XTestFakeButtonEvent и т. д. — только фиг знает, сколько тут всяких грабель вылезет. Ну и само собой, для венды и маков надо будет изобретать что-то своё, никакой кроссплатформенностью тут не пахнет. Короче, если очень-очень хочется, то реально такое сделать, надо только вагон времени и мешок терпения. А если это мелкая поделка ради фана, то пускай она пока тупо вызывает QCursor::pos() по таймеру, а дальше видно будет.

ero-sennin ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.