我需要編寫一個應用程序,它將監聽一些關鍵事件,並在應用程序發生後執行某些操作(這對此問題不重要)。在系統級聽取重要事件
該應用程序將運行就像一個守護程序 - 在背景(可能在系統盤)和等待輸入。
問題是,我怎樣才能聽系統級別的關鍵事件?我更喜歡一些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