2015-08-15 4 views
1

Мне нужно написать приложение, которое будет прослушивать некоторые ключевые события, и после того, как это произойдет, приложение сделает что-то (это не важно для этого вопроса).Прослушивание ключевых событий на системном уровне

Приложение будет работать как деамон - на фоне (возможно, на системном трее) и ждет ввода.

Вопрос в том, как я могу слушать ключевые события на системном уровне? Я предпочитаю решение Unix C (приоритет не переносится на систему, отличную от Unix), но если есть какой-то удобный класс Qt, почему бы не использовать его?

EDIT: Не существует способа сказать операционной системе что-то вроде: «Привет! Я здесь, разбужу меня на каком-то клавиатурном мероприятии!»?

+0

Похоже, у вас есть злонамеренные намерения.Создание кейлоггера для захвата чьи-то пароли? – dtech

+0

Nope - я добавлю подробное описание к моему вопросу. Моя цель - создать раскрывающееся окно, которое появится на каком-то ключевом событии, которое будет установлено пользователем. Само приложение будет по очевидным причинам работать на фоне, и поэтому мне нужно знать, когда происходит какое-то определенное событие. Вот почему решение, использующее root-доступ, не работает для меня. – tomascapek

ответ

1

Это не Qt (пока), но как-то связано, то этот класс в библиотеке Qxt называется qxtglobalshortcut

Вот ссылка: http://libqxt.bitbucket.org/doc/tip/qxtglobalshortcut.html

+0

Это выглядит многообещающим, но знаете ли вы о какой-либо функции системной библиотеки? Я бы предпочел это :) – tomascapek

+0

Я не могу загрузить его в любом месте, этот проект все еще активен? – tomascapek

+0

Я считаю, что у Qt ничего подобного нет. Я вижу, что проект выглядит не очень активным, но здесь я нашел ссылку с Howto для Qt5, поэтому я думаю, что стоит попробовать: http://wiki.qt.io/LibQxt_in_QtCreator – Marco

2

qxtglobalshortcut для ярлыков. Qt предлагает различные способы обработки собственных событий. Это, например, QWidget::nativeEvent или QAbstractNativeEventFilter.

Но если вы хотите использовать системный API, то вы можете попробовать мой код. Это код, который выполняется внутри отдельного потока и асинхронно вызывает метод для уведомления пользователя при возникновении события. Готов к копированию, но задайте имя вашей клавиатуры.

#include <QApplication> 
#include <QDebug> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <dirent.h> 
#include <linux/input.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <sys/select.h> 
#include <sys/time.h> 
#include <termios.h> 
#include <signal.h> 
#include <QSystemTrayIcon> 
#include <thread> 

QSystemTrayIcon *tray; 

void handler (int sig) 
{ 
    qDebug ("nexiting...(%d)n", sig); 
    exit (0); 
} 

void perror_exit (char *error) 
{ 
    perror (error); 
    handler (9); 
} 


int main(int argc, char *argv[]) 
{ 
    QApplication a(argc, argv); 


    tray = new QSystemTrayIcon; 
    QPixmap px(20,20); 
    px.fill(Qt::green); 

    tray->setIcon(QIcon(px)); 
    tray->show(); 
    tray->showMessage("hello","hello",QSystemTrayIcon::Information,1000); 

    //need this to use invokeMthod 
    qRegisterMetaType<QSystemTrayIcon::MessageIcon>("QSystemTrayIcon::MessageIcon"); 
    std::thread thread([tray]() 
    { 
     struct input_event ev[64]; 
     int fd, rd, value, size = sizeof (struct input_event); 
     char name[256] = "Unknown"; 
     char *device = NULL; 


     if ((getuid()) != 0) 
      qDebug ("You are not root! This may not work...n"); 


     //my keyboard,set name of yours 
     device = "/dev/input/by-id/usb-SIGMACHIP_USB_Keyboard-event-kbd"; 

     //Open Device 
     if ((fd = open (device, O_RDONLY)) == -1) 
      qDebug ("%s is not a vaild device.n", device); 

     //Print Device Name 
     ioctl (fd, EVIOCGNAME (sizeof (name)), name); 
     qDebug ("Reading From : %s (%s)n", device, name); 

     while (1){ 
      if ((rd = read (fd, ev, size * 64)) < size) 
       perror_exit ("read()"); 

      value = ev[0].value; 

      if (value != ' ' && ev[1].value == 1 && ev[1].type == 1){ // Only read the key press event 
      qDebug ("Code[%d]n", (ev[1].code)); 
      QMetaObject::invokeMethod(tray,"showMessage",Qt::QueuedConnection,Q_ARG(QString,"Was pressed"),Q_ARG(QString,QString::number(ev[1].code)), 
        Q_ARG(QSystemTrayIcon::MessageIcon,QSystemTrayIcon::Information),Q_ARG(int,500)); 
      } 
     } 
    }); 

    qDebug("after thread"); 
    return a.exec(); 
} 

я использовал код из here, а просто изменил его, чтобы быть в Qt образом.

Для запуска программы вы должны использовать sudo.

sudo /path/to/exe 
#if you want to run it inside qt creator but with sudo 
sudo /path/to/qtcreator 
+0

Это решение классно, но моему приложению не будет доступа к корню. Большое спасибо за решение, использующее/dev/input, я знал, что моя цель может быть достигнута таким образом. – tomascapek

0

Short: Вы не можете этого сделать. Более длинный ответ: вы можете, но вам нужно написать клавиатурный драйвер.

Даже с привилегиями root/Administrator вам нужен виджет ввода, который будет иметь фокус ввода ОС. (Это позволит избежать захвата ввода из других входных виджетов, таких как поля пароля или ваш чат). - Я полностью согласен с комментарием ddriver.

Если ваша служба имеет целенаправленный-виджет, вы можете использовать текстовые события виджета или использовать QObject::installEventFilter

Еще один момент: Вы можете повторно использовать/уведомления о событии в вашей службе, но не отправлять в другие приложения. См. notify. Если служба обработала событие клавиатуры, никакое другое приложение не получит событие. И если приложение фокус-виджета уже приняло ключевое событие, ваша служба не получит его.

Но я согласен: некоторые ОС позволяют получить доступ к устройствам с клавиатурой. (Как ответ Чернобыля). Для этого вы можете реализовать собственный драйвер/обработчик клавиатуры. Пример для встроенного Linux: QWSServer.

Примечание для пользователей: Использование такого драйвера не сохраняется! Пожалуйста, будьте осторожны, если вы используете сторонний клавиатурный драйвер! Для Windows очень рекомендуется использовать только драйверы, зависящие от Windows.

В любом случае: реализация собственного драйвера клавиатуры может решить проблему Rainbow Tom.

+0

Драйвер для клавиатуры? Кажется, что это правильный вызов. Спасибо за удивительное мнение. Теперь, на самом деле, если мое приложение работает в фоновом режиме (или в системном трее), как я могу сфокусировать виджет? – tomascapek

+0

Вы не можете этого сделать. (Как я и сказал). В любом случае и пример для systray: [systray] (https://doc.qt.io/archives/qtjambi-4.5.2_01/com/trolltech/qt/qtjambi-systemtrayexample.html) –

+0

Пример для systray находится в вашем Qt под примерами/widgets/desktop/systray. - Только на мой взгляд: в значке Активированный слот покажите и сфокусируйте QLineEdit. Затем вы находитесь в режиме ввода и можете обрабатывать нажатия клавиш. Скройте LineEdit, чтобы вернуть клавиатуру в ОС. –

Смежные вопросы