c++ - 在系统级别监听关键事件

标签 c++ linux qt

我需要写一个应用程序,它会监听一些关键事件,在它们发生后,应用程序会做一些事情(这对这个问题并不重要)。

应用程序将像守护进程一样运行 - 在后台(可能在系统托盘上)并等待输入。

问题是,我怎样才能在系统级别监听关键事件?我更喜欢一些 Unix C 解决方案(优先考虑的不是非 Unix 系统的可移植性),但是如果有一些方便的 Qt 类,为什么不使用它呢?

编辑:有没有什么方法可以告诉操作系统:“嗨!我在这里,‘一些键盘事件’叫醒我!”?

最佳答案

qxtglobalshortcut 用于快捷方式。 Qt 提供了不同的方式来处理本地事件。例如 QWidget::nativeEventQAbstractNativeEventFilter

但是如果你想使用系统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

关于c++ - 在系统级别监听关键事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32027081/

相关文章:

c++ - 无法在使用 SCons 编译的 Mac OSX 中聚焦 WxWidgets 框架

c++ - scanf(%s) EOF 问题

linux - 为什么 xargs -L 会产生正确的格式,而 xargs -n 却不会?

linux - Bash poweroff 脚本挂起系统

c++ - 使用 libtooling 测试类是否可复制构造

c++ - 虚表解释

linux - 在 Bash 脚本中将单词定义为变量

c++ - 没有动画框架的Qt动画

c++ - QDirIterator - 没有 hasNext 不是 FilePath react

python - PyQt 设置列宽