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

관련 정보