如何使用JNA调用GetRawInputDeviceInfo?

时间:2015-05-29 14:12:58

标签: java jna user32

我想使用GetRawInputDeviceInfo从我的Java应用程序中调用JNA

这就是我的JNA Library界面:

public static final UINT RIDI_DEVICEINFO = new UINT(0x2000000b);

public static DWORD RIM_TYPE_KEYBOARD = new DWORD(1);

public static class RID_DEVICE_INFO extends Structure {
  public DWORD cbSize;
  public DWORD dwType;
  public RID_DEVICE_INFO_ ridDeviceInfo_;

  @Override
  protected List<String> getFieldOrder() {
    return asList("cbSize", "dwType", "ridDeviceInfo_");
  }
}

public static class RID_DEVICE_INFO_ extends Structure {
  public RID_DEVICE_INFO_MOUSE mouse;
  public RID_DEVICE_INFO_KEYBOARD keyboard;
  public RID_DEVICE_INFO_HID hid;

  @Override
  protected List<String> getFieldOrder() {
    return asList("mouse", "keyboard", "hid");
  }
}

public static class RID_DEVICE_INFO_MOUSE extends Structure {
  public DWORD dwId;
  public DWORD dwNumberOfButtons;
  public DWORD dwSampleRate;
  public BOOL fHasHorizontalWheel;

  @Override
  protected List<String> getFieldOrder() {
    return asList("dwId", "dwNumberOfButtons", "dwSampleRate", "fHasHorizontalWheel");
  }
}

public static class RID_DEVICE_INFO_KEYBOARD extends Structure {
  public DWORD dwType;
  public DWORD dwSubType;
  public DWORD dwKeyboardMode;
  public DWORD dwNumberOfFunctionKeys;
  public DWORD dwNumberOfIndicators;
  public DWORD dwNumberOfKeysTotal;

  @Override
  protected List<String> getFieldOrder() {
    return asList("dwType", "dwSubType", "dwKeyboardMode", "dwNumberOfFunctionKeys", "dwNumberOfIndicators", "dwNumberOfKeysTotal");
  }
}

public static class RID_DEVICE_INFO_HID extends Structure {
  public DWORD dwVendorId;
  public DWORD dwProductId;
  public DWORD dwVersionNumber;
  public USHORT usUsagePage;
  public USHORT usUsage;

  @Override
  protected List<String> getFieldOrder() {
    return asList("dwVendorId", "dwProductId", "dwVersionNumber", "usUsagePage", "usUsage");
  }
}

public UINT GetRawInputDeviceInfo(HANDLE hDevice, UINT uiCommand, PointerByReference pData, IntByReference pcbSize);

然后,我像这样使用GetRawInputDeviceInfo :(假设hDevice是从某处获得的有效HANDLE。)

UINT uiCommand = RIDI_DEVICEINFO;
RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
deviceInfo.cbSize.setValue(deviceInfo.size());
PointerByReference pData = new PointerByReference(deviceInfo.getPointer());
IntByReference pcbSize = new IntByReference(deviceInfo.size());
UINT lResult = INSTANCE.GetRawInputDeviceInfo(hDevice, uiCommand, pData, pcbSize);

我的问题是lResult为-1,GetRawInputDeviceInfo的文档说明pData对于设备信息来说不够大。我是否错误地定义了pDatacbSize?如果是这样,在这种情况下定义它们的正确方法是什么?

我的JNA版本是4.1.0。我的应用程序在Windows 7 64位上的Java 8上运行。

1 个答案:

答案 0 :(得分:1)

至少你需要修改你的结构以获得正确的表示。您目前有三个单独的字段,而您应该有Union。这将使您的结构尺寸大于预期。

此外,您应该直接传递结构作为第三个参数(使用PointerByReference不仅不正确,而且本机代码将接收指针的地址而不是结构的地址)。直接传递结构时,JNA知道何时需要将Java字段与本机内存同步。

public interface DeviceAccess extends StdCallLibrary {
    public static class RID_DEVICE_INFO extends Structure {
        public int cbSize;
        public int dwType;
        public RID_DEVICE_INFO_ ridDeviceInfo_;

        // Ensure the active field corresponds to what is read back from native memory
        protected void read() {
            super.read();
            type = RID_DEVICE_INFO_HID.class;
            switch(dwType) {
            case RID_DEVICE_INFO_MOUSE:
                type = RID_DEVICE_INFO_MOUSE.class; break;
            case RID_DEVICE_INFO_KEYBOARD:
                type = RID_DEVICE_INFO_KEYBOARD.class; break;
            default:
                break;
            }
            ridDeviceInfo_.setType(type);
        }

        @Override
        protected List<String> getFieldOrder() {
            return asList("cbSize", "dwType", "ridDeviceInfo_");
        }
    }

    public static class RID_DEVICE_INFO_ extends Union {
        public RID_DEVICE_INFO_MOUSE mouse;
        public RID_DEVICE_INFO_KEYBOARD keyboard;
        public RID_DEVICE_INFO_HID hid;
    }

    public UINT GetRawInputDeviceInfo(HANDLE hDevice, UINT uiCommand, RID_DEVICE_INFO pData, IntByReference pcbSize);
}

然后像这样使用它:

UINT uiCommand = RIDI_DEVICEINFO;
RID_DEVICE_INFO deviceInfo = new RID_DEVICE_INFO();
// Could also just put this in the constructor
deviceInfo.cbSize = deviceInfo.size();

IntByReference pcbSize = new IntByReference(deviceInfo.size());
UINT lResult = INSTANCE.GetRawInputDeviceInfo(hDevice, uiCommand, deviceInfo, pcbSize);