diff --git a/build.xml b/build.xml
index 5e02527..e9654f3 100644
--- a/build.xml
+++ b/build.xml
@@ -10,6 +10,7 @@
+
@@ -40,6 +41,7 @@
+
@@ -84,6 +86,7 @@
+
diff --git a/jni/nv_io/build.sh b/jni/nv_io/build.sh
new file mode 100755
index 0000000..ed03e0c
--- /dev/null
+++ b/jni/nv_io/build.sh
@@ -0,0 +1,4 @@
+rm *.o libnv_io.so
+gcc -I $JAVA_HOME/include -I $JAVA_HOME/include/linux -fPIC -L. -c *.c
+gcc -shared -Wl,-soname,libnv_io.so -Wl,--no-undefined -o libnv_io.so *.o -L.
+rm *.o
diff --git a/jni/nv_io/libnv_io.so b/jni/nv_io/libnv_io.so
new file mode 100755
index 0000000..67fae47
Binary files /dev/null and b/jni/nv_io/libnv_io.so differ
diff --git a/jni/nv_io/nv_io_jni.c b/jni/nv_io/nv_io_jni.c
new file mode 100644
index 0000000..c587a37
--- /dev/null
+++ b/jni/nv_io/nv_io_jni.c
@@ -0,0 +1,24 @@
+#include
+#include
+
+JNIEXPORT jboolean JNICALL
+Java_com_limelight_input_IO_ioctl(
+ JNIEnv *env, jobject this, // JNI parameters
+ jstring filename, jbyteArray buffer, jint request)
+{
+ const char* jni_filename = (*env)->GetStringUTFChars(env, filename, NULL);
+ unsigned char* jni_buffer = (*env)->GetByteArrayElements(env, buffer, NULL);
+
+ jboolean retval;
+ int fd;
+ if ((fd = open(jni_filename, O_RDONLY)) < 0) {
+ retval = 0;
+ } else {
+ ioctl(fd, request, jni_buffer);
+ close(fd);
+ retval = 1;
+ }
+
+ (*env)->ReleaseByteArrayElements(env, buffer, jni_buffer, 0);
+ return retval;
+}
\ No newline at end of file
diff --git a/src/com/limelight/input/EvdevAbsolute.java b/src/com/limelight/input/EvdevAbsolute.java
new file mode 100644
index 0000000..be0e95d
--- /dev/null
+++ b/src/com/limelight/input/EvdevAbsolute.java
@@ -0,0 +1,55 @@
+package com.limelight.input;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * Class that handles absolute input ranges from evdev device
+ * @author Iwan Timmer
+ */
+public class EvdevAbsolute {
+
+ private final static int ABS_OFFSET = 0x40;
+ private final static int READ_ONLY = 2;
+ private final static char EVDEV_TYPE = 'E';
+
+ private int avg;
+ private int range;
+
+ public EvdevAbsolute(String filename, int axis) {
+ ByteBuffer buffer = ByteBuffer.allocate(6*4);
+ buffer.order(ByteOrder.nativeOrder());
+ byte[] data = buffer.array();
+ int request = getRequest(READ_ONLY, EVDEV_TYPE, ABS_OFFSET+axis, 6*4);
+ IO.ioctl(filename, data, request);
+
+ buffer.getInt(); //Skip current value
+ int min = buffer.getInt();
+ int max = buffer.getInt();
+ avg = (min+max)/2;
+ range = max-avg;
+ }
+
+ private int getRequest(int dir, int type, int nr, int size) {
+ return (dir << 30) | (size << 16) | (type << 8) | nr;
+ }
+
+ /**
+ * Convert input value to short range
+ * @param value received input
+ * @return input value as short
+ */
+ public short getShort(int value) {
+ return (short) ((value-avg) * range / Short.MAX_VALUE);
+ }
+
+ /**
+ * Convert input value to byte range
+ * @param value received input
+ * @return input value as byte
+ */
+ public byte getByte(int value) {
+ return (byte) ((value-avg) * range / Byte.MAX_VALUE);
+ }
+
+}
diff --git a/src/com/limelight/input/EvdevHandler.java b/src/com/limelight/input/EvdevHandler.java
index 95170b4..58efa6e 100644
--- a/src/com/limelight/input/EvdevHandler.java
+++ b/src/com/limelight/input/EvdevHandler.java
@@ -28,6 +28,8 @@ public class EvdevHandler implements Runnable {
private byte leftTrigger, rightTrigger;
private short leftStickX, leftStickY, rightStickX, rightStickY;
+ private EvdevAbsolute absLX, absLY, absRX, absRY, absLT, absRT;
+
private NvConnection conn;
private FileChannel deviceInput;
private ByteBuffer inputBuffer;
@@ -48,6 +50,13 @@ public class EvdevHandler implements Runnable {
inputBuffer = ByteBuffer.allocate(EvdevConstants.MAX_STRUCT_SIZE_BYTES);
inputBuffer.order(ByteOrder.nativeOrder());
+ absLX = new EvdevAbsolute(device, mapping.abs_x);
+ absLY = new EvdevAbsolute(device, mapping.abs_y);
+ absRX = new EvdevAbsolute(device, mapping.abs_rx);
+ absRY = new EvdevAbsolute(device, mapping.abs_ry);
+ absLT = new EvdevAbsolute(device, mapping.abs_rudder);
+ absRT = new EvdevAbsolute(device, mapping.abs_throttle);
+
translator = new KeyboardTranslator(conn);
}
@@ -140,17 +149,17 @@ public class EvdevHandler implements Runnable {
conn.sendMouseMove((short) 0, (short) value);
} else if (type==EvdevConstants.EV_ABS) {
if (code==mapping.abs_x)
- leftStickX = (short) value;
+ leftStickX = absLX.getShort(value);
else if (code==mapping.abs_y)
- leftStickY = (short) value;
+ leftStickY = absLY.getShort(value);
else if (code==mapping.abs_rx)
- rightStickX = (short) value;
+ rightStickX = absRX.getShort(value);
else if (code==mapping.abs_ry)
- rightStickY = (short) value;
+ rightStickY = absRY.getShort(value);
else if (code==mapping.abs_throttle)
- leftTrigger = (byte) value;
+ leftTrigger = absLT.getByte(value);
else if (code==mapping.abs_rudder)
- rightTrigger = (byte) value;
+ rightTrigger = absRT.getByte(value);
conn.sendControllerInput(buttonFlags, leftTrigger, rightTrigger, leftStickX, leftStickY, rightStickX, rightStickY);
}
diff --git a/src/com/limelight/input/IO.java b/src/com/limelight/input/IO.java
new file mode 100644
index 0000000..c919f77
--- /dev/null
+++ b/src/com/limelight/input/IO.java
@@ -0,0 +1,14 @@
+package com.limelight.input;
+
+/**
+ * IO bindings
+ * @author Iwan Timmer
+ */
+public class IO {
+ static {
+ System.loadLibrary("nv_io");
+ }
+
+ public static native boolean ioctl(String filename, byte[] buffer, int request);
+
+}