2016-08-22 2 views
2

L'objectif général est comme Windows Alt-Tab, donc je vais utiliser ces touches pour l'explication. Je veux:
Appuyez sur Alt -> appuyez sur Tab -> [popup apparaît] -> appuyez sur Tab à tout moment en maintenant Alt -> relâcher Alt -> [pop-up disparaît].Détection de la touche de modification dans la fenêtre racine X11

Je ne peux pas détecter la version finale finale.

  1. approche Trivial: saisir Alt-Tab:

    XGrabKey (dpy, 
        XKeysymToKeycode(dpy,XK_Tab), Mod1Mask, 
        root, True, GrabModeAsync, GrabModeAsync); 
    

    (code complet: http://pastebin.com/K2P65KJn)

    Résultat:

    [Alt enfoncée]
    [Tab pressé]
    En appuyant sur Alt-Tab reporté
    [Ta b libéré]
    Libération Alt-Tab a rapporté
    [Alt libérées pour] -> rien rapporté

  2. Saisissant les deux Alt-Tab et Any-Alt:

    XGrabKey (dpy, 
        XKeysymToKeycode(dpy,XK_Tab), Mod1Mask, 
        root, True, GrabModeAsync, GrabModeAsync); 
    XGrabKey (dpy, 
        XKeysymToKeycode(dpy,XK_Alt_L), AnyModifier, 
        root, True, GrabModeAsync, GrabModeAsync); 
    

    (code complet: http://pastebin.com/75mD1tjA)

    Cela fonctionne!

    [Alt enfoncée]
    En appuyant sur Alt rapporté
    [Tab enfoncé]
    En appuyant sur Alt-Tab a rapporté
    [Tab publié]
    Releasing Alt-Tab signalé
    [Alt publié]
    Libération Alt- Alt reporté

    Mais cela masque toute combinaison Alt de tout programme en cours d'exécution. Je ne trouve pas le moyen de repousser les événements qui ne nous appartiennent pas (essayé XSendEvent), et le fait de saisir Alt depuis le début semble trop envahissant.

  3. Saisir Alt après le premier appui sur Alt-Tab, puis dégrapper Alt après sa libération.

    Malheureusement, la première version Alt est toujours pas rapporté:

    [Alt enfoncée]
    [Tab enfoncé]
    En appuyant sur Alt-Tab a rapporté, Alt a saisi ici
    [Tab publié]
    Libération Alt- Onglet rapporté
    [Alt publié] -> rien n'a été signalé! appuyez sur Alt suite/release sont signalés, mais pas utiles:
    [Alt enfoncée]
    En appuyant sur Alt rapporté
    ...

Ai-je besoin de jouer avec xinput bas niveau ou il y a une autre façon pour atteindre l'objectif?

+0

rejouant Peut-être les événements avec 'fonctionne XAllowEvents'? Sinon, je pense que vous devrez peut-être aller à Xinput2. Vous pouvez également essayer de poser cette question sur la liste de diffusion xorg car la communauté X sur SO est plutôt éparse. –

+1

XGrabKey est plutôt gourmand; avez-vous essayé de gérer les XKeyPress/ReleaseEvents habituels? – JvO

Répondre

1

Il semblerait que vous n'obtiendrez pas un événement KeyRelease si vous vous êtes déjà enregistré après avoir appuyé sur la touche.

Je peux penser à deux façons de contourner cela.

  1. Sélectionnez KeyReleaseMask pour toutes les fenêtres (et de garder trace d'apparaître et disparaître les fenêtres); ou
  2. Une fois que vous avez appuyé sur Alt, interrogez l'état du clavier avec XQueryKeyboard toutes les 0,1 seconde environ jusqu'à ce qu'il soit libéré.

J'ai testé la première méthode et il semble fonctionner:

#include <X11/Xlib.h>    
#include <X11/Xutil.h>   
#include <stdbool.h>    
#include <stdio.h>    

void dowin (Display* dpy, Window win, int reg) 
{            
    Window root, parent;       
    Window* children;       
    int nchildren, i;       

    XSelectInput (dpy, win, reg ? KeyReleaseMask|SubstructureNotifyMask : 0); 
    XQueryTree (dpy, win, &root, &parent, &children, &nchildren);    

    for (i = 0; i < nchildren; ++i) 
    {        
    dowin (dpy, children[i], reg); 
    }        

    XFree(children); 
}     


int main()   
{     
    Display* dpy  = XOpenDisplay(0); 
    Window  win  = DefaultRootWindow(dpy); 
    XEvent  ev; 

    unsigned int alt_modmask  = Mod1Mask; 
    unsigned int ignored_modmask = 0; // stub 
    KeyCode   tab_keycode  = XKeysymToKeycode(dpy,XK_Tab); 
    KeyCode   alt_keycode  = XKeysymToKeycode(dpy,XK_Alt_L); 

    dowin (dpy, win, True); 

    XGrabKey (dpy, 
      tab_keycode, 
      alt_modmask | ignored_modmask, 
      win, 
      True, 
      GrabModeAsync, GrabModeAsync); 


    while(true) 
    { 
     ev.xkey.keycode = 0; 
     ev.xkey.state = 0; 
     ev.xkey.type = 0; 

     XNextEvent(dpy, &ev); 
     switch(ev.type) 
     { 
      case KeyPress: 
       printf ("Press %x: d-%d\n", ev.xkey.window, ev.xkey.state, ev.xkey.keycode); 
       break; 

      case KeyRelease: 
       printf ("Release %x: %d-%d\n", ev.xkey.window, ev.xkey.state, ev.xkey.keycode); 
       break; 

      case MapNotify: 
       printf ("Mapped %x\n", ev.xmap.window); 
       dowin (dpy, ev.xmap.window, True); 
       break; 

      case UnmapNotify: 
       printf ("Unmapped %x\n", ev.xunmap.window); 
       dowin (dpy, ev.xunmap.window, False); 
       break; 

      default: 
       printf ("Event type %d\n", ev.type); 
       break; 
     } 

    } 

    XCloseDisplay(dpy); 
    return 0; 
} 
+0

Merci, cela fonctionne! Le seul bogue à ce jour est l'erreur "BadWindow" X lorsque l'événement unmap déclenche XSelectInput pour une fenêtre inexistante (parce qu'elle est fermée ou que l'espace de travail WM a été modifié). Pour empêcher la résiliation de ces erreurs, je les ignore: http://pastebin.com/Q2UVJa61. J'ai peur que cela introduise des conditions de course ou des fuites de mémoire sous une exécution X asynchrone, donc je serai toujours reconnaissant pour toute révision. – sa7

+0

C'est une condition de course inoffensive (le serveur vous envoie unmapnotify, puis tue la fenêtre plus vite que vous ne pouvez la traiter). C'est tout à fait normal, ignorez simplement cette condition. –