diff --git a/plugins/wintab/build.xml b/plugins/wintab/build.xml
new file mode 100644
index 0000000..cc36299
--- /dev/null
+++ b/plugins/wintab/build.xml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabButtonComponent.java b/plugins/wintab/src/java/net/java/games/input/WinTabButtonComponent.java
new file mode 100644
index 0000000..ff6f425
--- /dev/null
+++ b/plugins/wintab/src/java/net/java/games/input/WinTabButtonComponent.java
@@ -0,0 +1,29 @@
+package net.java.games.input;
+
+import net.java.games.input.Component.Identifier;
+
+public class WinTabButtonComponent extends WinTabComponent {
+
+ private int index;
+
+ protected WinTabButtonComponent(WinTabContext context, int parentDevice, String name, Identifier id, int index) {
+ super(context, parentDevice, name, id);
+ this.index = index;
+ }
+
+ public Event processPacket(WinTabPacket packet) {
+ Event newEvent = null;
+
+ float newValue = ((packet.PK_BUTTONS & (int)Math.pow(2, index))>0) ? 1.0f : 0.0f;
+ if(newValue!=getPollData()) {
+ lastKnownValue = newValue;
+
+ //Generate an event
+ newEvent = new Event();
+ newEvent.set(this, newValue, packet.PK_TIME*1000);
+ return newEvent;
+ }
+
+ return newEvent;
+ }
+}
diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabComponent.java b/plugins/wintab/src/java/net/java/games/input/WinTabComponent.java
new file mode 100644
index 0000000..91ae205
--- /dev/null
+++ b/plugins/wintab/src/java/net/java/games/input/WinTabComponent.java
@@ -0,0 +1,195 @@
+package net.java.games.input;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import net.java.games.input.Component.Identifier;
+
+public class WinTabComponent extends AbstractComponent {
+
+ public final static int XAxis = 1;
+ public final static int YAxis = 2;
+ public final static int ZAxis = 3;
+ public final static int NPressureAxis = 4;
+ public final static int TPressureAxis = 5;
+ public final static int OrientationAxis = 6;
+ public final static int RotationAxis = 7;
+
+ private int parentDevice;
+ private int min;
+ private int max;
+ private WinTabContext context;
+ protected float lastKnownValue;
+ private boolean analog;
+
+ protected WinTabComponent(WinTabContext context, int parentDevice, String name, Identifier id, int min, int max) {
+ super(name, id);
+ this.parentDevice = parentDevice;
+ this.min = min;
+ this.max = max;
+ this.context = context;
+ analog = true;
+ }
+
+ protected WinTabComponent(WinTabContext context, int parentDevice, String name, Identifier id) {
+ super(name, id);
+ this.parentDevice = parentDevice;
+ this.min = 0;
+ this.max = 1;
+ this.context = context;
+ analog = false;
+ }
+
+ protected float poll() throws IOException {
+ return lastKnownValue;
+ }
+
+ public boolean isAnalog() {
+ return analog;
+ }
+
+ public boolean isRelative() {
+ // All axis are absolute
+ return false;
+ }
+
+ public static List createComponents(WinTabContext context, int parentDevice, int axisId, int[] axisRanges) {
+ List components = new ArrayList();
+ Identifier id;
+ switch(axisId) {
+ case XAxis:
+ id = Identifier.Axis.X;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ break;
+ case YAxis:
+ id = Identifier.Axis.Y;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ break;
+ case ZAxis:
+ id = Identifier.Axis.Z;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ break;
+ case NPressureAxis:
+ id = Identifier.Axis.X_FORCE;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ break;
+ case TPressureAxis:
+ id = Identifier.Axis.Y_FORCE;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ break;
+ case OrientationAxis:
+ id = Identifier.Axis.RX;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ id = Identifier.Axis.RY;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[2], axisRanges[3]));
+ id = Identifier.Axis.RZ;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[4], axisRanges[5]));
+ break;
+ case RotationAxis:
+ id = Identifier.Axis.RX;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[0], axisRanges[1]));
+ id = Identifier.Axis.RY;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[2], axisRanges[3]));
+ id = Identifier.Axis.RZ;
+ components.add(new WinTabComponent(context, parentDevice, id.getName(), id, axisRanges[4], axisRanges[5]));
+ break;
+ }
+
+ return components;
+ }
+
+ public static Collection createButtons(WinTabContext context, int deviceIndex, int numberOfButtons) {
+ List buttons = new ArrayList();
+ Identifier id;
+
+ for(int i=0;i0) {
+ Event ourEvent = (Event)eventList.remove(0);
+ event.set(ourEvent);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ protected void pollDevice() throws IOException {
+ // Get the data off the native queue.
+ context.processEvents();
+
+ super.pollDevice();
+ }
+
+ public Type getType() {
+ return Type.TRACKPAD;
+ }
+
+ public void processPacket(WinTabPacket packet) {
+ Component[] components = getComponents();
+ for(int i=0;i
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/plugins/wintab/src/native/net_java_games_input_WinTabContext.c b/plugins/wintab/src/native/net_java_games_input_WinTabContext.c
new file mode 100644
index 0000000..10863f9
--- /dev/null
+++ b/plugins/wintab/src/native/net_java_games_input_WinTabContext.c
@@ -0,0 +1,85 @@
+#include
+#include
+
+#include
+#include "net_java_games_input_WinTabContext.h"
+#include
+//#define PACKETDATA ( PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ROTATION | PK_ORIENTATION | PK_CURSOR )
+#define PACKETDATA ( PK_TIME | PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_CURSOR )
+#define PACKETMODE 0
+#include
+#include
+
+#define MAX_PACKETS 20
+
+JNIEXPORT jlong JNICALL Java_net_java_games_input_WinTabContext_nOpen(JNIEnv *env, jclass unused, jlong hWnd_long) {
+ LOGCONTEXT context;
+ HWND hWnd = (HWND)(INT_PTR)hWnd_long;
+ HCTX hCtx = NULL;
+
+ /* get default region */
+ WTInfo(WTI_DEFCONTEXT, 0, &context);
+
+ wsprintf(context.lcName, "JInput Digitizing");
+ context.lcPktData = PACKETDATA;
+ context.lcPktMode = PACKETMODE;
+ context.lcMoveMask = PACKETDATA;
+ context.lcBtnUpMask = context.lcBtnDnMask;
+
+ /* open the region */
+ hCtx = WTOpen(hWnd, &context, TRUE);
+
+ return (jlong)(intptr_t)hCtx;
+}
+
+JNIEXPORT void JNICALL Java_net_java_games_input_WinTabContext_nClose(JNIEnv *env, jclass unused, jlong hCtx_long) {
+ WTClose((HCTX)(INT_PTR)hCtx_long);
+}
+
+JNIEXPORT jint JNICALL Java_net_java_games_input_WinTabContext_nGetNumberOfSupportedDevices(JNIEnv *env, jclass unused) {
+ int numDevices;
+ WTInfo(WTI_INTERFACE, IFC_NDEVICES, &numDevices);
+ return numDevices;
+}
+
+JNIEXPORT jobjectArray JNICALL Java_net_java_games_input_WinTabContext_nGetPackets(JNIEnv *env, jclass unused, jlong hCtx_long) {
+
+ jobjectArray retval;
+ int i=0;
+ PACKET packets[MAX_PACKETS];
+ int numberRead = WTPacketsGet((HCTX)(INT_PTR)hCtx_long, MAX_PACKETS, packets);
+ jclass winTabPacketClass = (*env)->FindClass(env, "net/java/games/input/WinTabPacket");
+ jfieldID packetTimeField = (*env)->GetFieldID(env, winTabPacketClass, "PK_TIME", "J");
+ jfieldID packetXAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_X", "I");
+ jfieldID packetYAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_Y", "I");
+ jfieldID packetZAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_Z", "I");
+ jfieldID packetButtonsField = (*env)->GetFieldID(env, winTabPacketClass, "PK_BUTTONS", "I");
+ jfieldID packetNPressureAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_NORMAL_PRESSURE", "I");
+ jfieldID packetTPressureAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_TANGENT_PRESSURE", "I");
+ jfieldID packetCursorField = (*env)->GetFieldID(env, winTabPacketClass, "PK_CURSOR", "I");
+ jfieldID packetOrientationAltAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_ORIENTATION_ALT", "I");
+ jfieldID packetOrientationAzAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_ORIENTATION_AZ", "I");
+ jfieldID packetOrientationTwistAxisField = (*env)->GetFieldID(env, winTabPacketClass, "PK_ORIENTATION_TWIST", "I");
+ jobject prototypePacket = newJObject(env, "net/java/games/input/WinTabPacket", "()V");
+
+ retval = (*env)->NewObjectArray(env, numberRead, winTabPacketClass, NULL);
+ for(i=0;iSetLongField(env, tempPacket, packetTimeField, packets[i].pkTime);
+ (*env)->SetIntField(env, tempPacket, packetXAxisField, packets[i].pkX);
+ (*env)->SetIntField(env, tempPacket, packetYAxisField, packets[i].pkY);
+ (*env)->SetIntField(env, tempPacket, packetZAxisField, packets[i].pkZ);
+ (*env)->SetIntField(env, tempPacket, packetButtonsField, packets[i].pkButtons);
+ (*env)->SetIntField(env, tempPacket, packetNPressureAxisField, packets[i].pkNormalPressure);
+ (*env)->SetIntField(env, tempPacket, packetTPressureAxisField, packets[i].pkTangentPressure);
+ (*env)->SetIntField(env, tempPacket, packetCursorField, packets[i].pkCursor);
+ (*env)->SetIntField(env, tempPacket, packetOrientationAltAxisField, packets[i].pkOrientation.orAzimuth);
+ (*env)->SetIntField(env, tempPacket, packetOrientationAzAxisField, packets[i].pkOrientation.orAltitude);
+ (*env)->SetIntField(env, tempPacket, packetOrientationTwistAxisField, packets[i].pkOrientation.orTwist);
+
+ (*env)->SetObjectArrayElement(env, retval, i, tempPacket);
+ }
+
+ return retval;
+}
diff --git a/plugins/wintab/src/native/net_java_games_input_WinTabDevice.c b/plugins/wintab/src/native/net_java_games_input_WinTabDevice.c
new file mode 100644
index 0000000..45f202e
--- /dev/null
+++ b/plugins/wintab/src/native/net_java_games_input_WinTabDevice.c
@@ -0,0 +1,107 @@
+#include
+#include
+
+#include
+#include "net_java_games_input_WinTabDevice.h"
+#include "net_java_games_input_WinTabComponent.h"
+#include "util.h"
+#include
+#include
+#define PACKETDATA ( PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR )
+#define PACKETMODE 0
+#include
+
+JNIEXPORT jstring JNICALL Java_net_java_games_input_WinTabDevice_nGetName(JNIEnv *env, jclass unused, jint deviceIndex) {
+ char name[50];
+ WTInfo(WTI_DEVICES + deviceIndex, DVC_NAME, name);
+ return (*env)->NewStringUTF(env, name);
+}
+
+JNIEXPORT jintArray JNICALL Java_net_java_games_input_WinTabDevice_nGetAxisDetails(JNIEnv *env, jclass unused, jint deviceIndex, jint axisId) {
+ UINT type;
+ AXIS threeAxisArray[3];
+ AXIS axis;
+ long threeAxisData[6];
+ long axisData[2];
+ int res;
+ jintArray retVal = NULL;
+
+ if(axisId==net_java_games_input_WinTabComponent_XAxis) type = DVC_X;
+ else if(axisId==net_java_games_input_WinTabComponent_YAxis) type = DVC_Y;
+ else if(axisId==net_java_games_input_WinTabComponent_ZAxis) type = DVC_Z;
+ else if(axisId==net_java_games_input_WinTabComponent_NPressureAxis) type = DVC_NPRESSURE;
+ else if(axisId==net_java_games_input_WinTabComponent_TPressureAxis) type = DVC_TPRESSURE;
+ else if(axisId==net_java_games_input_WinTabComponent_OrientationAxis) type = DVC_ORIENTATION;
+ else if(axisId==net_java_games_input_WinTabComponent_RotationAxis) type = DVC_ROTATION;
+
+ if(axisId==net_java_games_input_WinTabComponent_RotationAxis || axisId==net_java_games_input_WinTabComponent_OrientationAxis) {
+ res = WTInfo(WTI_DEVICES + deviceIndex, type, &threeAxisArray);
+ if(res!=0) {
+ threeAxisData[0] = threeAxisArray[0].axMin;
+ threeAxisData[1] = threeAxisArray[0].axMax;
+ threeAxisData[2] = threeAxisArray[1].axMin;
+ threeAxisData[3] = threeAxisArray[1].axMax;
+ threeAxisData[4] = threeAxisArray[2].axMin;
+ threeAxisData[5] = threeAxisArray[2].axMax;
+ retVal = (*env)->NewIntArray(env, 6);
+ (*env)->SetIntArrayRegion(env, retVal, 0, 6, threeAxisData);
+ }
+ } else {
+ res = WTInfo(WTI_DEVICES + deviceIndex, type, &axis);
+ if(res!=0) {
+ axisData[0] = axis.axMin;
+ axisData[1] = axis.axMax;
+ retVal = (*env)->NewIntArray(env, 2);
+ (*env)->SetIntArrayRegion(env, retVal, 0, 2, axisData);
+ }
+ }
+
+ if(retVal==NULL) {
+ retVal = (*env)->NewIntArray(env, 0);
+ }
+
+ return retVal;
+}
+
+JNIEXPORT jobjectArray JNICALL Java_net_java_games_input_WinTabDevice_nGetCursorNames(JNIEnv *env, jclass unused, jint deviceId) {
+ int numberCursorTypes;
+ int firstCursorType;
+ char name[50];
+ int i;
+ jclass stringClass = (*env)->FindClass(env, "java/lang/String");
+ jstring nameString;
+ jobjectArray retval;
+
+ WTInfo(WTI_DEVICES + deviceId, DVC_NCSRTYPES, &numberCursorTypes);
+ WTInfo(WTI_DEVICES + deviceId, DVC_FIRSTCSR, &firstCursorType);
+
+ retval = (*env)->NewObjectArray(env, numberCursorTypes, stringClass, NULL);
+
+ for(i=0;iNewStringUTF(env, name);
+ (*env)->SetObjectArrayElement(env, retval, i-firstCursorType, nameString);
+ }
+
+ return retval;
+}
+
+JNIEXPORT jint JNICALL Java_net_java_games_input_WinTabDevice_nGetMaxButtonCount(JNIEnv *env, jclass unused, jint deviceId) {
+ int numberCursorTypes;
+ int firstCursorType;
+ byte buttonCount;
+ int i;
+ byte retval=0;
+
+ WTInfo(WTI_DEVICES + deviceId, DVC_NCSRTYPES, &numberCursorTypes);
+ WTInfo(WTI_DEVICES + deviceId, DVC_FIRSTCSR, &firstCursorType);
+
+ for(i=0;iretval) {
+ retval = buttonCount;
+ }
+ }
+
+ return (jint)retval;
+}