从 XGrabKeyboard 中排除一些按键

问题描述 投票:0回答:2

考虑一个应用程序,需要在聚焦时抓住键盘,以便捕获所有窗口管理器命令(Alt+F4 等)进行处理。现在,这有一个缺点,即当键盘被抓住时,用户无法通过键盘切换到另一个应用程序或虚拟桌面。我想要一个用户定义的组合键白名单(例如,用于切换虚拟桌面的组合键),这些组合键被排除在抓取之外。

我可以想到两种可能的方法。当列入白名单的关键事件到来时,要么

  1. 以某种方式告诉 X 像往常一样继续处理它。这听起来像是一种更自然的方法,但我找不到方法来做到这一点,或者
  2. 松开键盘并手动将事件重新发送到窗口管理器进行处理,但是我不知道将其发送到哪里(根窗口?)或者这是否有效。

有人可以填补这些空白吗?还有其他建议吗?

如果没有办法从抓取中排除按键,我想我将不得不满足于使用“退出键”,在按下时可以取消抓取键盘。不过,用户必须同时按下该命令和窗口管理器命令,这不太好。

keyboard x11 xlib
2个回答
4
投票

我认为没有办法做到这一点。没有一种机制能够完全按照您需要的方式工作。

方法 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 一样简单,窗口管理器可以减少其键绑定或向它们添加额外的修饰符或在该窗口聚焦时添加额外的修饰符。


0
投票

当我想抓住键盘进行屏幕截图程序但保留 PageUp PageDown 键来滚动屏幕时,我遇到了同样的问题。我最终得到了一个极端且丑陋的解决方案:

  1. 检测到所需按键后,
    XUngrab
    所有设备和
    XCloseDisplay
  2. 照常发出密钥(在我的例子中使用
    libxdo
    xdotool
    库)。
  3. XOpenDisplay
    重新初始化。这必须包括涉及显示的所有函数调用:根窗口、光标、颜色等。

似乎没有其他办法可以解决这个问题...

© www.soinside.com 2019 - 2024. All rights reserved.