First commit of the wintab plugin

This commit is contained in:
endolf 2006-10-29 15:57:42 +00:00
parent f201cc526b
commit 1ef6081c1f
11 changed files with 875 additions and 0 deletions

76
plugins/wintab/build.xml Normal file
View file

@ -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>

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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;
}
}

View file

@ -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);
}

View file

@ -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.
*/
}
}
}

View file

@ -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() {
}
}

View file

@ -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>

View file

@ -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;
}

View file

@ -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;
}