英文:
CGO converting Xlib XEvent struct to byte array?
问题
我正在使用Golang创建一个简单的窗口管理器(代码基于tinywm中的C代码)。为了使用Xlib,我正在使用cgo,所以我的头文件如下:
// #cgo LDFLAGS: -lX11
// #include <X11/Xlib.h>
我有一个变量声明,如下:
event := C.XEvent{}
然后,在事件循环中,我使用它进行赋值:
C.XNextEvent(display, &event) // 是的,display已经定义了
但是,当我尝试访问事件的属性,比如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结构类型来说是非常错误的。如果这有助于解决问题,XEvent结构在C库中的定义如下:
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;
英文:
I am creating a simple window manager (code based of the c code in tinywm) in Golang. To use Xlib, I am using cgo, so my header is:
// #cgo LDFLAGS: -lX11
// #include <X11/Xlib.h>
And I have a variable declaration, like:
event := C.XEvent{}
And then, I use this to assign to it, later, in the event loop:
C.XNextEvent(display, &event) // Yes, display is defined
But when I try to access properties on the event, such as xbutton or xkey, I get an error:
event.xbutton undefined (type C.XEvent has no field or method xbutton)
And when I look at the cgo output for XEvent, it looks like this, in the _cgo_gotypes.go
file:
type _Ctype_XEvent [192] byte
And I cant figure out what is going on, although I have a hunch that the type [192] byte
is very wrong for a C struct type. In case this helps, the XEvent struct looks like this in the C library:
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;
答案1
得分: 1
由于Go在一般情况下不支持C的联合类型,C的联合类型在Go中被表示为具有相同长度的字节数组。
另一个SO问题:https://stackoverflow.com/questions/14581063/golang-cgo-converting-union-field-to-go-type
或者go-nuts邮件列表帖子可能会有进一步的帮助。
简而言之,你不能简单地使用或者与使用联合的C代码进行简单的接口。至少你需要设置类似unsafe.Pointer
的东西来手动操作字段/类型,而你的示例看起来是一个特别麻烦的情况(即它不仅仅是上述链接案例中的几种不同类型的整数的联合)。
根据名称,我得到的印象是你可能想在Go中创建一个“事件”接口,并将每个所需的事件类型实现为实现该接口的Go类型。然后编写代码(在Go或C中),根据Go“联合”/[]byte的前C.sizeof(int)
字节将其转换为C联合,反之亦然(我认为每个X...事件类型中的第一个int类型
字段可能都包含在内)。
英文:
As mentioned 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.
Another SO question: https://stackoverflow.com/questions/14581063/golang-cgo-converting-union-field-to-go-type<br>
or a go-nuts mailing list post may be of further help.
In short, you won't be able to just simply use or simply interface with C code that uses a union. At a minimum you'll need set something like an unsafe.Pointer
to manipulate the field/type manually and your example looks like a particularly annoying case (i.e. it's not just a union over a few different kinds of integers as above linked cases are).
Given the names I get the impression you may want to create an "event" interface in Go and implement each of the required event types as Go types that implement that interface. Then write code (in Go or C) that converts to/from the C union based on the first C.sizeof(int)
bytes of the Go "union"/[]byte (I think the first int type
field is likely included in each if the X… event types).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论