将本机C结构映射到JNA

时间:2015-04-13 15:16:42

标签: jna

很长的帖子......

我有以下已映射到JNA的C结构。 这些结构在Windows上用于从鼠标,键盘和其他HID设备获取原始输入。 问题是我在RAWINPUT.data.keyboard(RAWKEYBAORD)结构中没有得到任何东西。我还没有用鼠标测试过。

关于RAWMOUSE结构,它在technomage之前的评论之后被修改。

但我在预期的字段中没有得到任何数据,在调试时我可以看到有数据。 我想我可能错误地映射了结构,或者在使用它们时做错了什么。 有人可以告诉我,我的映射是否正确或可以使用一些更正?

我之前用C代码编写了一个DLL,我在Java中使用JNI。 但我宁愿松开DLL并使用Java。

下面的两种方法映射如下: C代码:

UINT WINAPI GetRawInputData(
  _In_       HRAWINPUT hRawInput,
  _In_       UINT uiCommand,
  _Out_opt_  LPVOID pData,
  _Inout_    PUINT pcbSize,
  _In_       UINT cbSizeHeader
);

Java代码:

int GetRawInputData(RawInputLibrary.HRAWINPUT hRawInput, int uiCommand, Memory pData, IntByReference pcbSize, int cbSizeHeader);

C代码:

BOOL WINAPI RegisterRawInputDevices(
  _In_  PCRAWINPUTDEVICE pRawInputDevices,
  _In_  UINT uiNumDevices,
  _In_  UINT cbSize
);

Java代码

boolean RegisterRawInputDevices(RawInputLibrary.RAWINPUTDEVICE pRawInputDevices, int uiNumDevices, int cbSize);

当我转储缓冲区时,我可以看到以下按下的键的值。在内存块6中的42是键盘上按下的字母b,该值根据我按下的键而改变。这是RAWINPUT结构的转储:

RawInputLibrary$RAWINPUT(allocated@0x525ecb8 (44 bytes) (shared from allocated@0x525ecb8 (44 bytes))) {
  RawInputLibrary$RAWINPUTHEADER header@0=RawInputLibrary$RAWINPUTHEADER(allocated@0x525ecb8 (16 bytes) (shared from allocated@0x525ecb8 (44 bytes) (shared from allocated@0x525ecb8 (44 bytes)))) {
    int dwType@0=1
    int dwSize@4=20
    WinNT$HANDLE hDevice@8=native@0x3da0cb3 (com.sun.jna.platform.win32.WinNT$HANDLE@3da0cb3)
    WinDef$WPARAM wParam@c=1
  }
  RawInputLibrary$RAWINPUT$DataUnion data@10=RawInputLibrary$RAWINPUT$DataUnion(allocated@0x525ecc8 (28 bytes) (shared from allocated@0x525ecb8 (44 bytes) (shared from allocated@0x525ecb8 (44 bytes)))) {
    RawInputLibrary$RAWMOUSE mouse@0=RawInputLibrary$RAWMOUSE(auto-allocated@0x525ed48 (28 bytes)) {
      short usFlags@0=0
      NativeLong ulButtons@4=0
      short usButtonFlags@8=0
      short usButtonData@a=0
      NativeLong ulRawButtons@c=0
      NativeLong lLastX@10=0
      NativeLong lLastY@14=0
      NativeLong ulExtraInformation@18=0
    }
    RawInputLibrary$RAWKEYBOARD keyboard@0=RawInputLibrary$RAWKEYBOARD(auto-allocated@0x525ed70 (16 bytes)) {
      short MakeCode@0=0
      short Flags@2=0
      short Reserved@4=0
      short VKey@6=0
      int Message@8=0
      NativeLong ExtraInformation@c=0
    }
    RawInputLibrary$RAWHID hid@0=RawInputLibrary$RAWHID(auto-allocated@0x525ed88 (12 bytes)) {
      int dwSizeHid@0=0
      int dwCount@4=0
      byte bRawData[1]@8=[B@50fe39
    }
  }
}
memory dump
[01000000]
[20000000]
[b30cda03]
[01000000]
[30000000]
[00004200]
[00010000]
[00000000]
[00000000]
[00000000]
[00000000]

这些是我映射的结构。这里可以看到C计数器部分(不发布它们以保持帖子更小):https://msdn.microsoft.com/en-us/library/windows/desktop/ff468899(v=vs.85).aspx

public static class HRAWINPUT extends PointerType {
    public HRAWINPUT(Pointer address) {
        super(address);
    }
    public HRAWINPUT() {
        super();
    }
}

public class RAWINPUT extends Structure {
        public static class ByReference extends RAWINPUT implements Structure.ByReference {}
        public static class ByValue extends RAWINPUT implements Structure.ByValue {}

        public RawInputLibrary.RAWINPUTHEADER   header;
        public DataUnion                                            data;

        public static class DataUnion extends Union {
            public static class ByReference extends DataUnion implements Structure.ByReference {}
            public static class ByValue extends DataUnion implements Structure.ByValue {}

            public RawInputLibrary.RAWMOUSE mouse;
            public RawInputLibrary.RAWKEYBOARD keyboard;

            public RawInputLibrary.RAWHID hid;
            public DataUnion() {
                super();
            }

            public DataUnion(RawInputLibrary.RAWMOUSE mouse) {
                super();
                this.mouse = mouse;
                setType(RawInputLibrary.RAWMOUSE.class);
            }

            public DataUnion(RawInputLibrary.RAWKEYBOARD keyboard) {
                super();
                this.keyboard = keyboard;
                setType(RawInputLibrary.RAWKEYBOARD.class);
            }

            public DataUnion(RawInputLibrary.RAWHID hid) {
                super();
                this.hid = hid;
                setType(RawInputLibrary.RAWHID.class);
            }

            protected List<? > getFieldOrder() {
                return Arrays.asList("mouse", "keyboard", "hid");
            }
        }

        public RAWINPUT() {
            super();
        }

        public RAWINPUT(Pointer p) {
            super(p);
            useMemory(p); //using this doesn't make any difference, but maybe I need to do something similar to this in the data struct ?
            read();
        }

        public RAWINPUT(RawInputLibrary.RAWINPUTHEADER header, DataUnion data) {
            super();
            this.header = header;
            this.data = data;
        }

        protected List<? > getFieldOrder() {
            return Arrays.asList("header", "data");
        }
    }

    public static class RAWINPUTHEADER extends Structure {
        public static class ByReference extends RAWINPUTHEADER implements Structure.ByReference {}
        public static class ByValue extends RAWINPUTHEADER implements Structure.ByValue {}

        public int                          dwType;
        public int                          dwSize;

        public WinNT.HANDLE         hDevice;
        public WinDef.WPARAM    wParam;

        public RAWINPUTHEADER() {
            super();
        }

        public RAWINPUTHEADER(int dwType, int dwSize, WinNT.HANDLE hDevice, WinDef.WPARAM wParam) {
            super();
            this.dwType = dwType;
            this.dwSize = dwSize;
            this.hDevice = hDevice;
            this.wParam = wParam;
        }

        protected List<?> getFieldOrder() {
            return Arrays.asList("dwType", "dwSize", "hDevice", "wParam");
        }
    }

    public static class RAWHID extends Structure {
        public static class ByReference extends RAWHID implements Structure.ByReference {}
        public static class ByValue extends RAWHID implements Structure.ByValue {}

        public          int dwSizeHid;
        public          int dwCount;
        public byte[]   bRawData = new byte[1];

        public RAWHID() {
            super();
        }

        public RAWHID(int dwSizeHid, int dwCount, byte bRawData[]) {
            super();
            this.dwSizeHid = dwSizeHid;
            this.dwCount = dwCount;

            if ((bRawData.length != this.bRawData.length)) {
                throw new IllegalArgumentException("Wrong array size !");
            }
            this.bRawData = bRawData;
        }

        protected List<? > getFieldOrder() {
            return Arrays.asList("dwSizeHid", "dwCount", "bRawData");
        }
    }

    public static class RAWKEYBOARD extends Structure {
        public static class ByReference extends RAWKEYBOARD implements Structure.ByReference {}
        public static class ByValue extends RAWKEYBOARD implements Structure.ByValue {}

        public short            MakeCode;
        public short            Flags;
        public short            Reserved;
        public short            VKey;
        public int                  Message;
        public NativeLong   ExtraInformation;

        public RAWKEYBOARD() {
            super();
        }

        public RAWKEYBOARD(short MakeCode, short Flags, short Reserved, short VKey, int Message, NativeLong ExtraInformation) {
            super();
            this.MakeCode = MakeCode;
            this.Flags = Flags;
            this.Reserved = Reserved;
            this.VKey = VKey;
            this.Message = Message;
            this.ExtraInformation = ExtraInformation;
        }

        protected List<?> getFieldOrder() {
            return Arrays.asList("MakeCode", "Flags", "Reserved", "VKey", "Message", "ExtraInformation");
        }

    }

    public static class RAWMOUSE extends Structure {
        public static class ByReference extends RAWMOUSE implements Structure.ByReference {}
        public static class ByValue extends RAWMOUSE implements Structure.ByValue {}

        public short                usFlags;
        public NativeLong       ulButtons;

        public short                usButtonFlags;
        public short                usButtonData;

        public NativeLong       ulRawButtons;
        public NativeLong       lLastX;
        public NativeLong       lLastY;
        public NativeLong       ulExtraInformation;

        public RAWMOUSE() {
            super();
        }

        public RAWMOUSE(short usFlags, NativeLong ulButtons, short usButtonFlags, short usButtonData, NativeLong ulRawButtons, NativeLong lLastX, NativeLong lLastY, NativeLong ulExtraInformation) {
            super();
            this.usFlags = usFlags;
            this.ulButtons = ulButtons;
            this.usButtonFlags = usButtonFlags;
            this.usButtonData = usButtonData;
            this.ulRawButtons = ulRawButtons;
            this.lLastX = lLastX;
            this.lLastY = lLastY;
            this.ulExtraInformation = ulExtraInformation;
        }

        protected List<?> getFieldOrder() {
            return Arrays.asList("usFlags", "ulButtons", "usButtonFlags", "usButtonData", "ulRawButtons", "lLastX", "lLastY", "ulExtraInformation");
        }
    }

下面的代码是我用来测试的代码的摘录。

private class WndProc implements User32.WindowProc {
    public WndProc() {
    }

    @Override
    public LRESULT callback(HWND hwnd, int msg, WPARAM wparam, LPARAM lparam) {
        switch (msg) {
            case User32.WM_CREATE: {
                if (hwnd != null) {
                    log.debug("Registering raw input device notifications...");
                    RawInputLibrary.RAWINPUTDEVICE.ByReference rawInputDevice = new RawInputLibrary.RAWINPUTDEVICE.ByReference();

                    //create an array of the struct in memory and fill it with data, and then parse the reference to the native call
                    RawInputLibrary.RAWINPUTDEVICE[] pRawInputDevice = (RawInputLibrary.RAWINPUTDEVICE[]) rawInputDevice.toArray(1);

                    pRawInputDevice[0].dwFlags = RawInputLibrary.RIDEV_INPUTSINK;       // receive system wide keystrokes
                    pRawInputDevice[0].usUsagePage = 1;                                             // generic desktop controls
                    pRawInputDevice[0].usUsage = 6;                                                     // keyboard
                    pRawInputDevice[0].hwndTarget = hwnd;

                    // register interest in raw data input
                    if (!rawInputLib.RegisterRawInputDevices(rawInputDevice, 1, rawInputDevice.size())) {
                        rawInputRegistrationSuccess = false;
                        log.error("Failed to register for raw input messages");
                    } else {
                        log.debug("Done registering raw input device notifications...");
                    }
                } else {
                    log.debug("window handle is not defined");
                }
                break;
            }
            case RawInputLibrary.WM_INPUT: {
                log.debug("Got raw input device message...");

                IntByReference dwSize = new IntByReference();
                int rawInputHeaderSize = new RawInputLibrary.RAWINPUTHEADER().size();
                RawInputLibrary.HRAWINPUT hRawInput = new RawInputLibrary.HRAWINPUT(lparam.toPointer());

                if (rawInputLib.GetRawInputData(hRawInput, RawInputLibrary.RID_INPUT, null, dwSize, rawInputHeaderSize) < 0) {
                    break;
                }

                if (dwSize.getValue() == 0) {
                    break;
                }

                IntByReference bufferSize = new IntByReference(Math.max(dwSize.getValue(), new RawInputLibrary.RAWINPUT().size()));
                Memory buffer = new Memory(bufferSize.getValue());
                if (rawInputLib.GetRawInputData(hRawInput, RawInputLibrary.RID_INPUT, buffer, bufferSize, rawInputHeaderSize) == -1) {
                    buffer.clear();
                    break;
                }

                RawInputLibrary.RAWINPUT rawinput = new RawInputLibrary.RAWINPUT(buffer);
                int event = rawinput.data.keyboard.Message;
                switch(event) {
                    case User32.WM_KEYDOWN:
                    case User32.WM_SYSKEYDOWN:
                        log.debug("Got raw input keyboard pressed");
                        switch(rawinput.data.keyboard.VKey){
                            //Shift
                            case 160:
                            case 161:
                                // inform listener about shift key pressed
                                break;

                            //Ignore special characters
                            case 144: //Numlock
                                break;

                            default:
                                // inform listener about key pressed
                                break;
                        }
                        break;
                    case User32.WM_KEYUP:
                    case User32.WM_SYSKEYUP:
                        if (rawinput.data.keyboard.VKey == 160 || rawinput.data.keyboard.VKey == 161) {
                            // inform listener about shift key released
                        }
                        break;
                    default:
                        break;
                }
                break;
            }
            default : {
                return user32Lib.DefWindowProc(hwnd, msg, wparam, lparam);
            }
        }
        return new LRESULT(0);
    }
}

0 个答案:

没有答案