从 XGrabKeyboard 中排除一些键
考虑一个应用程序,需要在聚焦时抓住键盘,以便捕获所有窗口管理器命令(Alt+F4 等)进行处理。现在,这有一个缺点,即当键盘被抓住时,用户无法通过键盘切换到另一个应用程序或虚拟桌面。我想要一个用户定义的组合键白名单(例如,用于切换虚拟桌面的组合键),这些组合键被排除在外。
我可以想到两种可能的方法。当列入白名单的关键事件到达时,要么
- 以某种方式告诉 X 像往常一样继续处理它。这听起来像是一种更自然的方法,但我找不到一种方法来执行此操作,或者
- 松开键盘并将事件手动重新发送到窗口管理器进行处理,但我不知道发送到哪里它(根窗口?)或者是否可以工作。
有人可以填补这些空白吗?还有其他建议吗?
如果没有办法从抓取中排除按键,我想我将不得不满足于使用“退出键”,在按下时可以取消抓取键盘。不过,用户必须同时按下该命令和窗口管理器命令,这不太好。
Consider an application where it's desirable to grab the keyboard when focused in order to capture all window manager commands (Alt+F4 and whatnot) for processing. Now, this has the downside that the user has no way of switching to another application or virtual desktop via the keyboard when the keyboard is grabbed. I'd like to have a user-defined whitelist of key combination (say, the key combinations for switching virtual desktops) that are excluded from the grab.
I can think of two possible approaches. When a whitelisted key event arrives, either
- Somehow tell X to continue processing it as usual. This sounds like a more natural way of doing it but I can't find a way to do this, or
- Ungrab the keyboard and re-send the event by hand to the window manager for processing, however I don't know where to send it (the root window?) or whether that would even work.
Can anyone fill in the blanks on those? Any other suggestions?
If there's no way to exclude keys from a grab, I guess I'll have to settle for having an "escape key" that ungrabs the keyboard when pressed. The user'll have to press both that and then the window manager command, though, which isn't as nice.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不认为有办法做到这一点。没有一种机制能够完全按照您所需要的方式工作。
例如,如果窗口管理器决定不拦截单击或按键,则采用方法 1。但是,WM 使用“被动”抓取特定键(XGrabKey=passive XGrabKeyboard=active),然后使用 XAllowEvents()。 XAllowEvents() 不适用于 XGrabKeyboard()。此外,当您使用其中一种重播模式 XAllowEvents 时,重播事件会绕过具有原始抓取的窗口及其所有父窗口上的所有被动抓取。 WM 的抓取将位于根窗口上,该窗口将始终是父窗口,因此据我所知,无法重播到根窗口。无论如何,在每个可能的键上执行 XGrabKey 都会有点神经质。
方法 2 会出现严重的竞争条件问题,因为在重新发送之前可能会处理其他键和鼠标事件,因此您需要重新排序键并将事件发送到被破坏的窗口和其他混乱。另外,也没有发送关键事件的好方法。 XSendEvent() 被许多客户端忽略(它在允许此操作的事件中设置 send_event 标志)。 XTest 扩展可以使用,但可能在生产 X 服务器上被禁用,并且仍然存在竞争条件问题。
您可能需要的是一个协议扩展,让您可以在 GrabKeyboard 之后执行 AllowEvents(mode=ReplayKeyboard),并且无需绕过对父窗口的被动抓取。
需要注意的是,我不知道 XKB 和 XInput2 可以完成的所有疯狂的事情,所以也许这些扩展中有一些东西。
不管怎样,据我所知,你必须满足于“退出键”,尽管最终 X 服务器和/或窗口管理器规范拥有“VMWare/VNC 类型事物感知”可能会更好,这赢得了胜利短期内对你没有帮助。例如,EWMH 规范扩展可以像 vnc/vmware/类似的东西的新 _NET_WM_WINDOW_TYPE 一样简单,窗口管理器可以减少其键绑定或向它们添加额外的修饰符或在该窗口聚焦时添加额外的修饰符。
I don't think there's a way to do it. None of the mechanisms work quite how you would need them to.
Approach 1 is sort of what the window manager does if it decides not to intercept a click or key for example. However, the WM is using "passive" grabs on particular keys (XGrabKey=passive XGrabKeyboard=active) and then XAllowEvents(). XAllowEvents() does not work with XGrabKeyboard(). also, when you XAllowEvents with one of the Replay modes, the replayed event bypasses all passive grabs on the window that had the original grab and on all its parent windows. The WM's grabs will be on the root window which will always be a parent so there is no way to replay to the root window, best I can tell. Doing XGrabKey on every possible key would be sort of psycho anyhow.
Approach 2 would have bad race condition problems, because other key and mouse events could be processed before you could resend, so you'd reorder keys and send events to destroyed windows and other confusion. Also, there is no good way to send a key event. XSendEvent() is ignored by many clients (it sets a send_event flag in the event allowing this). XTest extension can be used but may be disabled on production X servers and still has race condition issues.
What you probably would need is a protocol extension that let you do an AllowEvents(mode=ReplayKeyboard) after a GrabKeyboard and without bypassing passive grabs on parent windows.
One caveat is that I don't know all the wild stuff that can be done with XKB and XInput2, so maybe there's something in those extensions.
Anyway, as far as I know you have to settle for the "escape key," though it might be nice eventually for the X server and/or the window manager specs to have "VMWare/VNC-type-thing awareness," that won't help you in the short term. An EWMH spec extension could be as simple as a new _NET_WM_WINDOW_TYPE for vnc/vmware/stuff-like-that and the window manager could reduce its keybindings or add an extra modifier to them or something when that window was focused, for example.
当我想抓住键盘进行屏幕截图程序但保留 PageUp PageDown 键来滚动屏幕时,我遇到了同样的问题。我最终得到了一个极端且丑陋的解决方案:
XUngrab
所有设备和XCloseDisplay
。libxdo
,xdotool
库)。XOpenDisplay
进行初始化。这必须包括涉及显示的所有函数调用:根窗口、光标、颜色等。似乎没有其他方法可以解决该问题......
I ran into the same problem when I wanted to grab the keyboard for a screenshot program but leave the PageUp PageDown keys to scroll the screen. I ended up with an extreme and ugly solution:
XUngrab
all devices andXCloseDisplay
.libxdo
, thexdotool
library).XOpenDisplay
all over again. This has to include all function calls that involved the display: root window, cursors, colors, etc.There seems to be no other ways to solve the problem...