2012-07-03 3 views
6

포커스가있는 창이나 포인터의 위치에 관계없이 모든 들어오는 키 누름 이벤트를 기록하고 싶습니다.X 포커스가있는 창에 관계없이 X 키 프레스/릴리스 이벤트

현재 포커스가있는 키 눌림 이벤트를 캡처해야하는 샘플 코드를 작성했습니다.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <locale.h> 
#include <stdint.h> 
#include <stdarg.h> 
#include <errno.h> 
#include <pthread.h> 
#include <X11/Xlib.h> 
#include <X11/Xos.h> 
#include <X11/Xfuncs.h> 
#include <X11/Xutil.h> 

#include <X11/Xatom.h> 
int _invalid_window_handler(Display *dsp, XErrorEvent *err) { 
    return 0; 
} 

int main() 
{ 
    Display *display = XOpenDisplay(NULL); 
    int iError; 
    KeySym k; 
    int revert_to; 
    Window window; 
    XEvent event; 
    Time time; 
    XSetErrorHandler(_invalid_window_handler); 
    XGetInputFocus(display, &window, &revert_to); 
    XSelectInput(display, window, KeyPressMask | KeyReleaseMask); 
    iError = XGrabKeyboard(display, window, 
          KeyPressMask | KeyReleaseMask, 
          GrabModeAsync, 
          GrabModeAsync, 
          CurrentTime); 
    if (iError != GrabSuccess && iError == AlreadyGrabbed) { 
     XUngrabPointer(display, CurrentTime); 
     XFlush(display); 
     printf("Already Grabbed\n");  
    } else if (iError == GrabSuccess) { 
     printf("Grabbed\n"); 
    } 
    while(1) { 
      XNextEvent(display,&event); 
      switch (event.type) { 
       case KeyPress : printf("Key Pressed\n"); break; 
       case KeyRelease : printf("Key Released\n"); break; 
       case EnterNotify : printf("Enter\n"); break; 
      } 
    } 
    XCloseDisplay(display); 
    return 0; 
} 

키보드를 캡처 한 응용 프로그램이 키보드 이벤트를 이미 가지고있을 수 있으므로 XGrabKeyboard를 호출하여 키보드를 캡처합니다. 위에서 언급 한 코드로 키보드를 잡을 수 있지만 while 루프 내부의 키보드에있는 키에 대해 KeyPress 또는 KeyRelease 이벤트를 수신 할 수 없습니다. 내가 이벤트를 수신 할 수 없기 때문에 코드에서 누락 된 것이 있습니까? 어떤 도움을 주셔서 감사합니다.

최종 목표는 포커스가있는 창에 관계없이 화면에서 주요 프레스 이벤트를 캡처하는 것입니다. 나는 코드를 읽을 수 있도록 포커스가있는 창만 샘플 코드를 제공했습니다. 나는 XQueryTree를 사용하여 모든 윈도우를 얻고 위에 주어진 동일한 로직을 적용하여 예상 된 결과를 얻는다.

+0

왜 다음 이벤트 하위 시스템을 사용하지? –

+0

이벤트 하위 시스템에 대해 자세히 설명해 주시겠습니까? KeyPressMask, KeyReleaseMask를 XSelectInput에 대한 호출에서 캡처 할 이벤트로 지정했습니다. 감사합니다 –

+0

Ignacio Vazquez-Abrams는 리눅스 커널 입력 서브 시스템을 가리키며'/ dev/input /'의 문자 장치를 통해 접근 할 수 있습니다. X를 완전히 무시하고 커널에서 직접 HID 이벤트를 가져 오지만 루트 권한도 필요합니다. –

답변

4

키보드를 잡으려면 매핑 된 창이 있어야합니다.

#include <X11/Xlib.h> 
#include <X11/keysym.h> 
#include <stdio.h> 

int main() 
{ 
    Display *display; 
    Window window, rootwindow; 
    XEvent event; 
    KeySym escape; 

    display = XOpenDisplay(NULL); 
    rootwindow = DefaultRootWindow(display); 
    window = XCreateWindow(display, rootwindow, 
          -99, -99, 1, 1, /* x, y, width, height */ 
          0, 0, InputOnly, /* border, depth, class */ 
          CopyFromParent, /* visual */ 
          0, NULL); /* valuemask and attributes */ 

    XSelectInput(display, window, StructureNotifyMask | SubstructureRedirectMask | ResizeRedirectMask | KeyPressMask | KeyReleaseMask); 
    XLowerWindow(display, window); 
    XMapWindow(display, window); 

    do { 
     XNextEvent(display, &event); 
    } while (event.type != MapNotify); 

    XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); 
    XLowerWindow(display, window); 

    escape = XKeysymToKeycode(display, XK_Escape); 
    printf("\nPress ESC to exit.\n\n"); 
    fflush(stdout); 

    while (1) { 

     XNextEvent(display, &event); 

     if (event.type == KeyPress) { 
      printf("KeyPress: keycode %u state %u\n", event.xkey.keycode, event.xkey.state); 
      fflush(stdout); 

     } else 
     if (event.type == KeyRelease) { 

      printf("KeyRelease: keycode %u state %u\n", event.xkey.keycode, event.xkey.state); 
      fflush(stdout); 

      if (event.xkey.keycode == escape) 
       break; 
     } else 
     if (event.type == UnmapNotify) { 

      XUngrabKeyboard(display, CurrentTime); 
      XDestroyWindow(display, window); 
      XCloseDisplay(display); 

      display = XOpenDisplay(NULL); 
      rootwindow = DefaultRootWindow(display); 
      window = XCreateWindow(display, rootwindow, 
            -99, -99, 1, 1, /* x, y, width, height */ 
            0, 0, InputOnly, /* border, depth, class */ 
            CopyFromParent, /* visual */ 
            0, NULL); /* valuemask and attributes */ 

      XSelectInput(display, window, StructureNotifyMask | SubstructureRedirectMask | ResizeRedirectMask | KeyPressMask | KeyReleaseMask); 
      XLowerWindow(display, window); 
      XMapWindow(display, window); 

      do { 
       XNextEvent(display, &event); 
      } while (event.type != MapNotify); 

      XGrabKeyboard(display, window, False, GrabModeAsync, GrabModeAsync, CurrentTime); 
      XLowerWindow(display, window); 

      escape = XKeysymToKeycode(display, XK_Escape); 

     } else { 

      printf("Event type %d\n", event.type); 
      fflush(stdout); 
     } 
    } 

    XUngrabKeyboard(display, CurrentTime); 

    XDestroyWindow(display, window); 
    XCloseDisplay(display); 
    return 0; 
} 

그것은 작은 창 (나는 심지어의 제목을 설정하는 귀찮게하지 않았다)는 윈도우 스택의 맨 아래로 낮추고, 그래서 기존의 창 뒤에 간다 사용 여기 개념의 증거입니다. 창 관리자 (WM)와 통신하여 창을 장식하지 않고 투명하게 만들거나 아이콘으로 표시하여 화면에 보이는 창이 보이지 않도록 할 수 있습니다. 위의 코드는 걱정하지 않습니다.

내가 사용한 트릭은 사용자가 다른 작업 공간으로 이동하여 창을 매핑 해제 할 때마다 코드가 이전 창을 삭제하고 새 창을 작성한 다음 키보드를 다시 가져 오는 것입니다. keypresses를 잃지 않을 정도로 빠르지 않아야합니다. 다른 방법이있을 수 있지만 창 관리자와 더 긴밀한 상호 작용이 필요하다고 생각됩니다.

키보드를 너무 오래 붙잡을 필요가 전혀 없으므로 위의 방법이 가장 단순하지 않을 수 있습니다. 그것은 제가 생각하기에 접근법이었습니다. 가능성이 더 좋은 것들이 있습니다.

+1

다른 X 응용 프로그램에서 키보드 이벤트를 수신하는 동안 키보드 이벤트를 캡처하는 방법이 있습니까? –

+3

'XSendEvent (display, InputFocus, True, KeyPressMask | KeyReleaseMask, event)'를 사용하여 현재 입력 포커스가있는 창으로 잡은 키보드 이벤트를 보낼 수는 있지만 일반적으로 잘못된 접근 방법입니다. 모든 키 누름을 모니터하고 싶다면 * do not * : 나는 키보드 스니퍼를 좋아하지 않는다. 단축키/자동 실행이 일반적으로 구현되는 방식을 보려면 예 : 'GtkHotKey' 또는'libtomboy/tomboykeybinder.c'; 루트 창에서 특정 키를 가져와 (즉, 다른 창에서 처리하지 않을 때) 올바른 작업을 수행합니다. –

+1

감사합니다.그냥 기록을 위해, 나는 모든 키 프레스를 모니터하여 내 오래된 키보드가 나에게 어떤 트릭을하지 않는지 확인합니다. –

3

다음 명령은 콘솔에 전체 X 세션의 모든 이벤트의 목록을 인쇄합니다 :

$ xinput test-xi2 --root 

예 출력 :

⎡ Virtual core pointer      id=2 [master pointer (3)] 
⎜ ↳ Virtual core XTEST pointer    id=4 [slave pointer (2)] 
⎜ ↳ USB Mouse         id=10 [slave pointer (2)] 
⎜ ↳ MCE IR Keyboard/Mouse (ite-cir)   id=11 [slave pointer (2)] 
⎣ Virtual core keyboard      id=3 [master keyboard (2)] 
    ↳ Virtual core XTEST keyboard    id=5 [slave keyboard (3)] 
    ↳ Power Button        id=6 [slave keyboard (3)] 
    ↳ Video Bus         id=7 [slave keyboard (3)] 
    ↳ Power Button        id=8 [slave keyboard (3)] 
    ↳ Oracle USB Keyboard      id=9 [slave keyboard (3)] 
    ↳ ITE8713 CIR transceiver     id=12 [slave keyboard (3)] 
EVENT type 14 (RawKeyRelease) 
    device: 3 (9) 
    detail: 36 
    valuators: 

EVENT type 3 (KeyRelease) 
    device: 9 (9) 
    detail: 36 
    flags: 
    root: 1324.55/821.81 
    event: 1324.55/821.81 
    buttons: 
    modifiers: locked 0x10 latched 0 base 0 effective: 0x10 
    group: locked 0 latched 0 base 0 effective: 0 
    valuators: 
    windows: root 0x9c event 0x9c child 0x7291d5 
EVENT type 15 (RawButtonPress) 
    device: 2 (10) 
    detail: 1 
    valuators: 
    flags: 

EVENT type 4 (ButtonPress) 
    device: 10 (10) 
    detail: 1 
    flags: 
    root: 1324.55/821.81 
    event: 1324.55/821.81 
    buttons: 
    modifiers: locked 0x10 latched 0 base 0 effective: 0x10 
    group: locked 0 latched 0 base 0 effective: 0 
    valuators: 
    windows: root 0x9c event 0x9c child 0x7291d5 
EVENT type 16 (RawButtonRelease) 
    device: 2 (10) 
    detail: 1 
    valuators: 
    flags: