我需要编写一个应用程序,它将监听一些关键事件,并在应用程序发生后执行某些操作(这对此问题不重要)。在系统级听取重要事件
该应用程序将运行就像一个守护程序 - 在背景(可能在系统盘)和等待输入。
问题是,我怎样才能听系统级别的关键事件?我更喜欢一些Unix C解决方案(优先级不是可移植到非Unix系统),但是如果有一些方便的Qt类,为什么不使用它?
编辑:是不是有一些方法,来告诉操作系统是这样的:“嗨!我在这里,叫我起床上‘一些键盘事件’!”?
我需要编写一个应用程序,它将监听一些关键事件,并在应用程序发生后执行某些操作(这对此问题不重要)。在系统级听取重要事件
该应用程序将运行就像一个守护程序 - 在背景(可能在系统盘)和等待输入。
问题是,我怎样才能听系统级别的关键事件?我更喜欢一些Unix C解决方案(优先级不是可移植到非Unix系统),但是如果有一些方便的Qt类,为什么不使用它?
编辑:是不是有一些方法,来告诉操作系统是这样的:“嗨!我在这里,叫我起床上‘一些键盘事件’!”?
这不是QT(还),但以某种方式连接,有这个类的QXT库调用qxtglobalshortcut
这里是链接:http://libqxt.bitbucket.org/doc/tip/qxtglobalshortcut.html
这看起来很有希望,但是你知道一些系统库函数吗?我宁愿它:) – tomascapek
我不能在任何地方下载,这个项目仍然活跃? – tomascapek
我相信Qt没有这样的东西。我看到该项目看起来并不十分活跃,但在这里我找到了一个Qt5的指导链接,所以我认为值得一试:http://wiki.qt.io/LibQxt_in_QtCreator – Marco
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
这种解决方案很酷,但我的应用程序将缺乏根访问。非常感谢您使用/ dev/input的解决方案,我知道,我的目标可以通过某种方式实现。 – tomascapek
短:你不能这样做。 较长的答案:你可以,但你必须写一个键盘驱动程序。
即使有根/管理员权限,您需要输入控件,将有OS输入焦点。 (这是为了避免抓取来自其他输入小部件的输入,如密码字段或聊天)。 - 我完全同意ddriver的评论。
如果你的服务有一个集中的小部件,你可以使用Widget的文本事件或使用QObject::installEventFilter
还有一点:你可以重用/服务内通知事件,但不能发送到其他应用程序。见notify。如果服务处理键盘事件,则其他应用程序将不会收到该事件。如果焦点控件的应用程序已经接受了按键事件,那么您的服务不会获得它。
但我不同意:一些操作系统允许访问keyboad的设备。 (就像切尔诺贝利的答案一样)。对于这些,您可以实现自己的键盘设备驱动程序/处理程序。 Linux嵌入的示例是:QWSServer。
用户须知:使用此类驱动程序不保存!如果您使用第三方键盘驱动程序,请小心!对于Windows来说,它只能使用Windows信任的驱动程序进行高度重新规划。
无论如何:实施自己的键盘驱动程序可以解决彩虹汤姆的问题。
键盘驱动程序?听起来像是一个适当的挑战。感谢真棒的意见。现在真的,如果我的应用程序在后台运行(或在系统托盘中),我该如何关注小部件? – tomascapek
你不能这样做。 (就像我说的)。无论如何,systray的例子在这里:[系统托管](https://doc.qt.io/archives/qtjambi-4.5.2_01/com/trolltech/qt/qtjambi-systemtrayexample.html) –
系统托盘的一个例子是在你的Qt在examples/widgets/desktop/systray下。 - 只有在我心中:在iconActivated-slot中,显示并聚焦一个QLineEdit。然后,您处于“输入模式”,并可以处理按键。隐藏LineEdit以将键盘返回给操作系统。 –
听起来像你有恶意的意图。建立一个keyloger来劫持某人的密码? – dtech
不 - 我会在我的问题中添加详细的描述。我的目标是创建下拉窗口,该窗口将显示在某些关键事件上 - 用户将设置哪个关键事件。应用程序本身会显而易见的原因在后台运行,因此我需要知道,何时发生某些事件。这就是为什么使用root访问的解决方案对我无效。 – tomascapek