Pregunta

Si se mantiene pulsado una tecla en el X11, mientras que RepeticiónAutomática está activada, recibirá continuamente KeyPress y KeyRelease eventos. Sé que RepeticiónAutomática puede ser desactivada mediante la función XAutoRepeatOff () , pero esto cambia la configuración para todo el servidor X. ¿Hay una manera de desactivar o bien RepeticiónAutomática para una sola aplicación o hacer caso omiso de las pulsaciones de teclado repetidas?

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

Este es un ejemplo mínimo para que te va (en su mayoría de la Principiante 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);
}
¿Fue útil?

Solución

Cuando se recibe una llave de desbloqueo y el siguiente evento es una pulsación de tecla de la misma combinación de teclas, entonces es la repetición automática y la clave no fue revelado; fuimos. 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 */
  }
}

Otros consejos

Se puede utilizar la función de XkbSetDetectableAutorepeat para indicar al servidor X para enviar sólo los eventos KeyRelease cuando el usuario realmente libera la tecla -. cuando no se desea que los eventos de repetición automática, entonces se descarta presiones cualquier tecla sin cumplir ninguna KeyRelease

Para su referencia, aquí hay un ejemplo de un mínimo de trabajo que elimina automáticamente repetida KeyPress eventos. 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);
}

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.

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;
    ...
    }

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 sale un evento KeyRelease, yo uso XQueryKeymap que copiará a keys los bits de teclas presionadas (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:

Búsqueda keys[event.xkey.keycode>>3] para el índice de 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 tipo fundido para flotar o doble y de vuelta al número entero).

0x1 << (event.xkey.keycode % 8) hace lo opuesto. 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 solamente conjunto de bits en el lado derecho de operando se pone a 1 dentro de este índice de matriz. Si es así, se presiona la tecla.

Por último que acaba de encerrar en (), con un ! justo antes y si el resultado se convierte en realidad, no estás presionando esa tecla más.

Una última Nota: : Para utilizar este método, es necesario mantener la alimentación de la XServer con los eventos. Si no es así, se XQueryKeymap freze hasta que lo haga (mejor uso con hilos).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top