2010-01-20 9 views
17

Si pulsa sin soltar una tecla en el X11, mientras RepeticiónAutomática está activado, recibirá continuamente KeyPress y KeyRelease eventos. Sé que AutoRepeat se puede desactivar con la función XAutoRepeatOff(), pero esto cambia la configuración de todo el servidor X. ¿Hay alguna manera de deshabilitar AutoRepeat para una sola aplicación o ignorar pulsaciones de teclas repetidas?Ignorar repetición automática en aplicaciones X11

Lo que estoy buscando es un solo evento KeyPress cuando se pulsa una tecla y un solo KeyRelease evento cuando se suelta una tecla, sin interferir con el ajuste RepeticiónAutomática del servidor X.

Aquí está un ejemplo mínimo para que te va (en su mayoría del Beginner Xlib Tutorial):

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xos.h> 
#include <X11/Xatom.h> 
#include <X11/keysym.h> 

Display *dis; 
Window win; 
XEvent report; 

int main() 
{ 
    dis = XOpenDisplay (NULL); 
    // XAutoRepeatOn(dis); 
    win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500, 
     0, BlackPixel (dis, 0), BlackPixel (dis, 0)); 
    XSelectInput (dis, win, KeyPressMask | KeyReleaseMask); 
    XMapWindow (dis, win); 
    XFlush (dis); 

    while (1) 
    { 
     XNextEvent (dis, &report); 
     switch (report.type) 
{ 
case KeyPress: 
    fprintf (stdout, "key #%ld was pressed.\n", 
    (long) XLookupKeysym (&report.xkey, 0)); 
    break; 
case KeyRelease: 
    fprintf (stdout, "key #%ld was released.\n", 
    (long) XLookupKeysym (&report.xkey, 0)); 
    break; 
} 
    } 

    return (0); 
} 

Respuesta

17

Cuando recibe una liberación de tecla y el siguiente evento es presionar una tecla con la misma combinación de teclas, se repite automáticamente y la clave no se ha liberado. Puede utilizar código como este para mirar próximo evento

if (event->type == KeyRelease && XEventsQueued(disp, QueuedAfterReading)) 
{ 
    XEvent nev; 
    XPeekEvent(disp, &nev); 

    if (nev.type == KeyPress && nev.xkey.time == event->xkey.time && 
     nev.xkey.keycode == event->xkey.keycode) 
    { 
    /* Key wasn’t actually released */ 
    } 
} 
+0

¡Gracias, eso es exactamente lo que he estado buscando! – mzuther

1

Se podría establecer un temporizador cuando se presiona o se suelta una tecla e ignorar eventos KeyPress y KeyRelease que ocurren dentro del intervalo de repetición .

6

Puede usar la función XkbSetDetectableAutorepeat para indicarle al servidor X que solo envíe eventos KeyRelease cuando el usuario realmente suelta la clave; cuando no desea eventos de repetición automática, descarta cualquier KeyPress sin coincidir con KeyRelease.

5

Para su referencia, esto es un ejemplo de un mínimo de trabajo que elimina KeyPress eventos de auto-repetido. ¡Gracias, kralyk!

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xos.h> 
#include <X11/Xatom.h> 
#include <X11/keysym.h> 

Display *dis; 
Window win; 
XEvent report; 

int main() 
{ 
    dis = XOpenDisplay (NULL); 
    // XAutoRepeatOn(dis); 
    win = XCreateSimpleWindow (dis, RootWindow (dis, 0), 1, 1, 500, 500, 
     0, BlackPixel (dis, 0), BlackPixel (dis, 0)); 
    XSelectInput (dis, win, KeyPressMask | KeyReleaseMask); 
    XMapWindow (dis, win); 
    XFlush (dis); 

    while (1) 
    { 
     XNextEvent (dis, &report); 
     switch (report.type) 
{ 
case KeyPress: 
    fprintf (stdout, "key #%ld was pressed.\n", 
    (long) XLookupKeysym (&report.xkey, 0)); 
    break; 
case KeyRelease: 
    { 
    unsigned short is_retriggered = 0; 

    if (XEventsQueued(dis, QueuedAfterReading)) 
     { 
     XEvent nev; 
     XPeekEvent(dis, &nev); 

     if (nev.type == KeyPress && nev.xkey.time == report.xkey.time && 
      nev.xkey.keycode == report.xkey.keycode) 
      { 
      fprintf (stdout, "key #%ld was retriggered.\n", 
       (long) XLookupKeysym (&nev.xkey, 0)); 

      // delete retriggered KeyPress event 
      XNextEvent (dis, &report); 
      is_retriggered = 1; 
      } 
     } 

    if (!is_retriggered) 
     fprintf (stdout, "key #%ld was released.\n", 
     (long) XLookupKeysym (&report.xkey, 0)); 
    } 
    break; 
} 
    } 

    return (0); 
} 
0

otro enfoque. esto funciona para mi.

char keyz[1024] = {0}; 
bool physical; 
XEvent event, nev; 

while (!quit) { 
    XNextEvent(display, &event); 
    ... 
    switch(event.type) { 
     case KeyPress: 
      physical = (keyz[event.xkey.keycode] == 0); 
      keyz[event.xkey.keycode] = 1; 
      keyboard(event.xkey.window, true, event.xkey.keycode, physical); 
      break; 
     case KeyRelease: 
      physical = true; 
      if (XPending(display)) { 
       XPeekEvent(display, &nev); 
       if (nev.type == KeyPress && nev.xkey.time == event.xkey.time 
       && nev.xkey.keycode == event.xkey.keycode) physical = false; 
      } 
      if (physical) keyz[event.xkey.keycode] = 0; 
      keyboard(event.xkey.window, false, event.xkey.keycode, physical); 
      break; 
    ... 
    } 
0

Aquí está la solución que se me ocurrió.

XEvent event; 

while(1) 
{ 
    XNextEvent(display, &event); 

    switch(event.type) 
    { 
     // Other cases 
     case ...: 
      ... 
      break; 
     ... 

     // On KeyRelease 
     case KeyRelease: 
     { 
      char keys[32]; 
      XQueryKeymap(display, keys); 

      if(!(keys[event.xkey.keycode>>3] & (0x1 << (event.xkey.keycode % 8)))) 
      { 
       // Stuff to do on KeyRelease 
       ... 
      } 
     } 
     break; 

     // On KeyPress 
     case KeyPress: 
      // Stuff to do on KeyPress 
      ... 
      break; 
     default: 
      ... 
    } 
} 

Por lo tanto, cada vez que reciben un evento KeyRelease, utilizo XQueryKeymap que copiará a keys los bits de teclas pulsadas (8 teclas diferentes por char). Para los que no están acostumbrados a trabajar con operatos bit a bit y operador de desplazamiento, aquí hay una explicación simple:

keys[event.xkey.keycode>>3] búsqueda de índice event.xkey.keycode/8 el uso de "operador de desplazamiento a la derecha" (que permite la "división entera" por 2, 4, 8, 16 y así sucesivamente, sin que el tipo emitido flote o doble y vuelva a entero).

0x1 << (event.xkey.keycode % 8) hace lo contrario.Se multiplica el valor de 0x1 (== 1) por 2 elevado a (event.xkey.keycode % 8)

El operador & bit a bit entre keys[event.xkey.keycode>>3] y 0x1 << (event.xkey.keycode % 8) comparará si el bit solamente situado en la derecha operando lado se pone a 1 dentro de este índice de matriz. Si es así, se está presionando la tecla.

Por último, simplemente enciérrelo en (), con un ! justo antes y si el resultado es verdadero, ya no está presionando esa tecla.

Una final Nota: Para utilizar este método, debe seguir alimentando el XServer con eventos. De lo contrario, XQueryKeymap correrá hasta que lo haga (mejor uso con los hilos).