X11:如何在没有focusloss的情况下实现全局热键

时间:2014-07-25 07:43:31

标签: c++ qt events hotkeys xorg

我有一个Qt应用程序,用XGrabKey抓取一个密钥。如果我按下热键,我希望我的应用程序显示和隐藏。此外,如果它失去焦点,它必须隐藏。这很好地解决了一个缺点:XGrabKeyboard使用的XGrabKey会生成FocusIn和FocusOut事件。这意味着,如果我在应用程序可见时按热键,应用程序将收到FocusOut事件,在收到hotkeyevent并再次显示之后隐藏并且非常好。

我可以以某种方式避免X服务器生成这些焦点事件吗?

2 个答案:

答案 0 :(得分:1)

我不这么认为,但你可以查看"模式" XFocusChangeEvent中的字段。它可以是NotifyNormal,NotifyWhileGrabbed,NotifyGrab或NotifyUngrab。抓取键应该使用最后两种模式生成事件,因此您可以选择忽略具有这些模式的事件,但我不确定如何使用Qt执行此操作。

答案 1 :(得分:1)

Diggin深入大约几个小时我修改了一个感觉很好的解决方案。它使用Qt QWidget::nativeEvent和libxcb。 libxcb似乎是下一代libX11包装器。但它非常无人问津。不冷却Qt不提供QFocusEvent的模式。但我想这就是想要与平台无关的一切的祸根。

注意:这是Qt5,Qt4有像QWidget::x11info()

这样的东西

·H

class Class : public QWidget
{
    Q_OBJECT
public:
    Class(QWidget *parent = 0);
    ~Class();

protected:
    virtual bool nativeEvent(const QByteArray &eventType, void *message, long *) override;
};

的.cpp

/**************************************************************************//**
 * @brief Class::nativeEvent
 * This special event handler can be reimplemented in a subclass to receive
 * native platform events identified by eventType which are passed in the
 * message parameter. In your reimplementation of this function, if you want to
 * stop the event being handled by Qt, return true and set result. If you
 * return false, this native event is passed back to Qt, which translates the
 * event into a Qt event and sends it to the widget.
 *
 * This method is called for every native event. On X11, eventType is set to
 * "xcb_generic_event_t", and the message can be casted to a
 * xcb_generic_event_t pointer.
 *
 * @param eventType
 * @param message
 * @return Indicator if this event shall be stoped being handled further.
 */
bool Class::nativeEvent(const QByteArray &eventType, void *message, long *)
{
    if (eventType == "xcb_generic_event_t")
    {
        xcb_generic_event_t* event = static_cast<xcb_generic_event_t *>(message);
        switch (event->response_type & ~0x80)
        {
        case XCB_FOCUS_IN: {
            xcb_focus_in_event_t *fe = (xcb_focus_in_event_t *)event;
            if (fe->mode & (XCB_NOTIFY_MODE_GRAB|XCB_NOTIFY_MODE_UNGRAB)){
                return true; // Ignore this events
            }
            break;
        }
        case XCB_FOCUS_OUT: {
            xcb_focus_out_event_t *fe = (xcb_focus_out_event_t *)event;
            if (fe->mode & (XCB_NOTIFY_MODE_GRAB|XCB_NOTIFY_MODE_UNGRAB)){
                return true; // Ignore this events
            }
            break;
        }
        }
    }
    return false;
}