C++ 在系统级侦听关键事件

C++ 在系统级侦听关键事件,c++,linux,qt,C++,Linux,Qt,我需要编写一个应用程序,它将侦听一些关键事件,在它们发生后,应用程序将执行一些操作(这对于这个问题并不重要) 应用程序将像一个迪蒙一样在后台运行(可能在系统托盘上),并等待输入 问题是,我如何在系统级收听关键事件?我更喜欢一些unixc解决方案(优先考虑的不是对非Unix系统的可移植性),但是如果有一些方便的Qt类,为什么不使用它呢 编辑:是不是有什么方法可以告诉操作系统:“嗨!我在这里,在‘某个键盘事件’中叫醒我!”?它不是Qt(还没有),但以某种方式连接在一起,Qxt库中有一个叫做qxtgl

我需要编写一个应用程序,它将侦听一些关键事件,在它们发生后,应用程序将执行一些操作(这对于这个问题并不重要)

应用程序将像一个迪蒙一样在后台运行(可能在系统托盘上),并等待输入

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

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

它不是Qt(还没有),但以某种方式连接在一起,Qxt库中有一个叫做qxtglobalshortcut的类


以下是链接:

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();
}
肖特:你不能这么做。 更长的回答:你可以,但你必须编写一个键盘驱动程序

即使具有root/管理员权限,您也需要一个具有OS输入焦点的输入小部件。(这是为了避免从其他输入小部件(如密码字段或聊天室)获取输入。)我完全同意ddriver的评论

如果您的服务有一个焦点小部件,您可以使用小部件的文本事件或

另一点:您可以在服务中重用/通知事件,但不能发送到其他应用程序。看见如果服务处理了键盘事件,则其他应用程序将不会接收该事件。若FocusWidget的应用程序已经接受了关键事件,那个么您的服务就不会得到它

但我同意:有些操作系统允许访问键盘设备。(就像切尔诺贝利的答案一样)。对于这些,您可以实现自己的键盘设备驱动程序/处理程序。嵌入式Linux的示例为:

用户注意:使用此驱动程序不保存!如果您使用第三方键盘驱动程序,请小心!对于Windows,强烈建议仅使用Windows受信任的驱动程序


无论如何:实现自己的键盘驱动程序可以解决Rainbow Tom的问题

这看起来很有希望,但是您知道一些系统库函数吗?我更喜欢:)我不能在任何地方下载它,这个项目仍然处于活动状态吗?我相信Qt没有类似的东西。我看到这个项目看起来不是很活跃,但在这里我找到了一个关于Qt5的howto的链接,所以我认为值得一试:现在我终于发现,这个库不再被维护——这解释了我的问题……这个解决方案很酷,但我的应用程序将缺少根访问权限。非常感谢您使用/dev/input解决方案,我知道,我的目标可以通过这种方式实现。听起来您有恶意意图。建立一个键盘记录器来劫持某人的密码?不-我会在我的问题中添加详细的描述。我的目标是创建一个下拉窗口,它将出现在一些关键事件上,这将由用户设置。应用程序本身将在后台运行,因此我需要知道什么时候发生某些事件。这就是为什么使用root访问的解决方案对我不起作用。键盘驱动程序?听起来是一个适当的挑战。谢谢你的宝贵意见。现在说真的,若我的应用程序运行在后台(或系统托盘中),那个么我怎么能有聚焦小部件呢?你们不能这么做。(就像我说的)。无论如何,systray的示例如下:systray的示例在您的Qt中的examples/widgets/desktop/systray下。-仅在我的脑海中:在iconActivated插槽中,显示并聚焦QLineEdit。然后,您处于“输入模式”,可以处理按键。隐藏LineEdit以将键盘返回操作系统。
sudo /path/to/exe
#if you want to run it inside qt creator but with sudo
sudo /path/to/qtcreator