为什么XGrabKey会产生额外的焦点和焦点事件?

diy*_*ism 37 python linux x11 xlib

有没有人知道一个xlib函数来捕获一个按键事件而不会失去原始焦点?如何摆脱它?

(或"使用XGrabKey()而不产生抓取式焦点"?)

(或"如何摆脱系统级别的NotifyGrab和NotifyUngrab焦点事件?)

XGrabKey将失去对关键按下和恢复焦点的关注.

而且我想捕获按键而不将其泄漏到原始窗口(正如XGrabKey可以做到的那样).

参考文献:

  1. ...... XGrabKey将窃取焦点... https://bugs.launchpad.net/gtkhotkey/+bug/390552/comments/8

  2. ...程序接受控制以响应键组合做某事.同时,该程序暂时关注... 在XGrabKey(董事会)期间,发现哪个窗口已经集中

  3. ... XGrabKeyboard函数主动抓取键盘控制并生成FocusIn和FocusOut事件...... http://www.x.org/archive/X11R6.8.0/doc/XGrabKeyboard.3.html#toc3

  4. ...我无法看到提供metacity当前桌面变换行为的方法(同时更改和显示弹出对话框),而不会在窗口上引起Grab类型的焦点... https://mail.gnome .ORG /档案馆/ WM说明列表/ 2007-月/ msg00000.html

  5. ...全屏模式不应退出使用NotifyGrab的FocusOut事件... https://bugzilla.mozilla.org/show_bug.cgi?id=578265

  6. 抓住键盘不允许改变焦点... 抓住键盘不允许改变焦点

  7. Grabs生成的焦点事件(XGrabKeyboard的主动抓取和XGrabKey的被动抓取) http://www.x.org/releases/X11R7.6/doc/libX11/specs/libX11/libX11.html#Focus_Events_Generated_by_Grabs

  8. XGrabKey源代码:http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/GrKey.c 也许我们可以修改它来摆脱焦点事件?

  9. 有"DoFocusEvents(keybd,oldWin,grab-> window,NotifyGrab);" 在ActivateKeyboardGrab()中: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

我想通过XGrabKey()和XUngrabKey()将其迁移到Linux: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

Ant*_*hon 12

我在90年代早期看过Irix,ultrix和solaris的全球热键,因为它在我的Acorn BBC电脑上很容易做到.最终,我们决定以低于xlib的级别以非便携方式使用一些专有代码来解决这个问题.由于我们的软件安装无论如何都需要作为超级用户权限,我们能够插入适当的软件挂钩作为守护进程.

对于Linux(现在),您应该通过在操作系统级别处理键盘事件来寻找软件解决方案.我先来看看这里:http://code.google.com/p/logkeys/

更通用的解决方案是使用带有USB输入和USB输出的小型PC板,它可以作为鼠标和键盘对计算机起作用,并根据需要翻译键盘键.但如果您想经常更改映射,这将不会那么灵活.


diy*_*ism 12

我目前的代码(来自http://diyism-myboard.googlecode.com/files/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()
Run Code Online (Sandbox Code Playgroud)

当我按下"shift"键时,焦点丢失,当我释放它时,焦点会回来.


hd1*_*hd1 5

看起来XQueryKeymap会对你进行排序.请参阅下面的C++源代码我发现:

/* compile with g++ keytest.cpp -LX11 -o keytest */
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>

double gettime() {
 timeval tim;
 gettimeofday(&tim, NULL);
 double t1=tim.tv_sec+(tim.tv_usec/1000000.0);
 return t1;
}

int main() {
 Display *display_name;
 int depth,screen,connection;
 display_name = XOpenDisplay(NULL);
 screen = DefaultScreen(display_name);
 depth = DefaultDepth(display_name,screen);
 connection = ConnectionNumber(display_name);
 printf("Keylogger started\n\nInfo about X11 connection:\n");
 printf(" The display is::%s\n",XDisplayName((char*)display_name));
 printf(" Width::%d\tHeight::%d\n",
 DisplayWidth(display_name,screen),
 DisplayHeight(display_name,screen));
 printf(" Connection number is %d\n",connection);

 if(depth == 1)
  printf(" You live in prehistoric times\n");
 else
  printf(" You've got a coloured monitor with depth of %d\n",depth);

 printf("\n\nLogging started.\n\n");

 char keys_return[32];
 while(1) {
  XQueryKeymap(display_name,keys_return);
  for (int i=0; i<32; i++) {
   if (keys_return[i] != 0) {
    int pos = 0;
    int num = keys_return[i];
    printf("%.20f: ",gettime());
    while (pos < 8) {
     if ((num & 0x01) == 1) {
      printf("%d ",i*8+pos);
     }
     pos++; num /= 2;
    }
    printf("\n");
   }
  }
  usleep(30000);
 }
 XCloseDisplay(display_name);
}
Run Code Online (Sandbox Code Playgroud)

注意,这不是经过测试的代码,也不是我的 - 我只是在互联网上找到它.

  • 它不会捕获事件,它可以让您查看事件队列而无需更改它. (2认同)

diy*_*ism 5

最后,正如你所知,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
Run Code Online (Sandbox Code Playgroud)

我还需要在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
Run Code Online (Sandbox Code Playgroud)

现在myboard.py效果很好.

如果您使用的是ubuntu raring-updates版本,可以尝试:

https://code.google.com/p/diyism-myboard/downloads/detail?name=xserver-xorg-core_1.13.3-0ubuntu6.2_i386.deb

和:

https://code.google.com/p/diyism-myboard/downloads/detail?name=libgtk2.0-0_2.24.17-0ubuntu2_i386.deb