10

どのウィンドウがフォーカスされているか、またはポインターがどこにあるかに関係なく、すべての着信キーが押されたイベントを記録したいと考えています。

フォーカスされている現在のウィンドウのキーが押されたイベントをキャプチャするサンプル コードを作成しました。

#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 を実行してすべての Windows を取得し、上記と同じロジックを適用して期待される結果を取得します。

4

2 に答える 2

8

キーボードをつかむことができるようにするには、マップされたウィンドウが必要です。概念実証は次のとおりです。

#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) と通信して、ウィンドウを装飾なしで透明にするか、アイコン化して、画面上にウィンドウが表示されないようにすることができます。上記のコードは気にしません。

私が使用したトリックは、ユーザーがウィンドウのマップを解除するたびに (たとえば、別のワークスペースに移動することによって)、コードが古いウィンドウを破棄し、新しいウィンドウを作成して、キーボードを再取得するというものです。キープレスを失わないのに十分な速さである必要があります。他にも方法があるかもしれませんが、ウィンドウマネージャーとのより緊密なやり取りが必要になると思います。

ここまで執拗にキーボードをつかむ必要はなかったので、上記のアプローチはおそらく最も単純ではないことに注意してください。それは私がうまくいくと思うアプローチでした。より良いものがある可能性があります。

于 2012-07-04T04:15:37.530 に答える
6

次のコマンドは、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: 
于 2015-04-05T16:26:44.203 に答える