为什么XGrabKey会生成额外的失去焦点和获得焦点事件?
有没有人知道一个xlib函数,可以在不失去原有焦点的情况下捕捉按键事件?怎么才能做到这一点呢?
(或者说“如何使用XGrabKey()而不产生Grab风格的焦点丢失事件?”)
(或者“如何在系统级别去掉NotifyGrab和NotifyUngrab焦点事件?”)
XGrabKey在按下按键时会失去焦点,并在松开按键时恢复焦点。
我想在不让原窗口接收到按键的情况下捕捉按键事件(就像XGrabKey可以做到的那样)。
参考资料:
...XGrabKey会抢占焦点... https://bugs.launchpad.net/gtkhotkey/+bug/390552/comments/8
...程序会接收到控制权,以响应按键组合。同时,程序会暂时获得焦点... 在XGrabKey期间,发现哪个窗口曾经获得焦点
...XGrabKeyboard函数会主动抢占键盘控制,并生成FocusIn和FocusOut事件... http://www.x.org/archive/X11R6.8.0/doc/XGrabKeyboard.3.html#toc3
...我看不出有什么办法可以在不导致窗口焦点丢失的情况下,提供metacity当前桌面变化的行为(同时改变并显示弹出对话框)... https://mail.gnome.org/archives/wm-spec-list/2007-May/msg00000.html
...全屏模式不应该在NotifyGrab的FocusOut事件下退出... https://bugzilla.mozilla.org/show_bug.cgi?id=578265
抢占键盘不允许改变焦点... 抢占键盘不允许改变焦点
由抢占产生的焦点事件(包括XGrabKeyboard的主动抢占和XGrabKey的被动抢占) http://www.x.org/releases/X11R7.6/doc/libX11/specs/libX11/libX11.html#Focus_Events_Generated_by_Grabs
XGrabKey的源代码:http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/GrKey.c 也许我们可以修改这个来去掉焦点丢失事件?
在ActivateKeyboardGrab()中有“DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab)”; http://cgit.freedesktop.org/xorg/xserver/tree/dix/events.c
我正在写一个将单个按键映射到按键组合(和鼠标移动)的软件:https://code.google.com/p/diyism-myboard/
我已经在Windows上用RegisterHotKey()和UnRegisterHotKey()实现了这个功能:https://code.google.com/p/diyism-myboard/downloads/detail?name=MyBoard.pas
现在我想把它迁移到Linux上,使用XGrabKey()和XUngrabKey():https://code.google.com/p/diyism-myboard/downloads/detail?name=myboard.py
我已经设定了10美元的悬赏来解决这个问题。我们需要更多的支持者来提供悬赏。 https://www.bountysource.com/issues/1072081-right-button-menu-flashes-while-jkli-keys-move-the-mouse-pointer
8 个回答
我现在的代码(来自 https://github.com/diyism/MyBoard/blob/master/myboard.py):
disp=Display()
screen=disp.screen()
root=screen.root
def grab_key(key, mod):
key_code=string_to_keycode(key)
#3rd: bool owner_events, 4th: pointer_mode, 5th: keyboard_mode, X.GrabModeSync, X.GrabModeAsync
root.grab_key(key_code, mod, 0, X.GrabModeAsync, X.GrabModeAsync)
root.grab_key(key_code, mod|X.LockMask, 0, X.GrabModeAsync, X.GrabModeAsync) #caps lock
root.grab_key(key_code, mod|X.Mod2Mask, 0, X.GrabModeAsync, X.GrabModeAsync) #num lock
root.grab_key(key_code, mod|X.LockMask|X.Mod2Mask, 0, X.GrabModeAsync, X.GrabModeAsync)
def main():
grab_key('Shift_L', X.NONE)
grab_key('Shift_R', X.NONE)
while 1:
evt=root.display.next_event()
if evt.type in [X.KeyPress, X.KeyRelease]: #ignore X.MappingNotify(=34)
handle_event(evt)
if __name__ == '__main__':
main()
当我按下“shift”键时,焦点就会消失;而当我松开它时,焦点又会回来。
我在90年代初期研究过全局热键,当时是在Irix、Ultrix和Solaris系统上,因为在我的Acorn BBC电脑上实现这个功能非常简单。最后,我们决定用一种不太通用的方法来解决这个问题,采用了一些专有代码,直接在xlib下面的层级进行处理。由于我们的软件安装本来就需要超级用户权限,所以我们能够作为守护进程插入合适的软件钩子。
对于现在的Linux系统,你可能应该寻找一种软件解决方案,通过处理操作系统层面的键盘事件来实现。我建议你可以先看看这个链接:http://code.google.com/p/logkeys/
还有一种更通用的解决方案,就是使用一个小型的PC板,带有USB输入和输出,它可以作为电脑的鼠标和键盘,并根据需要翻译键盘按键。不过,如果你想频繁更改按键映射,这种方法就不太灵活了。
最后,正如你所知道的,Linux代表着自由,我修改了xserver,以去掉那种抓取式的失去焦点:
sudo apt-get build-dep xorg-server
apt-get source xorg-server
cd xorg-server-*
#modify or patch dix/events.c: comment off "DoFocusEvents(keybd, oldWin, grab->window, NotifyGrab);" in ActivateKeyboardGrab(), comment off "DoFocusEvents(keybd, grab->window, focusWin, NotifyUngrab);" in DeactivateKeyboardGrab()
sudo apt-get install devscripts
debuild -us -uc #"-us -uc" to avoid the signature step
cd ..
sudo dpkg --install xserver-xorg-core_*.deb
#clear dependencies:
sudo apt-mark auto $(apt-cache showsrc xorg-server | grep Build-Depends | perl -p -e 's/(?:[\[(].+?[\])]|Build-Depends:|,|\|)//g')
sudo apt-get autoremove
我还需要在gtk上下文菜单中去掉XGrabKeyboard:
sudo apt-get build-dep gtk+2.0
apt-get source gtk+2.0
cd gtk+2.0-*
#modify or patch it: add "return TRUE;" in first line of popup_grab_on_window() of gtk/gtkmenu.c
dpkg-source --commit
debuild -us -uc #"-us -uc" to avoid the signature step, maybe need: sudo apt-get install devscripts
cd ..
sudo dpkg --install libgtk2.0-0_*.deb
#clear dependencies:
sudo apt-mark auto $(apt-cache showsrc gtk+2.0 | grep Build-Depends | perl -p -e 's/(?:[\[(].+?[\])]|Build-Depends:|,|\|)//g')
sudo apt-get autoremove
现在我的myboard.py运行得很好。
我已经把它从googlecode迁移到了github: https://github.com/diyism/MyBoard