python - ¿Por qué XGrabKey genera eventos adicionales de enfoque y enfoque?
linux x11 (7)
Finalmente, como sabes que Linux significa libertad, modifiqué xserver para deshacerte del enfoque al estilo grab:
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
Y también necesito deshacerme de XGrabKeyboard en el menú contextual de 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
Ahora myboard.py funciona bien.
Si está utilizando ubuntu raring-updates edition, podría intentar:
y:
https://code.google.com/p/diyism-myboard/downloads/detail?name=libgtk2.0-0_2.24.17-0ubuntu2_i386.deb
¿Alguien sabe una función xlib para atrapar un evento de pulsación de tecla sin perder el foco original? Cómo deshacerse de él?
(o "para usar XGrabKey () sin generar un enfoque Grab-style"?)
(o "¿Cómo deshacerse de los eventos de enfoque NotifyGrab y NotifyUngrab a nivel del sistema?"
El XGrabKey perderá el foco en la tecla presionada y restaurará el foco en la tecla liberada.
Y quiero atrapar la pulsación de tecla sin fugarla a la ventana original (al igual que XGrabKey puede hacerlo).
Referencias
... XGrabKey robará el foco ... https://bugs.launchpad.net/gtkhotkey/+bug/390552/comments/8
... El programa recibe el control para hacer algo en respuesta a la combinación de teclas. Mientras tanto, el programa se ha centrado temporalmente ... Durante XGrabKey (placa), descubre qué ventana se ha centrado
... La función XGrabKeyboard toma de forma activa el control del teclado y genera los eventos FocusIn y FocusOut ... http://www.x.org/archive/X11R6.8.0/doc/XGrabKeyboard.3.html#toc3
... No puedo ver una manera de proporcionar el comportamiento de cambio de escritorio actual de metacity (cambiando y mostrando el cuadro de diálogo emergente al mismo tiempo) sin causar un enfoque tipo Grab en la ventana ... https://mail.gnome.org/archives/wm-spec-list/2007-May/msg00000.html
... El modo de pantalla completa no debería salir en los eventos de FocusOut con NotifyGrab ... https://bugzilla.mozilla.org/show_bug.cgi?id=578265
agarrar el teclado no permite cambiar el enfoque ... agarrar el teclado no permite cambiar el enfoque
Eventos de enfoque generados por Grabs (tanto la captura activa de XGrabKeyboard como la captura pasiva de XGrabKey) http://www.x.org/releases/X11R7.6/doc/libX11/specs/libX11/libX11.html#Focus_Events_Generated_by_Grabs
el código fuente de XGrabKey: http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/GrKey.c quizás podríamos modificar esto para deshacernos de los eventos de enfoque?
hay "DoFocusEvents (keybd, oldWin, grab-> window, NotifyGrab);" en ActivateKeyboardGrab (): http://cgit.freedesktop.org/xorg/xserver/tree/dix/events.c
Estoy escribiendo un software de mapeo de combinación de teclas (y movimiento del mouse) con una sola tecla: https://code.google.com/p/diyism-myboard/
Me di cuenta en Windows con RegisterHotKey () y UnRegisterHotKey (): https://code.google.com/p/diyism-myboard/downloads/detail?name=MyBoard.pas
Y quiero migrarlo a Linux con XGrabKey () y XUngrabKey (): https://code.google.com/p/diyism-myboard/downloads/detail?name=myboard.py
Creé una recompensa de $ 10 para resolver este problema. Necesitamos más patrocinadores para colocar recompensas. https://www.bountysource.com/issues/1072081-right-button-menu-flashes-while-jkli-keys-move-the-mouse-pointer
Mi código actual (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()
Cuando presiono la tecla "shift", el foco se pierde, y cuando lo suelto, vuelve el foco.
Miré teclas de acceso rápido globales a principios de los 90 para Irix, Ultrix y Solaris, ya que había sido fácil de hacer en mi computadora Acorn BBC. Finalmente decidimos resolver esto de una manera no portátil en un nivel inferior a xlib con algún código de propiedad. Dado que nuestra instalación de software necesitaba como privilegios de superusuario de todos modos, pudimos insertar los ganchos de software apropiados como daemons.
Para Linux (hoy en día) probablemente debería buscar una solución de software procesando el evento del teclado en el nivel del sistema operativo. Empezaría echando un vistazo aquí: http://code.google.com/p/logkeys/
Una solución más genérica sería tener una pequeña placa de PC con entrada y salida USB, que actúa en la computadora como un mouse y un teclado y traduce las teclas del teclado según sea necesario. Pero esto no sería tan flexible si desea cambiar la asignación a menudo.
Para escribir un software de asignación de teclas (acceso directo), también consulte libtermkey
, una biblioteca de entrada de clave de terminal (escrita en C) que reconoce el informe de posición / botón del estilo XTerm, teclas especiales (como flecha y teclas de función), incluyendo " teclas modificadas como Ctrl-Left
.
Hay, por ejemplo, POE::Wheel::TermKey
, "un contenedor perl asíncrono alrededor de la biblioteca libtermkey
, que proporciona una forma abstracta de leer eventos de pulsación de tecla en programas basados en terminales".
Parece que XQueryKeymap lo resolverá. Vea a continuación el código fuente de C ++ que encontré :
/* 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);
}
Tenga en cuenta que este no es un código probado, ni es mío, simplemente lo encontré en Internet.
Puede usar XQueryKeymap para leer los eventos, luego puede usar XTestKey para enviar un evento de tecla de retroceso y luego la tecla que desea presionar. Mejor, podría registrar teclas rápidas para todos los eventos del teclado y luego generar el evento clave usando XTestKey. Por cierto, el módulo de control "Accesos directos personalizados" de KDE permite usar atajos para generar pulsaciones de teclas. Código fuente
Tengo una idea de que estoy bastante seguro de que funcionaría, pero tengo que irme a la cama y no puedo probarla por mí mismo, y no es bonita, ya que no creo que haya ninguna manera de hacer lo que quiero en X. Aquí están los pasos que tengo en mente. En resumen: desactive el teclado en X, lea los eventos desde la API de nivel inferior y vuélvalos a X usted mismo. Tienes que deshabilitar el teclado en X porque de lo contrario, podrías mirar el evento, pero no detenerlo; lo leerías junto a X, no lo interceptarías.
Entonces aquí está roto:
1) Ejecute xinput -list
para obtener el teclado que X está usando
2) Ejecute xinput list-props
id para encontrar la propiedad Device Enabled
3) Ejecute xinput set-prop id prop 0
para deshabilitar el dispositivo en 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
No sé cómo funciona xinput en el nivel xlib, simplemente lo llamaría al shell para simplificar la implementación.
4) Abra /dev/input/eventX
, donde X es el dispositivo de teclado. De hecho, buscaría el nombre (dado en xinput -list) en / dev / input / by-id y lo abriría de esa manera. Esto probablemente requerirá root en algún momento, ya que los permisos sobre estos son generalmente bastante restrictivos.
5) Lee la entrada del teclado desde allí:
El formato de los datos de los eventos de entrada es:
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
}
las entradas son de 32 bits, los usuales son de 16 bits. Como solo te interesa la entrada de teclado, puedes hacerlo de forma sencilla:
lee e ignora 8 bytes.
el siguiente byte debe ser 1, luego el siguiente es 0. si no, omita este evento
El siguiente byte es el final del código de tecla, y como hay <255 teclas, eso es suficiente para
omita el siguiente byte.
lea el siguiente byte para ver si se presiona o se libera
omita los siguientes tres bytes
6) Cuando tengas un evento que te interesa atrapar, tráelo tú mismo. De lo contrario, use XSendEvent para enviarlo a X para que pueda procesarse normalmente. Asignar el código de hardware que obtienes de / dev / input al keysym apropiado puede ser un truco, pero estoy bastante seguro de que hay una función en xlib en alguna parte para ayudar con esto.
7) goto 5 y bucle hasta que hayas terminado
8) ¡Asegúrate de volver a configurar todo como era cuando salías, o podrías romper la entrada del teclado del usuario a X!
Sugiero probar esto con un segundo teclado usb, puedes desactivar y escuchar los teclados de forma independiente el uno del otro con / dev / input y xinput, por lo que si bloqueas, aún tienes el primer teclado y funciona normalmente. (En realidad, creo que sería genial hacerlo intencionalmente con un segundo teclado, ¡duplicar los atajos de teclado!)
Pero sí, necesitar root y potencialmente dejar el teclado "separado" de X no son nada bonitos, y ese reenvío con SendKey podría ser más fácil decirlo que hacerlo, pero estoy bastante seguro de que esto funcionaría y te daría la máxima flexibilidad .