aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--coreAPI/src/java/net/java/games/input/DefaultControllerEnvironment.java4
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxDeviceTask.java62
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxDeviceThread.java91
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxEnvironmentPlugin.java5
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxEventDevice.java20
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxForceFeedbackEffect.java54
-rw-r--r--plugins/linux/src/java/net/java/games/input/LinuxRumbleFF.java2
-rw-r--r--plugins/windows/src/java/net/java/games/input/DirectInputEnvironmentPlugin.java10
-rw-r--r--plugins/windows/src/java/net/java/games/input/IDirectInputDevice.java10
9 files changed, 225 insertions, 33 deletions
diff --git a/coreAPI/src/java/net/java/games/input/DefaultControllerEnvironment.java b/coreAPI/src/java/net/java/games/input/DefaultControllerEnvironment.java
index 3ce2b2e..39db61a 100644
--- a/coreAPI/src/java/net/java/games/input/DefaultControllerEnvironment.java
+++ b/coreAPI/src/java/net/java/games/input/DefaultControllerEnvironment.java
@@ -123,13 +123,13 @@ class DefaultControllerEnvironment extends ControllerEnvironment {
pluginClasses = pluginClasses + " net.java.games.input.OSXEnvironmentPlugin";
} else if(osName.equals("Windows 98") || osName.equals("Windows 2000") || osName.equals("Windows XP")) {
pluginClasses = pluginClasses + " net.java.games.input.DirectInputEnvironmentPlugin";
- pluginClasses = pluginClasses + " net.java.games.input.RawInputEnvironmentPlugin";
+// pluginClasses = pluginClasses + " net.java.games.input.RawInputEnvironmentPlugin";
} else if (osName.startsWith("Windows")) {
System.out.println("WARNING: Found unknown Windows version: " + osName);
System.out.println("Attempting to use default windows plug-in.");
System.out.flush();
pluginClasses = pluginClasses + " net.java.games.input.DirectInputEnvironmentPlugin";
- pluginClasses = pluginClasses + " net.java.games.input.RawInputEnvironmentPlugin";
+// pluginClasses = pluginClasses + " net.java.games.input.RawInputEnvironmentPlugin";
} else {
System.out.println("Trying to use default plugin, OS name " + osName +" not recognised");
}
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxDeviceTask.java b/plugins/linux/src/java/net/java/games/input/LinuxDeviceTask.java
new file mode 100644
index 0000000..3dbdeda
--- /dev/null
+++ b/plugins/linux/src/java/net/java/games/input/LinuxDeviceTask.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (C) 2003 Jeremy Booth ([email protected])
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * The name of the author may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ */
+package net.java.games.input;
+
+import java.io.IOException;
+
+abstract class LinuxDeviceTask {
+ public final static int INPROGRESS = 1;
+ public final static int COMPLETED = 2;
+ public final static int FAILED = 3;
+
+ private Object result;
+ private IOException exception;
+ private int state = INPROGRESS;
+
+ public final void doExecute() {
+ try {
+ result = execute();
+ state = COMPLETED;
+ } catch (IOException e) {
+ exception = e;
+ state = FAILED;
+ }
+ }
+
+ public final IOException getException() {
+ return exception;
+ }
+
+ public final Object getResult() {
+ return result;
+ }
+
+ public final int getState() {
+ return state;
+ }
+
+ protected abstract Object execute() throws IOException;
+}
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxDeviceThread.java b/plugins/linux/src/java/net/java/games/input/LinuxDeviceThread.java
new file mode 100644
index 0000000..62d1849
--- /dev/null
+++ b/plugins/linux/src/java/net/java/games/input/LinuxDeviceThread.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2003 Jeremy Booth ([email protected])
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. Redistributions in binary
+ * form must reproduce the above copyright notice, this list of conditions and
+ * the following disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * The name of the author may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
+ */
+package net.java.games.input;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * Linux doesn't have proper support for force feedback
+ * from different threads since it relies on PIDs
+ * to determine ownership of a particular effect slot.
+ * Therefore we have to hack around this by
+ * making sure everything related to FF
+ * (including the final device close that performs
+ * and implicit deletion of all the process' effects)
+ * is run on a single thread.
+ */
+final class LinuxDeviceThread extends Thread {
+ private final List tasks = new ArrayList();
+
+ public LinuxDeviceThread() {
+ setDaemon(true);
+ start();
+ }
+
+ public synchronized final void run() {
+ while (true) {
+ if (!tasks.isEmpty()) {
+ LinuxDeviceTask task = (LinuxDeviceTask)tasks.remove(0);
+ task.doExecute();
+ synchronized (task) {
+ task.notify();
+ }
+ } else {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ public final Object execute(LinuxDeviceTask task) throws IOException {
+ synchronized (this) {
+ tasks.add(task);
+ notify();
+ }
+ synchronized (task) {
+ while (task.getState() == LinuxDeviceTask.INPROGRESS) {
+ try {
+ task.wait();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ }
+ switch (task.getState()) {
+ case LinuxDeviceTask.COMPLETED:
+ return task.getResult();
+ case LinuxDeviceTask.FAILED:
+ throw task.getException();
+ default:
+ throw new RuntimeException("Invalid task state: " + task.getState());
+ }
+ }
+}
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxEnvironmentPlugin.java b/plugins/linux/src/java/net/java/games/input/LinuxEnvironmentPlugin.java
index 628ee04..d6afb96 100644
--- a/plugins/linux/src/java/net/java/games/input/LinuxEnvironmentPlugin.java
+++ b/plugins/linux/src/java/net/java/games/input/LinuxEnvironmentPlugin.java
@@ -41,6 +41,7 @@ import java.security.PrivilegedAction;
public final class LinuxEnvironmentPlugin extends ControllerEnvironment implements Plugin {
private final Controller[] controllers;
private final List devices = new ArrayList();
+ private final static LinuxDeviceThread device_thread = new LinuxDeviceThread();
static {
AccessController.doPrivileged(
@@ -52,6 +53,10 @@ public final class LinuxEnvironmentPlugin extends ControllerEnvironment implemen
});
}
+ public final static Object execute(LinuxDeviceTask task) throws IOException {
+ return device_thread.execute(task);
+ }
+
public LinuxEnvironmentPlugin() {
this.controllers = enumerateControllers();
System.out.println("Linux plugin claims to have found " + controllers.length + " controllers");
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxEventDevice.java b/plugins/linux/src/java/net/java/games/input/LinuxEventDevice.java
index f17e05d..bcd941a 100644
--- a/plugins/linux/src/java/net/java/games/input/LinuxEventDevice.java
+++ b/plugins/linux/src/java/net/java/games/input/LinuxEventDevice.java
@@ -369,20 +369,16 @@ final class LinuxEventDevice implements LinuxDevice {
}
private final static native String nGetName(long fd) throws IOException;
- public final synchronized void close() throws IOException {
- if (!closed) {
- try {
- if (rumblers != null)
- for (int i = 0; i < rumblers.length; i++) {
- rumblers[i].rumble(0);
- // erasing effects seems to be unsupported on logitech devices
- //rumblers[i].erase();
- }
- } finally {
- closed = true;
+ public synchronized final void close() throws IOException {
+ if (closed)
+ return;
+ closed = true;
+ LinuxEnvironmentPlugin.execute(new LinuxDeviceTask() {
+ protected final Object execute() throws IOException {
nClose(fd);
+ return null;
}
- }
+ });
}
private final static native void nClose(long fd) throws IOException;
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxForceFeedbackEffect.java b/plugins/linux/src/java/net/java/games/input/LinuxForceFeedbackEffect.java
index 2e3a0e7..528cbff 100644
--- a/plugins/linux/src/java/net/java/games/input/LinuxForceFeedbackEffect.java
+++ b/plugins/linux/src/java/net/java/games/input/LinuxForceFeedbackEffect.java
@@ -33,39 +33,42 @@ import java.io.IOException;
abstract class LinuxForceFeedbackEffect implements Rumbler {
private final LinuxEventDevice device;
private final int ff_id;
+ private final WriteTask write_task = new WriteTask();
+ private final UploadTask upload_task = new UploadTask();
public LinuxForceFeedbackEffect(LinuxEventDevice device) throws IOException {
this.device = device;
- this.ff_id = upload(-1, 0);
+ this.ff_id = upload_task.doUpload(-1, 0);
}
protected abstract int upload(int id, float intensity) throws IOException;
- private final void write(int value) throws IOException {
- device.writeEvent(NativeDefinitions.EV_FF, ff_id, value);
- }
-
protected final LinuxEventDevice getDevice() {
return device;
}
- public final void rumble(float intensity) {
+ public synchronized final void rumble(float intensity) {
try {
if (intensity > 0) {
- upload(ff_id, intensity);
- write(1);
+ upload_task.doUpload(ff_id, intensity);
+ write_task.write(1);
} else {
- write(0);
+ write_task.write(0);
}
} catch (IOException e) {
ControllerEnvironment.logln("Failed to rumble: " + e);
}
}
+ /*
+ * Erase doesn't seem to be implemented on Logitech joysticks,
+ * so we'll rely on the kernel cleaning up on device close
+ */
+/*
public final void erase() throws IOException {
device.eraseEffect(ff_id);
}
-
+*/
public final String getAxisName() {
return null;
}
@@ -73,4 +76,35 @@ abstract class LinuxForceFeedbackEffect implements Rumbler {
public final Component.Identifier getAxisIdentifier() {
return null;
}
+
+ private final class UploadTask extends LinuxDeviceTask {
+ private int id;
+ private float intensity;
+
+ public final int doUpload(int id, float intensity) throws IOException {
+ this.id = id;
+ this.intensity = intensity;
+ LinuxEnvironmentPlugin.execute(this);
+ return this.id;
+ }
+
+ protected final Object execute() throws IOException {
+ this.id = upload(id, intensity);
+ return null;
+ }
+ }
+
+ private final class WriteTask extends LinuxDeviceTask {
+ private int value;
+
+ public final void write(int value) throws IOException {
+ this.value = value;
+ LinuxEnvironmentPlugin.execute(this);
+ }
+
+ protected final Object execute() throws IOException {
+ device.writeEvent(NativeDefinitions.EV_FF, ff_id, value);
+ return null;
+ }
+ }
}
diff --git a/plugins/linux/src/java/net/java/games/input/LinuxRumbleFF.java b/plugins/linux/src/java/net/java/games/input/LinuxRumbleFF.java
index e76bd31..578793a 100644
--- a/plugins/linux/src/java/net/java/games/input/LinuxRumbleFF.java
+++ b/plugins/linux/src/java/net/java/games/input/LinuxRumbleFF.java
@@ -49,6 +49,6 @@ final class LinuxRumbleFF extends LinuxForceFeedbackEffect {
weak_magnitude = (int)(0xc000*intensity);
}
- return getDevice().uploadRumbleEffect(id, 0, 0, 0, 0, 0, strong_magnitude, weak_magnitude);
+ return getDevice().uploadRumbleEffect(id, 0, 0, 0, -1, 0, strong_magnitude, weak_magnitude);
}
}
diff --git a/plugins/windows/src/java/net/java/games/input/DirectInputEnvironmentPlugin.java b/plugins/windows/src/java/net/java/games/input/DirectInputEnvironmentPlugin.java
index 46c9b7d..a7fa563 100644
--- a/plugins/windows/src/java/net/java/games/input/DirectInputEnvironmentPlugin.java
+++ b/plugins/windows/src/java/net/java/games/input/DirectInputEnvironmentPlugin.java
@@ -140,12 +140,16 @@ public final class DirectInputEnvironmentPlugin extends ControllerEnvironment im
return createMouseFromDevice(device);
case IDirectInputDevice.DI8DEVTYPE_KEYBOARD:
return createKeyboardFromDevice(device);
- case IDirectInputDevice.DI8DEVTYPE_JOYSTICK:
- return createControllerFromDevice(device, Controller.Type.STICK);
case IDirectInputDevice.DI8DEVTYPE_GAMEPAD:
return createControllerFromDevice(device, Controller.Type.GAMEPAD);
+ case IDirectInputDevice.DI8DEVTYPE_DRIVING:
+ return createControllerFromDevice(device, Controller.Type.WHEEL);
+ case IDirectInputDevice.DI8DEVTYPE_FLIGHT:
+ /* Fall through */
+ case IDirectInputDevice.DI8DEVTYPE_JOYSTICK:
+ /* Fall through */
default:
- return null;
+ return createControllerFromDevice(device, Controller.Type.STICK);
}
}
diff --git a/plugins/windows/src/java/net/java/games/input/IDirectInputDevice.java b/plugins/windows/src/java/net/java/games/input/IDirectInputDevice.java
index ef061cd..2e3e22f 100644
--- a/plugins/windows/src/java/net/java/games/input/IDirectInputDevice.java
+++ b/plugins/windows/src/java/net/java/games/input/IDirectInputDevice.java
@@ -250,11 +250,11 @@ final class IDirectInputDevice {
private final List createRumblers() throws IOException {
DIDeviceObject x_axis = lookupObjectByGUID(GUID_XAxis);
- DIDeviceObject y_axis = lookupObjectByGUID(GUID_YAxis);
- if(x_axis == null || y_axis == null)
+// DIDeviceObject y_axis = lookupObjectByGUID(GUID_YAxis);
+ if(x_axis == null/* || y_axis == null*/)
return rumblers;
- DIDeviceObject[] axes = {x_axis, y_axis};
- long[] directions = {0, 0};
+ DIDeviceObject[] axes = {x_axis/*, y_axis*/};
+ long[] directions = {0/*, 0*/};
for (int i = 0; i < effects.size(); i++) {
DIEffectInfo info = (DIEffectInfo)effects.get(i);
if ((info.getEffectType() & 0xff) == DIEFT_PERIODIC &&
@@ -270,7 +270,7 @@ final class IDirectInputDevice {
for (int i = 0; i < axis_ids.length; i++) {
axis_ids[i] = axes[i].getDIIdentifier();
}
- long effect_address = nCreatePeriodicEffect(address, info.getGUID(), DIEFF_CARTESIAN | DIEFF_OBJECTIDS, INFINITE, 0, 0, DIEB_NOTRIGGER, 0, axis_ids, directions, 0, 0, 0, 0, DI_FFNOMINALMAX, 0, 0, 50000, 0);
+ long effect_address = nCreatePeriodicEffect(address, info.getGUID(), DIEFF_CARTESIAN | DIEFF_OBJECTIDS, INFINITE, 0, DI_FFNOMINALMAX, DIEB_NOTRIGGER, 0, axis_ids, directions, 0, 0, 0, 0, DI_FFNOMINALMAX, 0, 0, 50000, 0);
return new IDirectInputEffect(effect_address, info);
}
private final static native long nCreatePeriodicEffect(long address, byte[] effect_guid, int flags, int duration, int sample_period, int gain, int trigger_button, int trigger_repeat_interval, int[] axis_ids, long[] directions, int envelope_attack_level, int envelope_attack_time, int envelope_fade_level, int envelope_fade_time, int periodic_magnitude, int periodic_offset, int periodic_phase, int periodic_period, int start_delay) throws IOException;