CGO 将 Xlib XEvent 结构转换为字节数组?

CGO converting Xlib XEvent struct to byte array?

我正在 Golang 中创建一个简单的 window 管理器(代码基于 tinywm 中的 c 代码)。为了使用Xlib,我使用的是cgo,所以我的header是:

// #cgo LDFLAGS: -lX11
// #include <X11/Xlib.h>

我有一个变量声明,例如:

event := C.XEvent{}

然后,我用它来分配给它,稍后,在事件循环中:

C.XNextEvent(display, &event) // Yes, display is defined

但是当我尝试访问事件的属性(例如 xbutton 或 xkey)时,出现错误:

event.xbutton undefined (type C.XEvent has no field or method xbutton)

当我查看 XEvent 的 cgo 输出时,它看起来像这样,在 _cgo_gotypes.go 文件中:

type _Ctype_XEvent [192] byte

虽然我有预感类型 [192] byte 对于 C 结构类型来说是非常错误的,但我无法弄清楚发生了什么。如果这有帮助,C 库中的 XEvent 结构如下所示:

typedef union _XEvent {

    int type;   /* must not be changed */
    XAnyEvent xany;
    XKeyEvent xkey;
    XButtonEvent xbutton;
    XMotionEvent xmotion;
    XCrossingEvent xcrossing;
    XFocusChangeEvent xfocus;
    XExposeEvent xexpose;
    XGraphicsExposeEvent xgraphicsexpose;
    XNoExposeEvent xnoexpose;
    XVisibilityEvent xvisibility;
    XCreateWindowEvent xcreatewindow;
    XDestroyWindowEvent xdestroywindow;
    XUnmapEvent xunmap;
    XMapEvent xmap;
    XMapRequestEvent xmaprequest;
    XReparentEvent xreparent;
    XConfigureEvent xconfigure;
    XGravityEvent xgravity;
    XResizeRequestEvent xresizerequest;
    XConfigureRequestEvent xconfigurerequest;
    XCirculateEvent xcirculate;
    XCirculateRequestEvent xcirculaterequest;
    XPropertyEvent xproperty;
    XSelectionClearEvent xselectionclear;
    XSelectionRequestEvent xselectionrequest;
    XSelectionEvent xselection;
    XColormapEvent xcolormap;
    XClientMessageEvent xclient;
    XMappingEvent xmapping;
    XErrorEvent xerror;
    XKeymapEvent xkeymap;
    long pad[24];
} XEvent;

如前所述in the cgo documentation

As Go doesn't have support for C's union type in the general case, C's union types are represented as a Go byte array with the same length.

另一个问题:Golang CGo: converting union field to Go type
或者 a go-nuts mailing list post 可能会有进一步的帮助。

简而言之,您将无法简单地使用或简单地与使用联合的 C 代码交互。至少你需要设置类似 unsafe.Pointer 的东西来手动操作 field/type 并且你的示例看起来特别烦人(即它不仅仅是上面几种不同类型整数的联合关联案例是)。

鉴于这些名称,我的印象是您可能希望在 Go 中创建一个 "event" 接口,并将每个所需的事件类型实现为实现该接口的 Go 类型。然后编写代码(在 Go 或 C 中)根据 Go "union"/[] 字节的前 C.sizeof(int) 字节转换 to/from C 联合(我认为第一个 int type 字段可能包含在每个 if X… 事件类型中)。