Skip to content

Commit

Permalink
make spi work
Browse files Browse the repository at this point in the history
  • Loading branch information
umjammer committed Jan 30, 2024
1 parent e9f1bd2 commit d3dd04a
Show file tree
Hide file tree
Showing 18 changed files with 443 additions and 146 deletions.
33 changes: 32 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,43 @@

<groupId>purejavahidapi</groupId>
<artifactId>purejavahidapi</artifactId>
<version>0.0.14v</version>
<version>0.0.15v-SNAPSHOT</version>

<packaging>jar</packaging>
<name>Pure Java HID-API</name>
<url>https://github.com/umjammer/purejavahidapi</url>

<profiles>
<profile>
<!-- mvn -P run antrun:run -Dfoo='bar' -->
<id>run</id>
<build>
<plugins>
<plugin>
<!-- GOOD: fork: OK, test jars: OK, user args, default args: OK -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>3.1.0</version>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<java classname="vavi.games.input.purejavahidapi.spi.GamepadTest" fork="true">
<classpath>
<path refid="maven.compile.classpath"/>
<path refid="maven.test.classpath"/>
</classpath>
<jvmarg value="-Djava.util.logging.config.file=${project.build.testOutputDirectory}/logging.properties" />
</java>
</target>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<build>
<plugins>
<plugin>
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/purejavahidapi/HidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public InputReportListener getInputReportListener() {
* <p>
*
* @param reportId a specifying the report ID to received
* @param data a byte array into which data is received
* @param data a byte array into which data is received, first byte for report id is included.
* @param length the size of the feature report
* @return the number of bytes actually received or -1 if the call failed
*/
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/purejavahidapi/InputReportListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ public interface InputReportListener {
* as possible and inside this call.
*
* @param source the HidDevice object that called this method
* @param reportID the report Id number if used or zero
* @param reportData the report data
* @param reportID the report id number if used or zero
* @param reportData the report data included first byte for report id
* @param reportLength report length
*/
void onInputReport(HidDevice source, byte reportID, byte[] reportData, int reportLength);
Expand Down
8 changes: 2 additions & 6 deletions src/main/java/purejavahidapi/linux/HidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,8 @@ private void runReadOnBackground() throws IOException {
// the HID descriptor AND parse it. I like the Mac OS and Windows ways better, what a mess the world is!
int bytes_read = read(m_DeviceHandle, m_InputReportBytes, m_InputReportBytes.length);
if (m_InputReportListener != null) {
byte reportID = 0;
if (m_UsesNumberedReports) {
reportID = m_InputReportBytes[0];
bytes_read--;
System.arraycopy(m_InputReportBytes, 1, m_InputReportBytes, 0, bytes_read);
}
byte reportID = m_UsesNumberedReports ? m_InputReportBytes[0] : 0;
System.arraycopy(m_InputReportBytes, 0, m_InputReportBytes, 0, bytes_read);
m_InputReportListener.onInputReport(this, reportID, m_InputReportBytes, bytes_read);
}
}
Expand Down
53 changes: 25 additions & 28 deletions src/main/java/purejavahidapi/macosx/HidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.sun.jna.Callback;
Expand All @@ -42,6 +43,8 @@
import purejavahidapi.DeviceRemovalListener;
import purejavahidapi.InputReportListener;
import purejavahidapi.shared.SyncPoint;
import vavi.util.Debug;
import vavi.util.StringUtil;

import static purejavahidapi.macosx.CoreFoundationLibrary.*;
import static purejavahidapi.macosx.IOHIDManagerLibrary.IOHIDDeviceCallback;
Expand Down Expand Up @@ -233,17 +236,18 @@ static String getStringProperty(IOHIDDeviceRef device, CFStringRef prop) {
return null;
}

/** */
static String createPathForDevice(IOHIDDeviceRef dev) {
short vid, pid;
String transport = getStringProperty(dev, CFSTR(kIOHIDTransportKey));
if (transport == null)
return null;
vid = (short) getIntProperty(dev, CFSTR(kIOHIDVendorIDKey));
pid = (short) getIntProperty(dev, CFSTR(kIOHIDProductIDKey));
short vid = (short) getIntProperty(dev, CFSTR(kIOHIDVendorIDKey));
short pid = (short) getIntProperty(dev, CFSTR(kIOHIDProductIDKey));

return String.format("%s_%04x_%04x_0x%08x", transport, vid, pid, Pointer.nativeValue(dev.getPointer()));
}

/** */
static class HidDeviceRemovalCallback implements IOHIDDeviceCallback {

@Override
Expand All @@ -259,29 +263,25 @@ public void hid_device_removal_callback(Pointer context, int result, Pointer sen
}
}

/** */
static class HidReportCallback implements IOHIDReportCallback {

@Override
public void callback(Pointer context, int result, Pointer sender, int reportType, int reportId, Pointer report, NativeLong report_length) {
// System.out.println("HidReportCallback "+Thread.currentThread().getName());
Debug.println(Level.FINER, "HidReportCallback: " + Thread.currentThread().getName());
HidDevice dev = m_DevFromCallback.get(this);
if (dev != null) {
if (dev.m_InputReportListener != null) {
int length;
if (reportId == 0) {
length = report_length.intValue();
report.read(0, dev.m_InputReportData, 0, length);
} else {
length = report_length.intValue() - 1;
report.read(1, dev.m_InputReportData, 0, length);
}
int length = report_length.intValue();
report.read(0, dev.m_InputReportData, 0, length);
dev.m_InputReportListener.onInputReport(dev, (byte) reportId, dev.m_InputReportData, length);
}
} else
System.err.println("HidReportCallback could not get the HidDevice object");
}
}

/** */
private static class PerformSignalCallback implements CFRunLoopPerformCallBack {

@Override
Expand All @@ -294,19 +294,19 @@ public void callback(Pointer context) {
public synchronized int getInputReportDescriptor(byte[] data, int length) {
CFTypeRef ref = IOHIDDeviceGetProperty(m_IOHIDDeviceRef, CFSTR(kIOHIDReportDescriptorKey));
if (ref != null && CFGetTypeID(ref.getPointer()) == CFDataGetTypeID()) {
Pointer descriptor_buf = CFDataGetBytePtr(ref.getPointer());
int copy_len = (int) CFDataGetLength(ref.getPointer());
Pointer descriptorBuf = CFDataGetBytePtr(ref.getPointer());
int copyLen = (int) CFDataGetLength(ref.getPointer());

if (descriptor_buf == null || copy_len < 0) {
if (descriptorBuf == null || copyLen < 0) {
throw new IllegalStateException("Zero buffer/length");
}

if (length < copy_len) {
copy_len = length;
if (length < copyLen) {
copyLen = length;
}

descriptor_buf.read(0, data, 0, copy_len);
return copy_len;
descriptorBuf.read(0, data, 0, copyLen);
return copyLen;
} else {
return -1;
}
Expand All @@ -322,29 +322,26 @@ public synchronized int getFeatureReport(int reportId, byte[] data, int length)
int res = IOHIDDeviceGetReport(m_IOHIDDeviceRef, kIOHIDReportTypeFeature, reportId, ByteBuffer.wrap(temp), len);
int rlen = len[0];
if (res == kIOReturnSuccess) {
if (reportId == 0) {
System.arraycopy(temp, 0, data, 0, rlen);
return rlen;
} else {
System.arraycopy(temp, 1, data, 0, rlen - 1);
return rlen - 1;
}
System.arraycopy(temp, 0, data, 0, rlen);
return rlen;
} else
return -1;
}

/** */
private int setReport(int type, byte reportID, byte[] data, int length) {
ByteBuffer data_to_send = ByteBuffer.wrap(data);
ByteBuffer dataToSend = ByteBuffer.wrap(data);

// On Mac OS X the IOHIDDeviceSetReport() always takes pure data and explicit report number (which maybe 0 if numbers are not used)
int res = IOHIDDeviceSetReport(m_IOHIDDeviceRef, type, 0xff & reportID, data_to_send, length);
int res = IOHIDDeviceSetReport(m_IOHIDDeviceRef, type, 0xff & reportID, dataToSend, length);

if (res == kIOReturnSuccess) {
return length;
} else
return -1;
}

/** */
private int setReportInternal(int type, byte reportId, byte[] data, int length) {
if (!m_Open)
throw new IllegalStateException("device not open");
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/purejavahidapi/macosx/MacOsXBackend.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ public purejavahidapi.HidDevice openDevice(purejavahidapi.HidDeviceInfo deviceIn
try {
return new HidDevice((HidDeviceInfo) deviceInfo, this);
} catch (IllegalStateException e) {
log.warning("no device for " + deviceInfo.getPath());
log.finer("no device for " + deviceInfo.getPath());
return null;
}
}
Expand All @@ -118,7 +118,7 @@ public purejavahidapi.HidDevice openDevice(purejavahidapi.HidDeviceInfo deviceIn
CFRelease(device_set);
return os_dev;
} else {
log.fine(String.format("IOHIDDeviceOpen: %d,%d,%d", (ret >> (32 - 6)) & 0x3f, (ret >> (32 - 6 - 12)) & 0xFFF, ret & 0x3FFF));
log.finer(String.format("IOHIDDeviceOpen: %d, %d, %d", (ret >> (32 - 6)) & 0x3f, (ret >> (32 - 6 - 12)) & 0xFFF, ret & 0x3FFF));
}
}
}
Expand All @@ -128,7 +128,7 @@ public purejavahidapi.HidDevice openDevice(purejavahidapi.HidDeviceInfo deviceIn
log.finest(String.format("device[%d]: %s", i, x));
}
CFRelease(device_set);
log.warning("no IOHIDDeviceRef for path: " + path);
log.finer("no IOHIDDeviceRef for path: " + path);
return null;
}

Expand Down
13 changes: 4 additions & 9 deletions src/main/java/purejavahidapi/windows/HidDevice.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,16 +273,11 @@ private void runReadOnBackground() {
}
}

if (m_Transfrd[INPUT][0] > 0) {
byte reportId = m_Buffer[INPUT].getByte(0);
m_Transfrd[INPUT][0]--;

m_Buffer[INPUT].read(1, m_InputReportBytes, 0, m_Transfrd[INPUT][0]);

if (m_InputReportListener != null)
m_InputReportListener.onInputReport(this, reportId, m_InputReportBytes, m_Transfrd[INPUT][0]);
}
byte reportId = m_Transfrd[INPUT][0] > 0 ? m_Buffer[INPUT].getByte(0) : 0;
m_Buffer[INPUT].read(0, m_InputReportBytes, 0, m_Transfrd[INPUT][0]);

if (m_InputReportListener != null)
m_InputReportListener.onInputReport(this, reportId, m_InputReportBytes, m_Transfrd[INPUT][0]);
}
m_SyncShutdown.waitAndSync();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

package vavi.games.input.purejavahidapi.spi;

import java.util.function.Function;

import net.java.games.input.AbstractComponent;
import net.java.games.input.WrappedComponent;
import net.java.games.input.usb.HidComponent;
Expand All @@ -25,6 +27,9 @@ public class HidapiComponent extends AbstractComponent implements HidComponent,

private final Field field;

/** special data picker (e.g. for touch x, y) */
private Function<byte[], Integer> function;

/**
* Protected constructor
*
Expand All @@ -37,12 +42,21 @@ protected HidapiComponent(String name, Identifier id, Field field) {
}

/**
* @param offset bits
* @param offset bits (must be excluded first one byte (8 bits) for report id)
* @param size bit length
*/
public HidapiComponent(String name, Identifier id, int offset, int size) {
this(name, id, offset, size, null);
}

/**
* @param offset bits (must be excluded first one byte (8 bits) for report id)
* @param size bit length
*/
public HidapiComponent(String name, Identifier id, int offset, int size, Function<byte[], Integer> function) {
super(name, id);
this.field = new Field(offset, size);
this.function = function;
}

@Override
Expand Down
Loading

0 comments on commit d3dd04a

Please sign in to comment.