在X11根窗口中检测修改器键释放 [英] Detect modifier key release in X11 root window
问题描述
总体目标类似于Windows的Alt-Tab,因此我将使用这些键进行解释.我想要:
按住Alt键->按下Tab键-> [弹出窗口出现]->随时按住Tab键->释放Alt键-> [弹出窗口消失].
我无法检测到最终的Alt版本.
-
传统方法:抢夺Alt-Tab:
XGrabKey(dpy,XKeysymToKeycode(dpy,XK_Tab),Mod1Mask,root,True,GrabModeAsync,GrabModeAsync);
(完整代码: http://pastebin.com/K2P65KJn )
结果:
[按住Alt键]
[按Tab键]
按Alt-Tab键报告
[选项卡已发布]
发布Alt-Tab报告
[Alt释放]->没有报告 -
同时抓取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似乎太具有侵入性.
-
先按Alt-Tab键,然后按Alt键,然后释放它.
不幸的是,仍然没有报告第一个Alt版本:
[按住Alt键]
[按Tab键]
按Alt-Tab的报道,Alt抓住了这里
[选项卡已发布]
发布Alt-Tab报告
[Alt发布]->没有任何报道!报告了随后的Alt新闻稿/发布,尽管没有用:
[按Alt]
按Alt报告了
...
我需要弄混低级的xinput还是有另一种方法可以实现目标?
如果您在按下键后对此感兴趣,那么您似乎不会得到 KeyRelease
事件.
我可以考虑两种不同的解决方法.
- 为所有窗口选择
KeyReleaseMask
(并跟踪出现和消失的窗口);或 - 一旦您知道已按下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.
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 reportedGrabbing 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 reportedBut 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.
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.
- Select
KeyReleaseMask
for all windows (and keep track of appearing and disappearing windows); or - 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屋!