From dc97bc9cf0fad3aa3ae59c7be583767ce5a8ae49 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Tue, 28 Jan 2014 01:34:45 +0100 Subject: [PATCH] Use range from evdev device for gamepad input --- build.xml | 3 ++ jni/nv_io/build.sh | 4 ++ jni/nv_io/nv_io_jni.c | 24 ++++++++++ src/com/limelight/input/EvdevAbsolute.java | 55 ++++++++++++++++++++++ src/com/limelight/input/EvdevHandler.java | 21 ++++++--- src/com/limelight/input/IO.java | 14 ++++++ 6 files changed, 115 insertions(+), 6 deletions(-) create mode 100755 jni/nv_io/build.sh create mode 100644 jni/nv_io/nv_io_jni.c create mode 100644 src/com/limelight/input/EvdevAbsolute.java create mode 100644 src/com/limelight/input/IO.java 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/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); + +}