mirror of
https://github.com/shadowfacts/jinput-arm64.git
synced 2026-02-05 07:14:53 +01:00
First commit of the wintab plugin
This commit is contained in:
parent
f201cc526b
commit
1ef6081c1f
76
plugins/wintab/build.xml
Normal file
76
plugins/wintab/build.xml
Normal 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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
131
plugins/wintab/src/java/net/java/games/input/WinTabDevice.java
Normal file
131
plugins/wintab/src/java/net/java/games/input/WinTabDevice.java
Normal 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);
|
||||
}
|
||||
|
|
@ -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.
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
|
||||
}
|
||||
}
|
||||
70
plugins/wintab/src/native/build.xml
Normal file
70
plugins/wintab/src/native/build.xml
Normal 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>
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
107
plugins/wintab/src/native/net_java_games_input_WinTabDevice.c
Normal file
107
plugins/wintab/src/native/net_java_games_input_WinTabDevice.c
Normal 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;
|
||||
}
|
||||
Loading…
Reference in a new issue