diff options
11 files changed, 875 insertions, 0 deletions
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 @@ +<?xml version="1.0"?> +<project name="WinTab Input Plugin" basedir="." default="all"> + <target name="init"> + <mkdir dir="classes"/> + <mkdir dir="bin"/> + <condition property="wintab" > + <os family="Windows" /> + </condition> + </target> + + <target name="compile" depends="init"> + <javac srcdir="../windows/src/java" destdir="classes" debug="true" deprecation="true" source="1.4" target="1.4"> + <include name="**/DummyWindow.java"/> + </javac> + + <javac srcdir="src/java" destdir="classes" debug="true" deprecation="true" source="1.4" target="1.4"> + <!-- To add something to the classpath: --> + <classpath> + <pathelement location="../../coreAPI/bin/jinput-core.jar"/> + <pathelement location="../../lib/jutils.jar"/> + </classpath> + </javac> + </target> + + <target depends="init,compile" name="create_jniheaders"> + <javah destdir="src/native"> + <classpath> + <pathelement path="classes"/> + <pathelement location="../../coreAPI/classes"/> + </classpath> + <class name="net.java.games.input.DummyWindow"/> + <class name="net.java.games.input.WinTabContext"/> + <class name="net.java.games.input.WinTabDevice"/> + <class name="net.java.games.input.WinTabComponent"/> + </javah> + </target> + + <target name="compile_native" depends="init,create_jniheaders" if="wintab"> + <ant dir="src/native" target="compile"/> + <copy todir="bin"> + <fileset dir="src/native" includes="*.dll"/> + </copy> + </target> + + <target name="jar" depends="init,compile"> + <jar jarfile="bin/wintab.jar" compress="true" basedir="classes"> + <include name="**/*.class"/> + </jar> + </target> + + <target name="all" depends="compile,compile_native,jar" description="Build everything."> + </target> + + <target name="javadoc" depends="init" description="Javadoc for my API."> + <mkdir dir="apidocs"/> + <javadoc packagenames="net.*" + destdir="apidocs" + additionalparam="-source 1.4"> + <sourcepath> + <pathelement location="src/java"/> + </sourcepath> + <classpath> + <pathelement location="../windows/src/java"/> + <pathelement location="../../bin/jinput-core.jar"/> + <pathelement location="../../lib/jutils.jar"/> + </classpath> + </javadoc> + </target> + + <target name="clean" depends="init" description="Clean all build products."> + <delete dir="classes" failonerror="no"/> + <delete dir="bin" failonerror="no"/> + <delete dir="apidocs" failonerror="no"/> + <ant inheritAll="false" antfile="src/native/build.xml" target="clean"/> + </target> +</project> 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;i<numberOfButtons;i++) { + try { + Class buttonIdClass = Identifier.Button.class; + Field idField = buttonIdClass.getField("_" + i); + id = (Identifier)idField.get(null); + buttons.add(new WinTabButtonComponent(context, deviceIndex, id.getName(), id, i)); + } catch (SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchFieldException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalArgumentException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + return buttons; + } + + public Event processPacket(WinTabPacket packet) { + // Set this to be the old value incase we don't change it + float newValue=lastKnownValue; + + if(getIdentifier()==Identifier.Axis.X) { + newValue = normalise(packet.PK_X); + } + if(getIdentifier()==Identifier.Axis.Y) { + newValue = normalise(packet.PK_Y); + } + if(getIdentifier()==Identifier.Axis.Z) { + newValue = normalise(packet.PK_Z); + } + if(getIdentifier()==Identifier.Axis.X_FORCE) { + newValue = normalise(packet.PK_NORMAL_PRESSURE); + } + if(getIdentifier()==Identifier.Axis.Y_FORCE) { + newValue = normalise(packet.PK_TANGENT_PRESSURE); + } + if(getIdentifier()==Identifier.Axis.RX) { + newValue = normalise(packet.PK_ORIENTATION_ALT); + } + if(getIdentifier()==Identifier.Axis.RY) { + newValue = normalise(packet.PK_ORIENTATION_AZ); + } + if(getIdentifier()==Identifier.Axis.RZ) { + newValue = normalise(packet.PK_ORIENTATION_TWIST); + } + if(newValue!=getPollData()) { + lastKnownValue = newValue; + + //Generate an event + Event newEvent = new Event(); + newEvent.set(this, newValue, packet.PK_TIME*1000); + return newEvent; + } + + return null; + } + + private float normalise(float value) { + if(max == min) return value; + float bottom = max - min; + return (value - min)/bottom; + } + + public static Collection createCursors(WinTabContext context, int deviceIndex, String[] cursorNames) { + Identifier id; + List cursors = new ArrayList(); + + for(int i=0;i<cursorNames.length;i++) { + if(cursorNames[i].matches("Puck")) { + id = Identifier.Button.TOOL_FINGER; + } else if(cursorNames[i].matches("Eraser.*")) { + id = Identifier.Button.TOOL_RUBBER; + } else { + id = Identifier.Button.TOOL_PEN; + } + cursors.add(new WinTabCursorComponent(context, deviceIndex, id.getName(), id, i)); + } + + return cursors; + } +} diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabContext.java b/plugins/wintab/src/java/net/java/games/input/WinTabContext.java new file mode 100644 index 0000000..185f4c2 --- /dev/null +++ b/plugins/wintab/src/java/net/java/games/input/WinTabContext.java @@ -0,0 +1,74 @@ +package net.java.games.input; + +import java.util.ArrayList; +import java.util.List; + +public class WinTabContext { + + private DummyWindow window; + private long hCTX; + private Controller[] controllers; + + public WinTabContext(DummyWindow window) { + this.window = window; + } + + public Controller[] getControllers() { + if(hCTX==0) { + throw new IllegalStateException("Context must be open before getting the controllers"); + } + return controllers; + } + + public synchronized void open() { + ControllerEnvironment.logln("Opening context"); + this.hCTX = nOpen(window.getHwnd()); + List devices = new ArrayList(); + + int numSupportedDevices = nGetNumberOfSupportedDevices(); + ControllerEnvironment.logln(numSupportedDevices + " devices maximum supported"); + for(int i=0;i<numSupportedDevices;i++) { + WinTabDevice newDevice = WinTabDevice.createDevice(this,i); + if(newDevice!=null) { + devices.add(newDevice); + } + } + + controllers = (Controller[])devices.toArray(new Controller[0]); + } + + public synchronized void close() { + ControllerEnvironment.logln("Closing context"); + nClose(hCTX); + } + + public synchronized void processEvents() { + WinTabPacket[] packets = nGetPackets(hCTX); + //ControllerEnvironment.logln("Packets read: " + packets.length); + for(int i=0;i<packets.length;i++) { + //ControllerEnvironment.logln("Packet time: " + packets[i].PK_TIME); + //ControllerEnvironment.logln("Packet x: " + packets[i].PK_X); + //ControllerEnvironment.logln("Packet y: " + packets[i].PK_Y); + //ControllerEnvironment.logln("Packet z: " + packets[i].PK_Z); + //ControllerEnvironment.logln("Packet buttons: " + packets[i].PK_BUTTONS); + //ControllerEnvironment.logln("Packet cursor: " + packets[i].PK_CURSOR); + //ControllerEnvironment.logln("Packet Normal Pressure: " + packets[i].PK_NORMAL_PRESSURE); + //ControllerEnvironment.logln("Packet Tangent Pressure: " + packets[i].PK_TANGENT_PRESSURE); + //ControllerEnvironment.logln("Packet Alt: " + packets[i].PK_ORIENTATION_ALT); + //ControllerEnvironment.logln("Packet Az: " + packets[i].PK_ORIENTATION_AZ); + //ControllerEnvironment.logln("Packet Twist: " + packets[i].PK_ORIENTATION_TWIST); + + // TODO I can't seem to find a way to identify which device the packet is for + // This is not good. + // NASTY HACK based of assumptions that might very well be wrong + // Just send it to the first device + ((WinTabDevice)(getControllers()[0])).processPacket(packets[i]); + } + } + + private final static native int nGetNumberOfSupportedDevices(); + private final static native long nOpen(long hwnd); + private final static native void nClose(long hCtx); + private final static native WinTabPacket[] nGetPackets(long hCtx); + +} diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabCursorComponent.java b/plugins/wintab/src/java/net/java/games/input/WinTabCursorComponent.java new file mode 100644 index 0000000..5f65399 --- /dev/null +++ b/plugins/wintab/src/java/net/java/games/input/WinTabCursorComponent.java @@ -0,0 +1,28 @@ +package net.java.games.input; + +import net.java.games.input.Component.Identifier; + +public class WinTabCursorComponent extends WinTabComponent { + + private int index; + + protected WinTabCursorComponent(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; + if(packet.PK_CURSOR==index && lastKnownValue==0) { + lastKnownValue = 1; + newEvent = new Event(); + newEvent.set(this, lastKnownValue, packet.PK_TIME*1000); + } else if(packet.PK_CURSOR!=index && lastKnownValue==1) { + lastKnownValue = 0; + newEvent = new Event(); + newEvent.set(this, lastKnownValue, packet.PK_TIME*1000); + } + + return newEvent; + } +} diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabDevice.java b/plugins/wintab/src/java/net/java/games/input/WinTabDevice.java new file mode 100644 index 0000000..261338a --- /dev/null +++ b/plugins/wintab/src/java/net/java/games/input/WinTabDevice.java @@ -0,0 +1,131 @@ +package net.java.games.input; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import net.java.games.input.Component.Identifier; + +public class WinTabDevice extends AbstractController { + private int deviceIndex; + private WinTabContext context; + private List eventList = new ArrayList(); + + private WinTabDevice(WinTabContext context, int index, String name, Component[] components) { + super(name, components, new Controller[0], new Rumbler[0]); + this.deviceIndex = index; + this.context = context; + } + + protected boolean getNextDeviceEvent(Event event) throws IOException { + if(eventList.size()>0) { + 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<components.length;i++) { + Event event = ((WinTabComponent)components[i]).processPacket(packet); + if(event!=null) { + eventList.add(event); + } + } + } + + public static WinTabDevice createDevice(WinTabContext context, int deviceIndex) { + String name = nGetName(deviceIndex); + ControllerEnvironment.logln("Device " + deviceIndex + ", name: " + name); + List componentsList = new ArrayList(); + + int[] axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.XAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("ZAxis not supported"); + } else { + ControllerEnvironment.logln("Xmin: " + axisDetails[0] + ", Xmax: " + axisDetails[1]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.XAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.YAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("YAxis not supported"); + } else { + ControllerEnvironment.logln("Ymin: " + axisDetails[0] + ", Ymax: " + axisDetails[1]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.YAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.ZAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("ZAxis not supported"); + } else { + ControllerEnvironment.logln("Zmin: " + axisDetails[0] + ", Zmax: " + axisDetails[1]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.ZAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.NPressureAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("NPressureAxis not supported"); + } else { + ControllerEnvironment.logln("NPressMin: " + axisDetails[0] + ", NPressMax: " + axisDetails[1]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.NPressureAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.TPressureAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("TPressureAxis not supported"); + } else { + ControllerEnvironment.logln("TPressureAxismin: " + axisDetails[0] + ", TPressureAxismax: " + axisDetails[1]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.TPressureAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.OrientationAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("OrientationAxis not supported"); + } else { + ControllerEnvironment.logln("OrientationAxis mins/maxs: " + axisDetails[0] + "," + axisDetails[1] + ", " + axisDetails[2] + "," + axisDetails[3] + ", " + axisDetails[4] + "," + axisDetails[5]); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.OrientationAxis, axisDetails)); + } + + axisDetails = nGetAxisDetails(deviceIndex, WinTabComponent.RotationAxis); + if(axisDetails.length==0) { + ControllerEnvironment.logln("RotationAxis not supported"); + } else { + ControllerEnvironment.logln("RotationAxis is supported (by the device, not by this plugin)"); + componentsList.addAll(WinTabComponent.createComponents(context, deviceIndex, WinTabComponent.RotationAxis, axisDetails)); + } + + String[] cursorNames = nGetCursorNames(deviceIndex); + componentsList.addAll(WinTabComponent.createCursors(context, deviceIndex, cursorNames)); + for(int i=0;i<cursorNames.length;i++) { + ControllerEnvironment.logln("Cursor " + i + "'s name: " + cursorNames[i]); + } + + int numberOfButtons = nGetMaxButtonCount(deviceIndex); + ControllerEnvironment.logln("Device has " + numberOfButtons + " buttons"); + componentsList.addAll(WinTabComponent.createButtons(context, deviceIndex, numberOfButtons)); + + Component[] components = (Component[])componentsList.toArray(new Component[0]); + + return new WinTabDevice(context, deviceIndex, name, components); + } + + private final static native String nGetName(int deviceIndex); + private final static native int[] nGetAxisDetails(int deviceIndex, int axisId); + private final static native String[] nGetCursorNames(int deviceIndex); + private final static native int nGetMaxButtonCount(int deviceIndex); +} diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabEnvironmentPlugin.java b/plugins/wintab/src/java/net/java/games/input/WinTabEnvironmentPlugin.java new file mode 100644 index 0000000..aa18f2b --- /dev/null +++ b/plugins/wintab/src/java/net/java/games/input/WinTabEnvironmentPlugin.java @@ -0,0 +1,69 @@ +package net.java.games.input; + +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.List; + +import net.java.games.util.plugins.Plugin; + +public class WinTabEnvironmentPlugin extends ControllerEnvironment implements Plugin { + static { + DefaultControllerEnvironment.loadLibrary("jinput-wintab"); + } + + private final Controller[] controllers; + private final List active_devices = new ArrayList(); + private final DummyWindow window; + private final WinTabContext winTabContext; + + /** Creates new DirectInputEnvironment */ + public WinTabEnvironmentPlugin() { + DummyWindow window = null; + WinTabContext winTabContext = null; + Controller[] controllers = new Controller[]{}; + try { + window = new DummyWindow(); + winTabContext = new WinTabContext(window); + try { + winTabContext.open(); + controllers = winTabContext.getControllers(); + } catch (Exception e) { + window.destroy(); + throw e; + } + } catch (Exception e) { + ControllerEnvironment.logln("Failed to enumerate devices: " + e.getMessage()); + e.printStackTrace(); + } + this.window = window; + this.controllers = controllers; + this.winTabContext = winTabContext; + AccessController.doPrivileged( + new PrivilegedAction() { + public final Object run() { + Runtime.getRuntime().addShutdownHook(new ShutdownHook()); + return null; + } + }); + } + + public Controller[] getControllers() { + return controllers; + } + + private final class ShutdownHook extends Thread { + public final void run() { + /* Release the devices to kill off active force feedback effects */ + for (int i = 0; i < active_devices.size(); i++) { + // TODO free the devices + } + //Close the context + winTabContext.close(); + /* We won't release the window since it is + * owned by the thread that created the environment. + */ + } + } +} diff --git a/plugins/wintab/src/java/net/java/games/input/WinTabPacket.java b/plugins/wintab/src/java/net/java/games/input/WinTabPacket.java new file mode 100644 index 0000000..28f1fd4 --- /dev/null +++ b/plugins/wintab/src/java/net/java/games/input/WinTabPacket.java @@ -0,0 +1,11 @@ +package net.java.games.input; + +public class WinTabPacket { + long PK_TIME; + int PK_X, PK_Y, PK_Z, PK_BUTTONS, PK_NORMAL_PRESSURE, PK_TANGENT_PRESSURE, PK_CURSOR; + int PK_ORIENTATION_ALT, PK_ORIENTATION_AZ, PK_ORIENTATION_TWIST; + + public WinTabPacket() { + + } +} diff --git a/plugins/wintab/src/native/build.xml b/plugins/wintab/src/native/build.xml new file mode 100644 index 0000000..152ef24 --- /dev/null +++ b/plugins/wintab/src/native/build.xml @@ -0,0 +1,70 @@ +<?xml version="1.0"?> + +<project name="JInput wintab port, Native code" basedir="." default="compile"> + <property environment="env"/> + <property name="wintabhome" location="${env.WINTAB_DIR}"/> + <property name="sdkhome" location="c:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2"/> + + <target name="compile_dir"> + <echo message="${compiledir}"/> + <echo message="wintab: ${wintabhome}"/> + <apply dir="${compiledir}" failonerror="true" executable="cl" dest="${compiledir}" skipemptyfilesets="true"> + <arg line="/Ox /Wp64 /W2 /nologo /c"/> + <arg value="/I${sdkhome}\include"/> + <arg value="/I${wintabhome}\include"/> + <arg value="/I${java.home}\..\include"/> + <arg value="/I${java.home}\..\include\win32"/> + <arg value="/I${commonhome}/src/native"/> + <arg value="/I.."/> + <srcfile/> + <fileset dir="${compiledir}" includes="*.c"/> + <mapper type="glob" from="*.c" to="*.obj"/> + </apply> + </target> + + <!-- <target name="link" unless="nolink">--> + <target name="link"> + <apply dir="." parallel="true" executable="cl" failonerror="true"> + <arg line="/LD /nologo"/> + <srcfile/> + <arg line="/Fe${dllname} /link"/> + <arg value="/LIBPATH:${java.home}\lib"/> + <arg value="/LIBPATH:${wintabhome}\lib\I386"/> + <arg value="/LIBPATH:${sdkhome}\lib"/> + <arg line="/DLL ${libs}"/> + <fileset dir="${commonhome}/src/native" includes="*.obj"/> + <fileset dir="." includes="*.obj"/> + <fileset dir="../../../windows/src/native" includes="*.obj"/> + </apply> + </target> + + <target name="clean"> + <delete> + <fileset dir="." includes="*.obj"/> + <fileset dir="." includes="*.dll"/> + </delete> + </target> + + <target name="compile"> + <property name="wintablibs" value="Kernel32.lib WINTAB32.LIB User32.lib"/> + <property name="commonhome" location="../../../common"/> + <property name="dllname" value="jinput-wintab.dll"/> + <antcall target="compile_dir"> + <param name="compiledir" location="${commonhome}/src/native"/> + </antcall> + <antcall target="compile_dir"> + <param name="compiledir" location="."/> + </antcall> + <antcall target="compile_dir"> + <param name="compiledir" location="../../../windows/src/native"/> + </antcall> + <!-- <uptodate property="nolink" targetfile="${dllname}"> + <srcfiles dir="." includes="*.obj"/> + </uptodate>--> + <antcall target="link"> + <param name="dllname" value="${dllname}"/> + <param name="libs" value="${wintablibs}"/> + </antcall> + </target> +</project> + 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 <windows.h> +#include <stdio.h> + +#include <jni.h> +#include "net_java_games_input_WinTabContext.h" +#include <wintab.h> +//#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 <pktdef.h> +#include <util.h> + +#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;i<numberRead;i++) { + jobject tempPacket = newJObject(env, "net/java/games/input/WinTabPacket", "()V"); + + (*env)->SetLongField(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 <windows.h> +#include <stdio.h> + +#include <jni.h> +#include "net_java_games_input_WinTabDevice.h" +#include "net_java_games_input_WinTabComponent.h" +#include "util.h" +#include <wintab.h> +#include <malloc.h> +#define PACKETDATA ( PK_X | PK_Y | PK_Z | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_ORIENTATION | PK_CURSOR ) +#define PACKETMODE 0 +#include <pktdef.h> + +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;i<numberCursorTypes;i++) { + WTInfo(WTI_CURSORS + i + firstCursorType, CSR_NAME, name); + nameString = (*env)->NewStringUTF(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;i<numberCursorTypes;i++) { + WTInfo(WTI_CURSORS + i + firstCursorType, CSR_BUTTONS, &buttonCount); + if(buttonCount>retval) { + retval = buttonCount; + } + } + + return (jint)retval; +} |