【问题标题】:Launch application function using keyboard shortcut in GNU/Linux在 GNU/Linux 中使用键盘快捷键启动应用程序功能
【发布时间】:2015-04-28 20:34:31
【问题描述】:

我在GNU/Linux 中使用Qt 创建了一个应用程序,并在后台运行。我想在用户按下某些组合键时执行某些应用程序功能,例如Ctrl+Alt+A...

我知道这是可能的,Gnome Pie 做到了,但我不知道如何获取密钥。我尝试使用此问题中提供的examples,但它们都不起作用……我也不想以 root 身份运行我的应用程序……

谁能给我一些资源或给我一些提示?

编辑:

@iharob 建议我应该使用libkeybinder。我找到了它,试过了,但它使用 GTKGTK 不能很好地与 Qt...事件循环与Qt 事件循环冲突;当我从回调中发出Qt 信号时,该信号在按下键后被调用(这也是在调用gtk_init 之后)应用程序崩溃。

如果我可以创建一个在按下键盘组合键时发出信号的类(例如Ctrl+Alt+A),那就太好了。

【问题讨论】:

  • 我认为有一些库可以帮助你,比如libkeybinder
  • 如果有人告诉我为什么这个问题被否决了会很有帮助...
  • 不,这根本没有帮助。
  • 因为那无助于您解决问题,但您真正需要的是 google。
  • 不能用 Qt 完成。只有处于焦点的小部件才能接收关键事件。后台应用程序没有焦点。

标签: c++ c linux qt keyboard-events


【解决方案1】:

据我所见,@SamVarshavchik 指出libkeybinder 在后台使用libx11,因此您可以使用libx11 来摆脱GTK 事件循环不是很友好Qt。 AFAIK KDEKAction 对其全局短键使用相同的技术,所以我认为这种技术可以很好地与 Qt 的事件循环配合使用。

说了这么多,你可以使用here提供的热键示例:

x11_hot_key.pro:

#-------------------------------------------------
#
# Project created by QtCreator 2015-05-04T01:47:22
#
#-------------------------------------------------

QT       += core

QT       -= gui

TARGET = x11_hot_key
CONFIG   += console
CONFIG   -= app_bundle

TEMPLATE = app


SOURCES += main.cpp

CONFIG  += link_pkgconfig
PKGCONFIG += x11

ma​​in.cpp:

#include <QCoreApplication>

#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>

using namespace std;

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

    Display*    dpy     = XOpenDisplay(0);
    Window      root    = DefaultRootWindow(dpy);
    XEvent      ev;

    unsigned int    modifiers       = ControlMask | ShiftMask;
    int             keycode         = XKeysymToKeycode(dpy,XK_Y);
    Window          grab_window     =  root;
    Bool            owner_events    = False;
    int             pointer_mode    = GrabModeAsync;
    int             keyboard_mode   = GrabModeAsync;

    XGrabKey(dpy, keycode, modifiers, grab_window, owner_events, pointer_mode,
             keyboard_mode);

    XSelectInput(dpy, root, KeyPressMask );
    while(true)
    {
        bool shouldQuit = false;
        XNextEvent(dpy, &ev);
        switch(ev.type)
        {
        case KeyPress:
            cout << "Hot key pressed!" << endl;
            XUngrabKey(dpy,keycode,modifiers,grab_window);
            shouldQuit = true;

        default:
            break;
        }

        if(shouldQuit)
            break;
    }

    XCloseDisplay(dpy);

    return a.exec();
}

或者您也可以使用this simple library 所提供的here,它还有一些简单的示例以及方便的Makefile 供您使用。

由于我不知道XGrabKey 的异步通信者,您将遇到的一个问题是while(true) 循环永远不会返回并阻塞主线程因此应用程序因此您想要将其移入一个单独的线程并使用signalsslots 将其连接到主线程。不过,这应该不是什么大问题,也不会影响您的应用程序的性能,因为 AFAIK XNextEvent 会阻塞直到您的键被击中,因此处理器不会进行无用的处理...

希望这会有所帮助。

【讨论】:

    【解决方案2】:

    简单看一下libkeybinder's very small source 表明它所做的就是在X 显示器的根窗口上安装一个keygrab。

    这应该是可行的,但并不容易,需要对低级X Window System protocol有一定的了解和了解。 Qtlibxcb 应该可以在一个进程中和平共存。我尝试实现这样的方式如下:

    1. 启动一个单独的线程。
    2. 线程将打开一个到 X 服务器的单独连接,枚举显示器上的所有屏幕,获取每个屏幕的根窗口,每个根窗口上的 install a key grab,然后进入一个循环,从 xcb_connection_t 句柄读取 X 事件。
    3. 一旦收到一个关键事件(我希望在这个循环中处理的唯一关键事件将是与抓取的关键对应的事件),立即ungrab the keyboard 以便 X 服务器可以继续其愉快的方式,然后通知您的应用程序的主线程,以某种形式或方式,该键已被按下。
    4. 当需要退出时,您的应用程序必须有一些方法来停止此线程。

    【讨论】:

      【解决方案3】:

      可能的解决方案是模拟这种行为 - 有一个小型独立应用程序向您的后台进程发送信号(有很多变体这样做,signal() 可能是最简单的)。然后在特定环境的窗口管理器中附加该应用程序以进行所需的键绑定。它可能需要学习如何为各种窗口管理器执行此操作,但结果可能会更清晰、更快速地实现。

      【讨论】:

        猜你喜欢
        • 2014-07-04
        • 1970-01-01
        • 2011-03-21
        • 2014-11-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多