Pourquoi XGrabKey génère des évènements de focus-out et de focus-in supplémentaires?

est-ce que quelqu'un connaît une fonction xlib pour piéger un événement de keypress sans perdre la mise au point originale? Comment s'en débarrasser?

(ou "à utiliser XGrabKey (), sans générer de Saisir le style focusout"?)

(ou "Comment se débarrasser de NotifyGrab et NotifyUngrab événements de focus au niveau du système?)

le xgrabkey perdra le focus sur la touche pressée et restaurera le focus sur la touche libérée.

et je veux piéger le keypress sans fuite à la fenêtre d'origine (tout comme XGrabKey peut le faire).

, les Références:

  1. ...XGrabKey volera la mise au point... https://bugs.launchpad.net/gtkhotkey / +bug / 390552 / comments/8

  2. ...Le programme reçoit le contrôle de faire quelque chose en réponse à la combinaison de clés. Entre-temps, le programme a été temporairement ciblé... au Cours de XGrabKey (board), découvrez quelle fenêtre avait été ciblée

  3. ...La fonction XGrabKeyboard prend activement le contrôle du clavier et génère les événements FocusIn et FocusOut... http://www.x.org/archive/X11R6.8.0/doc/XGrabKeyboard.3.html#toc3

  4. ...Je ne peux pas voir un façon de fournir le comportement actuel de changement de bureau de metacity (changer et affichage de la popup dialogue en même temps) sans provoquer d' Saisir le type de mise au point sur la fenêtre... https://mail.gnome.org/archives/wm-spec-list/2007-May/msg00000.html

  5. ...Le mode Fullscreen ne doit pas s'arrêter sur les événements de Focus-out Avec NotifyGrab... https://bugzilla.mozilla.org/show_bug.cgi?id=578265

  6. toucher le clavier ne permet pas de changer de foyer ... saisir le clavier ne permet pas de changer de focus

  7. Concentrer les Événements Générés par le Jeu (à la fois l'actif saisir de XGrabKeyboard et le passif, la prise de XGrabKey) http://www.x.org/releases/X11R7.6/doc/libX11/specs/libX11/libX11.html#Focus_Events_Generated_by_Grabs

  8. la XGrabKey code source: http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/GrKey.c peut-être que nous pourrions modifier ceci pour nous débarrasser des événements de focus-out?

  9. il y a "DoFocusEvents(keybd, oldWin, prenez->fenêtre, NotifyGrab);" dans ActivateKeyboardGrab(): http://cgit.freedesktop.org/xorg/xserver/tree/dix/events.c

j'écris une touche à une combinaison de touches(et de mouvements de souris)) logiciel de cartographie: https://code.google.com/p/diyism-myboard /

Je L'ai réalisé dans Windows avec RegisterHotKey() et UnRegisterHotKey(): https://code.google.com/p/diyism-myboard/downloads/detail?name=MyBoard.pas

et je veux le migrer vers Linux avec XGrabKey() et XUngrabKey (): https://code.google.com/p/diyism-myboard/downloads/detail?name=myboard.py

j'ai créé $10 bounty pour résoudre ce problème. Nous avons besoin de plus de bailleurs de fonds pour placer des primes. https://www.bountysource.com/issues/1072081-right-button-menu-flashes-while-jkli-keys-move-the-mouse-pointer

37
demandé sur diyism 2013-03-07 15:48:39

7 réponses

j'ai regardé global hotkeys au début des années 90 pour Irix, ultrix et solaris, comme il avait été facile de le faire sur mon ordinateur Acorn BBC. Finalement, nous avons décidé de résoudre ce problème d'une manière non-portable à un niveau inférieur à xlib avec du code propriétaire. Comme notre installation logicielle nécessitait de toute façon des privilèges de superutilisateur, nous avons pu insérer les crochets logiciels appropriés en tant que démons.

Pour Linux (de nos jours) vous devriez probablement chercher une solution logicielle par traitement de l'événement clavier au niveau os. Je commencerais par jeter un oeil ici: http://code.google.com/p/logkeys /

plus générique solution serait d'avoir une petite carte PC avec un port USB et USB, qui agit à l'ordinateur (souris, clavier et traduit les touches du clavier comme nécessaire. Mais cela ne serait pas aussi flexible si vous voulez changer la cartographie souvent.

12
répondu Anthon 2013-03-10 13:34:37

mon code actuel (de 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()

Quand j'ai appuyer sur "shift", l'accent a perdu, et quand je le libère, l'accent revenir.

12
répondu diyism 2013-03-14 08:30:10

on dirait que XQueryKeymap va vous Trier. Voir ci-dessous pour code source C++ j'ai trouvé :

/* 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);
}

Note, Ce n'est pas du code testé, ni le mien -- je l'ai simplement trouvé sur Internet.

5
répondu hd1 2013-03-10 21:07:06

enfin, comme vous le savez linux signifie liberté, j'ai modifié xserver pour se débarrasser de grab-style focusout:

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

et je dois aussi me débarrasser de XGrabKeyboard dans le menu contextuel gtk:

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

maintenant myboard.py ça marche bien.

si vous utilisez ubuntu raring-updates edition, vous pouvez donner un essai à:

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

et:

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

5
répondu diyism 2013-11-28 13:26:49

j'ai une idée que je suis assez sûr que ça marcherait, mais je dois aller au lit et je ne peux pas le tester moi-même, et ce n'est pas joli, puisque je ne pense pas qu'il y ait un moyen de faire ce que vous voulez dans X. Voici les étapes que j'ai en tête. En bref: désactiver le clavier dans X, lire les événements à partir de l'api de niveau inférieur, et les transmettre sélectivement à X vous-même. Vous devez désactiver le clavier dans X parce que sinon, vous pourriez regarder l'événement, mais pas l'arrêter; vous le liriez à côté de X, pas l'intercepter il.

donc ici il est décomposé:

1) Exécuter xinput -list pour obtenir le clavier X utilise

2) Exécuter xinput list-props id pour trouver la propriété activée de L'appareil

3) Exécuter xinput set-prop id prop 0 pour désactiver le dispositif dans X:

xinput -list
xinput list-props 12 # 12 is the id of the keyboard in the list... (example # btw)
xinput set-prop 12 119 0 # 119 is the "Device Enabled" prop, we turn it off

Je ne sais pas comment xinput fonctionne au niveau xlib, Je l'appellerais simplement à l'interpréteur de commandes pour simplifier la mise en œuvre.

4) Ouvert /dev/input/eventX , où X est le dispositif de clavier. En fait, je cherche le nom (donné dans xinput-list) sous /dev/input/by-id et je l'ouvre de cette façon. Cela nécessitera probablement root à un moment donné, puisque les permissions sur ces derniers sont généralement assez restrictives.

5) Lire l'entrée clavier de là:

le format des données des événements d'entrée est:

struct input_event {
    int tv_sec; // time of the event
    int tv_usec; // ditto
    ushort type; // == 1 for key event
    ushort code; // key code, not the same as X keysyms, you should check it experimentally. 42 is left shift on mine, 54 is right shift
    int value; // for keys, 1 == pressed, 0 == released, 2 == repeat
}

ints sont en 32 bits, ushorts sont en 16 bits. Puisque vous êtes seulement intéressé par la saisie de clavier, vous pouvez le faire assez simplement:

  • lire et ignorer 8 octets.

  • le prochain octet doit être 1, puis le prochain est 0. si non, sautez cet événement

  • de l'octet Suivant est le petit bout de code de la clé, et depuis il y a < 255 touches, c'est assez bon, donc

  • passer de l'octet suivant.

  • lire le prochain octet pour voir si elle est pressée ou libérée

  • sauter les trois octets

6) lorsque vous recevez un événement qui vous intéresse, traitez-le vous-même. Sinon, utilisez XSendEvent pour l'Envoyer à X afin qu'il puisse être traité normalement. Mapping le code matériel que vous obtenez à partir de/dev / input à la clé appropriée pourrait être un truc, mais je suis je suis certain qu'il y a une fonction quelque part dans xlib pour aider avec ça.

7) goto 5 et boucle jusqu'à ce que vous êtes fait

8) assurez-vous de tout remettre en place comme il était lorsque vous sortez, ou vous pourriez casser l'entrée clavier de l'utilisateur à X!

je suggère de tester cela avec un second clavier usb, vous pouvez désactiver et écouter les claviers indépendamment les uns des autres avec /dev/input et xinput, donc si vous vous crash, vous avez toujours le premier clavier, et qu'elle fonctionne normalement. (En fait, je pense que ce serait plutôt cool de le faire intentionnellement avec un deuxième clavier, doublez les hotkeys!)

Mais oui, avoir besoin de root et potentiellement laisser le clavier" détaché "de X ne sont pas jolis du tout, et que le forwarding-avec-SendKey pourrait être plus facile à dire qu'à faire, mais je suis assez sûr que ce fonctionnerait et vous donnerait un maximum de flexibilité.

3
répondu Adam D. Ruppe 2013-11-16 05:41:03

pour l'écriture d'une clé (raccourci) le logiciel de cartographie ont également un regard sur libtermkey , une bibliothèque d'entrée de clé de terminal (écrite en C) qui reconnaît xterm-style rapport de position de souris/bouton, touches spéciales (telles que les flèches et les touches de fonction), y compris" modifié "des touches comme Ctrl-Left .

il y a, par exemple, POE::Wheel::TermKey , "une enveloppe perl asynchrone autour de la bibliothèque libtermkey , qui fournit une manière abstraite de lire les événements de keypress dans les terminaux basés programme."

1
répondu mmx 2014-02-04 11:38:27

vous pouvez utiliser XQueryKeymap pour lire les événements, alors vous pouvez utiliser XTestKey pour envoyer un événement clé backspace et ensuite la clé que vous voulez presser. Mieux, vous pouvez enregistrer hotkeys pour tous les événements clavier et ensuite générer l'événement clé en utilisant XTestKey. Le module de contrôle "raccourcis personnalisés" de BTW, KDE, permet d'utiliser des raccourcis pour générer des touches. code Source .

0
répondu Ramchandra Apte 2017-05-23 12:09:00