在X11根窗口中检测修改器键释放 [英] Detect modifier key release in X11 root window

查看:75
本文介绍了在X11根窗口中检测修改器键释放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

总体目标类似于Windows的Alt-Tab,因此我将使用这些键进行解释.我想要:
按住Alt键->按下Tab键-> [弹出窗口出现]->随时按住Tab键->释放Alt键-> [弹出窗口消失].

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

  1. 传统方法:抢夺Alt-Tab:

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

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

    结果:

    [按住Alt键]
    [按Tab键]
    按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报告了
    [按Tab键]
    按Alt-Tab键报告
    [选项卡已发布]
    发布Alt-Tab报告
    [Alt发布]
    已发布Alt-Alt报告

    但是,这将从任何正在运行的程序中隐藏任何Alt组合.我找不到推回不属于我们的事件的方法(尝试过XSendEvent),并且从一开始就全面抢占Alt似乎太具有侵入性.

  3. 先按Alt-Tab键,然后按Alt键,然后释放它.

    不幸的是,仍然没有报告第一个Alt版本:

    [按住Alt键]
    [按Tab键]
    按Alt-Tab的报道,Alt抓住了这里
    [选项卡已发布]
    发布Alt-Tab报告
    [Alt发布]->没有任何报道!报告了随后的Alt新闻稿/发布,尽管没有用:
    [按Alt]
    按Alt报告了
    ...

我需要弄混低级的xinput还是有另一种方法可以实现目标?

解决方案

如果您在按下键后对此感兴趣,那么您似乎不会得到 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){窗口根,父级;窗口*儿童;聪明的孩子,我;XSelectInput(dpy,win,reg?KeyReleaseMask | SubstructureNotifyMask:0);XQueryTree(dpy,win,& root,& parent,& children,& nchildren);对于(i = 0; i< nchildren; ++ i){dowin(dpy,children [i],reg);}XFree(儿童);}int main(){显示* dpy = XOpenDisplay(0);视窗赢= DefaultRootWindow(dpy);XEvent ev;unsigned int alt_modmask = Mod1Mask;unsigned int ignore_modmask = 0;//存根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 |ignore_modmask,赢,真的,GrabModeAsync,GrabModeAsync);而(真){ev.xkey.keycode = 0;ev.xkey.state = 0;ev.xkey.type = 0;XNextEvent(dpy,& ev);开关(ev.type){案例KeyPress:printf(按%x:d-%d \ n",ev.xkey.window,ev.xkey.state,ev.xkey.keycode);休息;案例KeyRelease:printf(发布%x:%d-%d \ n",ev.xkey.window,ev.xkey.state,ev.xkey.keycode);休息;案例MapNotify:printf(映射的%x \ n",ev.xmap.window);dowin(dpy,ev.xmap.window,True);休息;案例UnmapNotify:printf(未映射的%x \ n",ev.xunmap.window);dowin(dpy,ev.xunmap.window,False);休息;默认:printf(事件类型%d \ n",ev.type);休息;}}XCloseDisplay(dpy);返回0;} 

The overall goal is like Windows' Alt-Tab, so I will use these keys for explanation. I want:
Press Alt -> press Tab -> [ popup appears ] -> press Tab any time holding Alt -> release Alt -> [ popup disappears ].

I can't detect final Alt release.

  1. Trivial approach: grabbing Alt-Tab:

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

    (full code: http://pastebin.com/K2P65KJn)

    Result:

    [ Alt pressed ]
    [ Tab pressed ]
    Pressing Alt-Tab reported
    [ Tab released ]
    Releasing Alt-Tab reported
    [ Alt released ] -> nothing reported

  2. Grabbing both Alt-Tab and 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);
    

    (full code: http://pastebin.com/75mD1tjA)

    It works!

    [ Alt pressed ]
    Pressing Alt reported
    [ Tab pressed ]
    Pressing Alt-Tab reported
    [ Tab released ]
    Releasing Alt-Tab reported
    [ Alt released ]
    Releasing Alt-Alt reported

    But this hides any Alt combination from any running program. I can't find the way to push back events which don't belong to us (tried XSendEvent), and overally grabbing Alt from the start looks too invasive.

  3. Grabbing Alt after first Alt-Tab press, then ungrab Alt after its release.

    Unfortunately, first Alt release is still not reported:

    [ Alt pressed ]
    [ Tab pressed ]
    Pressing Alt-Tab reported, Alt grabbed here
    [ Tab released ]
    Releasing Alt-Tab reported
    [ Alt released ] -> nothing reported! subsequent Alt press/release are reported, though not useful:
    [ Alt pressed ]
    Pressing Alt reported
    ...

Do I need to mess with low-level xinput or there is another way to achieve the goal?

解决方案

It looks like you won't get a KeyRelease event if you have registered interest in it after the key was pressed.

I can think of two different ways around this.

  1. Select KeyReleaseMask for all windows (and keep track of appearing and disappearing windows); or
  2. Once you know Alt is pressed, poll the keyboard state with XQueryKeyboard every 0.1 second or so until it's released.

I have tested the first method and it seems to be working:

#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;
}

这篇关于在X11根窗口中检测修改器键释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆