【问题标题】:Detect modifier key release in X11 root window在 X11 根窗口中检测修改键释放
【发布时间】:2016-08-22 19:12:02
【问题描述】:

总体目标类似于 Windows 的 Alt-Tab,因此我将使用这些键进行说明。我要:
按 Alt -> 按 Tab -> [弹出窗口出现] -> 按住 Alt 随时按 Tab -> 松开 Alt -> [弹出窗口消失]。

我无法检测到最终的 Alt 版本。

  1. 简单的方法:抓住 Alt-Tab:

    XGrabKey (dpy, 
      XKeysymToKeycode(dpy,XK_Tab), Mod1Mask,
      root, True, GrabModeAsync, GrabModeAsync);
    

    (完整代码:http://pastebin.com/K2P65KJn

    结果:

    [ 按下 Alt ]
    [ 按下标签 ]
    报告按 Alt-Tab
    [标签发布]
    发布 Alt-Tab 报告
    [ Alt 已发布 ] -> 没有任何报道

  2. 同时使用 Alt-Tab 和 Any-Alt:

    XGrabKey (dpy, 
      XKeysymToKeycode(dpy,XK_Tab), Mod1Mask,
      root, True, GrabModeAsync, GrabModeAsync);
    XGrabKey (dpy, 
      XKeysymToKeycode(dpy,XK_Alt_L), AnyModifier,
      root, True, GrabModeAsync, GrabModeAsync);
    

    (完整代码:http://pastebin.com/75mD1tjA

    有效!

    [ 按下 Alt ]
    按 Alt 报告
    [ 按下标签 ]
    报告按 Alt-Tab
    [标签发布]
    发布 Alt-Tab 报告
    [ Alt 已发布 ]
    发布 Alt-Alt 报告

    但这会隐藏任何正在运行的程序的任何 Alt 组合。 我找不到回退不属于我们的事件的方法(尝试过 XSendEvent),总体而言,从一开始就抓住 Alt 看起来太有侵略性了。

  3. 在第一次按下 Alt-Tab 后抓住 Alt,然后在松开 Alt 后取消抓住 Alt。

    很遗憾,仍然没有报告第一个 Alt 版本:

    [ 按下 Alt ]
    [ 按下标签 ]
    按 Alt-Tab 报告,Alt 抓到这里
    [标签发布]
    发布 Alt-Tab 报告
    [ Alt 发布 ] -> 没有报告!报告了随后的 Alt 按下/释放,但没有用:
    [ 按住 Alt ]
    按 Alt 报告
    ...

我需要搞乱低级 xinput 还是有其他方法可以实现目标?

【问题讨论】:

  • 也许用XAllowEvents 重播事件有效?如果没有,我认为您可能确实必须去 Xinput2。您也可以尝试在 xorg 邮件列表上询问这个问题,因为 SO 上的 X 社区相当稀少。
  • XGrabKey 比较贪心;您是否尝试过处理常规的 XKeyPress/ReleaseEvents?

标签: x11 hotkeys xlib


【解决方案1】:

如果您在按键后注册了对它的兴趣,您似乎不会收到KeyRelease 事件。

我可以想到两种不同的方法。

  1. 所有窗口选择KeyReleaseMask(并跟踪出现和消失的窗口);
  2. 一旦您知道 Alt 被按下,每隔 0.1 秒左右使用 XQueryKeyboard 轮询键盘状态,直到它被释放。

我已经测试了第一种方法,它似乎有效:

#include <X11/Xlib.h>            
#include <X11/Xutil.h>           
#include <stdbool.h>             
#include <stdio.h>               

void dowin (Display* dpy, Window win, int reg)
{                                             
  Window root, parent;                        
  Window* children;                           
  int nchildren, i;                           

  XSelectInput (dpy, win, reg ? KeyReleaseMask|SubstructureNotifyMask : 0);
  XQueryTree (dpy, win, &root, &parent, &children, &nchildren);            

  for (i = 0; i < nchildren; ++i)
  {                              
    dowin (dpy, children[i], reg);
  }                               

  XFree(children);
}                 


int main()        
{                 
    Display*    dpy     = XOpenDisplay(0);
    Window      win     = DefaultRootWindow(dpy);
    XEvent      ev;

    unsigned int    alt_modmask       = Mod1Mask;
    unsigned int    ignored_modmask   = 0; // stub
    KeyCode         tab_keycode       = XKeysymToKeycode(dpy,XK_Tab);
    KeyCode         alt_keycode       = XKeysymToKeycode(dpy,XK_Alt_L);

    dowin (dpy, win, True);

    XGrabKey (dpy,
            tab_keycode,
            alt_modmask | ignored_modmask,
            win,
            True,
            GrabModeAsync, GrabModeAsync);


    while(true)
    {
        ev.xkey.keycode = 0;
        ev.xkey.state = 0;
        ev.xkey.type = 0;

        XNextEvent(dpy, &ev);
        switch(ev.type)
        {
            case KeyPress:
                printf ("Press %x: d-%d\n", ev.xkey.window, ev.xkey.state, ev.xkey.keycode);
                break;

            case KeyRelease:
                printf ("Release %x: %d-%d\n", ev.xkey.window, ev.xkey.state, ev.xkey.keycode);
                break;

            case MapNotify:
                printf ("Mapped %x\n", ev.xmap.window);
                dowin (dpy, ev.xmap.window, True);
                break;

            case UnmapNotify:
                printf ("Unmapped %x\n", ev.xunmap.window);
                dowin (dpy, ev.xunmap.window, False);
                break;

            default:
                printf ("Event type %d\n", ev.type);
                break;
        }

    }

    XCloseDisplay(dpy);
    return 0;
}

【讨论】:

  • 谢谢你,这行得通!到目前为止,唯一的错误是当 unmap 事件为不存在的窗口触发 XSelectInput 时出现“BadWindow”X 错误(因为它已关闭或 WM 工作区已更改)。为了防止终止这些错误,我只是忽略它们:pastebin.com/Q2UVJa61。恐怕这会在异步 X 执行下引入一些竞争条件或内存泄漏,所以我仍然会感谢任何评论。
  • 这是一个无害的竞争条件(tje 服务器向您发送 unmapnotify,然后以比您处理它的速度更快的速度杀死窗口)。完全正常,忽略这种情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-11
相关资源
最近更新 更多