views:

48

answers:

2

In JNA, how do you map a union structure like the following XEvent from Xlib

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 want to be able later on to cast the XEvent in JNA to other events (like XKeyEvent, XButtonEvent, XMotionEvent ...etc) based on the type of the event received.

I am not asking for a full mapping for all the structures above. A clear explanation with a small example on how to do it will be enough.

Thanks

A: 

The sources for JNA already provide examples for xlib.

This is described here. here

The implementation can be found in the jna sources under the contrib folder.

Specifically for XEvent it is defined as:

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

I'm still learning JNA myself but I believe the idea is check the type value and then only refer to the corresponding event field. The others should be null. I don't think it is possible to do this through a cast.

Aaron
Have you tried it? I tried the code in contrib with XGrabKeyboard with XNextEvent. It returns the XEvent and the type is KeyPress/KeyRelease, however, when I access the event.xkey.keycode, I always get zero regardless of which key pressed. If you tried it successfully, then I will mark your answer as the correct one, as maybe the problem is somewhere else in my code.
Untitled
A: 

Use the mappings defined in the JNA contrib (com.sun.jna.platform.X11) then do the following:

  1. Get the XEvent using whatever method yo prefer (e.g. XNextEvent).
  2. Determine the type of the event using the type field.
  3. Based on the type, call the method readFiled with the field name (in string) and cast the returned value to the event type of the field name.

Example:

XEvent event = new XEvent();
X11.INSTANCE.XNextEvent(display, event);
if(event.type == X11.KeyPress) {
    XKeyEvent xKey = (XKeyEvent)event.readField("xkey");
    // you can now use xKey.keycode and other fields
}
temp