Qemu / Spiceが他の場所にバインドされたキーをキャッチするのを防ぎます。

Qemu / Spiceが他の場所にバインドされたキーをキャッチするのを防ぎます。

私の設定:libvirtで管理されているSpiceディスプレイを持つQemu、LinuxでX11を実行します。

QemuクライアントにフォーカスがあるときにウィンドウマネージャとXサーバーでキーバインディングを維持する方法を探しています。libvirtやQemuオプション、コンパイルフラグ、いくつかのX11マジックなど何でも可能です。

具体的な例:キーを押すと、Mod4+1WMがラベルに切り替わります。1。現在、ゲストは1 入力として受信し、WMは何も受信しません。

グラフィックQemuクライアント(主にWindowsクライアントですが重要ではありません)は、xkbをバイパスしても無差別にキーボード入力を受け取るようです。などの項目は無視してくださいcapslock(swapescape)

これにより、ウィンドウマネージャが混乱する可能性があります。たとえば、クライアントの繰り返し中にQemuクライアントに集中すると、WMのバインディングは役に立ちません。マウスを動かして問題の顧客の注意を分散させるまで。言うまでもなく、これはキーボードベースのワークフローを中断します。本当に迷惑ですね。

さらに、入力がクライアントに渡されるので、ゲスト内部アプリケーションが入力を処理するように選択する方法によっては、あらゆる種類の興味深いことが発生する可能性があります。

編集:アップストリームではこれが望ましい動作だと思うようです。「キーボードフォーカスを受け取ったら、好きなようにキーボードを持ちます。どのキーボードフォーカスが表示されたら、キーを押して仮想マシンに入ります。 - 私が避けたいのはこれです。 Spiceのお客様が権利を持つ理由はありません。みんなフォーカスを受信するかどうかにかかわらず、キーボード入力。

答え1

あなたはウィンドウマネージャの親 - 子関係のリセット。また、ウィンドウマネージャは、キーボードイベントの伝播がソースウィンドウではなく親ウィンドウで開始されていることを確認する必要があります(Xlibのデフォルト)。

答え2

このトリックを使用して(またはから)関数をLD_PRELOADオーバーライドできます。XGrabKeyboardXlibxcb_grab_keyboardlibxcb

例:

$ cat xgkb.c
#include <X11/Xlib.h>
int XGrabKeyboard(Display *dpy, Window gw, Bool oe, int pm, int km, Time t){
        return 0;
}
$ cc -shared xgkb.c -o xgkb.so
$ LD_PRELOAD=`pwd`/xgkb.so your_program

XGrabKeyboard()もちろん、ラッパーで同じパラメータを使用してrealを呼び出して、特定のフラグ(たとえば、ルートウィンドウの一部のプロパティ)が設定されている場合は、キャッチを成功させることでこれを改善できます。 (探すdlopen(3)、、、dlsym(3)RTLD_NEXT

終わり:

virt-viewerはXIGrabDeviceキーボードとポインタをキャッチするために(おそらくgtk経由で)使用しているので、より多くの介入が必要です。デバイスがキーボードの場合、キャッチはキャンセルされます。

$ cat xigd.c
#define _GNU_SOURCE
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#include <dlfcn.h>

#include <err.h>

Status XIGrabDevice(
        Display*           dpy,
        int                deviceid,
        Window             grab_window,
        Time               time,
        Cursor             cursor,
        int                grab_mode,
        int                paired_device_mode,
        Bool               owner_events,
        XIEventMask        *mask
){
        int n, is_kb;
        static Status (*XIGrabDevice_orig)(Display*, int, Window, Time,
                Cursor, int, int, Bool, XIEventMask*);
        if(!XIGrabDevice_orig)
                XIGrabDevice_orig = dlsym(RTLD_NEXT, "XIGrabDevice");
        XIDeviceInfo *info = XIQueryDevice(dpy, deviceid, &n);
        is_kb = info->num_classes == 1 && info->classes[0]->type == XIKeyClass;
        warnx("trying XIGrabDevice %d %s is_kb=%d %p\n",
                deviceid, info->name, is_kb, XIGrabDevice_orig);
        XIFreeDeviceInfo(info);
        return is_kb ? 0 :
                XIGrabDevice_orig(dpy, deviceid, grab_window,
                        time, cursor, grab_mode, paired_device_mode,
                        owner_events, mask);
}
$ cc -shared -ldl -Wall -W xigd.c -o xigd.so
$ LD_PRELOAD=`pwd`/xigd.so virt-viewer ...

関連情報