Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* %W% %E%
*
* Copyright 2002 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/*****************************************************************************
* Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materails provided with the distribution.
*
* Neither the name Sun Microsystems, Inc. or the names of the contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind.
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANT OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMEN, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN") AND
* ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS
* A RESULT OF USING, MODIFYING OR DESTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES. HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OUR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed or intended for us in
* the design, construction, operation or maintenance of any nuclear facility
*
*****************************************************************************/
package net.java.games.input;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.Arrays;
/** Java wrapper for IDirectInputDevice
* @author martak
* @author elias
* @version 1.0
*/
final class IDirectInputDevice {
public final static int GUID_XAxis = 1;
public final static int GUID_YAxis = 2;
public final static int GUID_ZAxis = 3;
public final static int GUID_RxAxis = 4;
public final static int GUID_RyAxis = 5;
public final static int GUID_RzAxis = 6;
public final static int GUID_Slider = 7;
public final static int GUID_Button = 8;
public final static int GUID_Key = 9;
public final static int GUID_POV = 10;
public final static int GUID_Unknown = 11;
public final static int GUID_ConstantForce = 12;
public final static int GUID_RampForce = 13;
public final static int GUID_Square = 14;
public final static int GUID_Sine = 15;
public final static int GUID_Triangle = 16;
public final static int GUID_SawtoothUp = 17;
public final static int GUID_SawtoothDown = 18;
public final static int GUID_Spring = 19;
public final static int GUID_Damper = 20;
public final static int GUID_Inertia = 21;
public final static int GUID_Friction = 22;
public final static int GUID_CustomForce = 23;
public final static int DI8DEVTYPE_DEVICE = 0x11;
public final static int DI8DEVTYPE_MOUSE = 0x12;
public final static int DI8DEVTYPE_KEYBOARD = 0x13;
public final static int DI8DEVTYPE_JOYSTICK = 0x14;
public final static int DI8DEVTYPE_GAMEPAD = 0x15;
public final static int DI8DEVTYPE_DRIVING = 0x16;
public final static int DI8DEVTYPE_FLIGHT = 0x17;
public final static int DI8DEVTYPE_1STPERSON = 0x18;
public final static int DI8DEVTYPE_DEVICECTRL = 0x19;
public final static int DI8DEVTYPE_SCREENPOINTER = 0x1A;
public final static int DI8DEVTYPE_REMOTE = 0x1B;
public final static int DI8DEVTYPE_SUPPLEMENTAL = 0x1C;
public final static int DISCL_EXCLUSIVE = 0x00000001;
public final static int DISCL_NONEXCLUSIVE = 0x00000002;
public final static int DISCL_FOREGROUND = 0x00000004;
public final static int DISCL_BACKGROUND = 0x00000008;
public final static int DISCL_NOWINKEY = 0x00000010;
public final static int DIDFT_ALL = 0x00000000;
public final static int DIDFT_RELAXIS = 0x00000001;
public final static int DIDFT_ABSAXIS = 0x00000002;
public final static int DIDFT_AXIS = 0x00000003;
public final static int DIDFT_PSHBUTTON = 0x00000004;
public final static int DIDFT_TGLBUTTON = 0x00000008;
public final static int DIDFT_BUTTON = 0x0000000C;
public final static int DIDFT_POV = 0x00000010;
public final static int DIDFT_COLLECTION = 0x00000040;
public final static int DIDFT_NODATA = 0x00000080;
public final static int DIDFT_FFACTUATOR = 0x01000000;
public final static int DIDFT_FFEFFECTTRIGGER = 0x02000000;
public final static int DIDFT_OUTPUT = 0x10000000;
public final static int DIDFT_VENDORDEFINED = 0x04000000;
public final static int DIDFT_ALIAS = 0x08000000;
public final static int DIDFT_OPTIONAL = 0x80000000;
public final static int DIDFT_NOCOLLECTION = 0x00FFFF00;
public final static int DIDF_ABSAXIS = 0x00000001;
public final static int DIDF_RELAXIS = 0x00000002;
public final static int DI_OK = 0x00000000;
public final static int DI_NOEFFECT = 0x00000001;
public final static int DI_PROPNOEFFECT = 0x00000001;
public final static int DI_POLLEDDEVICE = 0x00000002;
public final static int DI_DOWNLOADSKIPPED = 0x00000003;
public final static int DI_EFFECTRESTARTED = 0x00000004;
public final static int DI_TRUNCATED = 0x00000008;
public final static int DI_SETTINGSNOTSAVED = 0x0000000B;
public final static int DI_TRUNCATEDANDRESTARTED = 0x0000000C;
public final static int DI_BUFFEROVERFLOW = 0x00000001;
public final static int DIERR_INPUTLOST = 0x8007001E;
public final static int DIERR_NOTACQUIRED = 0x8007001C;
public final static int DIERR_OTHERAPPHASPRIO = 0x80070005;
public final static int DIDOI_FFACTUATOR = 0x00000001;
public final static int DIDOI_FFEFFECTTRIGGER = 0x00000002;
public final static int DIDOI_POLLED = 0x00008000;
public final static int DIDOI_ASPECTPOSITION = 0x00000100;
public final static int DIDOI_ASPECTVELOCITY = 0x00000200;
public final static int DIDOI_ASPECTACCEL = 0x00000300;
public final static int DIDOI_ASPECTFORCE = 0x00000400;
public final static int DIDOI_ASPECTMASK = 0x00000F00;
public final static int DIDOI_GUIDISUSAGE = 0x00010000;
public final static int DIEFT_ALL = 0x00000000;
public final static int DIEFT_CONSTANTFORCE = 0x00000001;
public final static int DIEFT_RAMPFORCE = 0x00000002;
public final static int DIEFT_PERIODIC = 0x00000003;
public final static int DIEFT_CONDITION = 0x00000004;
public final static int DIEFT_CUSTOMFORCE = 0x00000005;
public final static int DIEFT_HARDWARE = 0x000000FF;
public final static int DIEFT_FFATTACK = 0x00000200;
public final static int DIEFT_FFFADE = 0x00000400;
public final static int DIEFT_SATURATION = 0x00000800;
public final static int DIEFT_POSNEGCOEFFICIENTS = 0x00001000;
public final static int DIEFT_POSNEGSATURATION = 0x00002000;
public final static int DIEFT_DEADBAND = 0x00004000;
public final static int DIEFT_STARTDELAY = 0x00008000;
public final static int DIEFF_OBJECTIDS = 0x00000001;
public final static int DIEFF_OBJECTOFFSETS = 0x00000002;
public final static int DIEFF_CARTESIAN = 0x00000010;
public final static int DIEFF_POLAR = 0x00000020;
public final static int DIEFF_SPHERICAL = 0x00000040;
public final static int DIEP_DURATION = 0x00000001;
public final static int DIEP_SAMPLEPERIOD = 0x00000002;
public final static int DIEP_GAIN = 0x00000004;
public final static int DIEP_TRIGGERBUTTON = 0x00000008;
public final static int DIEP_TRIGGERREPEATINTERVAL = 0x00000010;
public final static int DIEP_AXES = 0x00000020;
public final static int DIEP_DIRECTION = 0x00000040;
public final static int DIEP_ENVELOPE = 0x00000080;
public final static int DIEP_TYPESPECIFICPARAMS = 0x00000100;
public final static int DIEP_STARTDELAY = 0x00000200;
public final static int DIEP_ALLPARAMS_DX5 = 0x000001FF;
public final static int DIEP_ALLPARAMS = 0x000003FF;
public final static int DIEP_START = 0x20000000;
public final static int DIEP_NORESTART = 0x40000000;
public final static int DIEP_NODOWNLOAD = 0x80000000;
public final static int DIEB_NOTRIGGER = 0xFFFFFFFF;
public final static int INFINITE = 0xFFFFFFFF;
public final static int DI_DEGREES = 100;
public final static int DI_FFNOMINALMAX = 10000;
public final static int DI_SECONDS = 1000000;
public final static int DIPROPRANGE_NOMIN = 0x80000000;
public final static int DIPROPRANGE_NOMAX = 0x7FFFFFFF;
private final DummyWindow window;
private final long address;
private final int dev_type;
private final int dev_subtype;
private final String instance_name;
private final String product_name;
private final List objects = new ArrayList();
private final List effects = new ArrayList();
private final List rumblers = new ArrayList();
private final int[] device_state;
private final Map object_to_component = new HashMap();
private final boolean axes_in_relative_mode;
private boolean released;
private DataQueue queue;
private int button_counter;
private int current_format_offset;
public IDirectInputDevice(DummyWindow window, long address, byte[] instance_guid, byte[] product_guid, int dev_type, int dev_subtype, String instance_name, String product_name) throws IOException {
this.window = window;
this.address = address;
this.product_name = product_name;
this.instance_name = instance_name;
this.dev_type = dev_type;
this.dev_subtype = dev_subtype;
// Assume that the caller (native side) releases the device if setup fails
enumObjects();
try {
enumEffects();
createRumblers();
} catch (IOException e) {
DirectInputEnvironmentPlugin.log("Failed to create rumblers: " + e.getMessage());
}
/* Some DirectInput lamer-designer made the device state
* axis mode be per-device not per-axis, so I'll just
* get all axes as absolute and compensate for relative axes.
*
* Unless, of course, all axes are relative like a mouse device,
* in which case setting the DIDF_ABSAXIS flag will result in
* incorrect axis values returned from GetDeviceData for some
* obscure reason.
*/
boolean all_relative = true;
boolean has_axis = false;
for (int i = 0; i < objects.size(); i++) {
DIDeviceObject obj = (DIDeviceObject)objects.get(i);
if (obj.isAxis()) {
has_axis = true;
if (!obj.isRelative()) {
all_relative = false;
break;
}
}
}
this.axes_in_relative_mode = all_relative && has_axis;
int axis_mode = all_relative ? DIDF_RELAXIS : DIDF_ABSAXIS;
setDataFormat(axis_mode);
if (rumblers.size() > 0) {
try {
setCooperativeLevel(DISCL_BACKGROUND | DISCL_EXCLUSIVE);
} catch (IOException e) {
setCooperativeLevel(DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
}
} else
setCooperativeLevel(DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);
setBufferSize(AbstractController.EVENT_QUEUE_DEPTH);
acquire();
this.device_state = new int[objects.size()];
}
public final boolean areAxesRelative() {
return axes_in_relative_mode;
}
public final Rumbler[] getRumblers() {
return (Rumbler[])rumblers.toArray(new Rumbler[]{});
}
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*/)
return rumblers;
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 &&
(info.getDynamicParams() & DIEP_GAIN) != 0) {
rumblers.add(createPeriodicRumbler(axes, directions, info));
}
}
return rumblers;
}
private final Rumbler createPeriodicRumbler(DIDeviceObject[] axes, long[] directions, DIEffectInfo info) throws IOException {
int[] axis_ids = new int[axes.length];
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, 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;
private final DIDeviceObject lookupObjectByGUID(int guid_id) {
for (int i = 0; i < objects.size(); i++) {
DIDeviceObject object = (DIDeviceObject)objects.get(i);
if (guid_id == object.getGUIDType())
return object;
}
return null;
}
public final int getPollData(DIDeviceObject object) {
return device_state[object.getFormatOffset()];
}
public final DIDeviceObject mapEvent(DIDeviceObjectData event) {
/* Raw event format offsets (dwOfs member) is in bytes,
* but we're indexing into ints so we have to compensate
* for the int size (4 bytes)
*/
int format_offset = event.getFormatOffset()/4;
return (DIDeviceObject)objects.get(format_offset);
}
public final DIComponent mapObject(DIDeviceObject object) {
return (DIComponent)object_to_component.get(object);
}
public final void registerComponent(DIDeviceObject object, DIComponent component) {
object_to_component.put(object, component);
}
public final synchronized void pollAll() throws IOException {
checkReleased();
poll();
getDeviceState(device_state);
queue.compact();
getDeviceData(queue);
queue.flip();
}
public synchronized final boolean getNextEvent(DIDeviceObjectData data) {
DIDeviceObjectData next_event = (DIDeviceObjectData)queue.get();
if (next_event == null)
return false;
data.set(next_event);
return true;
}
private final void poll() throws IOException {
int res = nPoll(address);
if (res != DI_OK && res != DI_NOEFFECT) {
if (res == DIERR_NOTACQUIRED) {
acquire();
return;
}
throw new IOException("Failed to poll device (" + Integer.toHexString(res) + ")");
}
}
private final static native int nPoll(long address) throws IOException;
private final void acquire() throws IOException {
int res = nAcquire(address);
if (res != DI_OK && res != DIERR_OTHERAPPHASPRIO && res != DI_NOEFFECT)
throw new IOException("Failed to acquire device (" + Integer.toHexString(res) + ")");
}
private final static native int nAcquire(long address);
private final void unacquire() throws IOException {
int res = nUnacquire(address);
if (res != DI_OK && res != DI_NOEFFECT)
throw new IOException("Failed to unAcquire device (" + Integer.toHexString(res) + ")");
}
private final static native int nUnacquire(long address);
private final boolean getDeviceData(DataQueue queue) throws IOException {
int res = nGetDeviceData(address, 0, queue, queue.getElements(), queue.position(), queue.remaining());
if (res != DI_OK && res != DI_BUFFEROVERFLOW) {
if (res == DIERR_NOTACQUIRED) {
acquire();
return false;
}
throw new IOException("Failed to get device data (" + Integer.toHexString(res) + ")");
}
return true;
}
private final static native int nGetDeviceData(long address, int flags, DataQueue queue, Object[] queue_elements, int position, int remaining);
private final void getDeviceState(int[] device_state) throws IOException {
int res = nGetDeviceState(address, device_state);
if (res != DI_OK) {
if (res == DIERR_NOTACQUIRED) {
Arrays.fill(device_state, 0);
acquire();
return;
}
throw new IOException("Failed to get device state (" + Integer.toHexString(res) + ")");
}
}
private final static native int nGetDeviceState(long address, int[] device_state);
/* Set a custom data format that maps each object's data into an int[]
array with the same index as in the objects List */
private final void setDataFormat(int flags) throws IOException {
DIDeviceObject[] device_objects = new DIDeviceObject[objects.size()];
objects.toArray(device_objects);
int res = nSetDataFormat(address, flags, device_objects);
if (res != DI_OK)
throw new IOException("Failed to set data format (" + Integer.toHexString(res) + ")");
}
private final static native int nSetDataFormat(long address, int flags, DIDeviceObject[] device_objects);
public final String getProductName() {
return product_name;
}
public final int getType() {
return dev_type;
}
public final List getObjects() {
return objects;
}
private final void enumEffects() throws IOException {
int res = nEnumEffects(address, DIEFT_ALL);
if (res != DI_OK)
throw new IOException("Failed to enumerate effects (" + Integer.toHexString(res) + ")");
}
private final native int nEnumEffects(long address, int flags);
/* Called from native side from nEnumEffects */
private final void addEffect(byte[] guid, int guid_id, int effect_type, int static_params, int dynamic_params, String name) {
effects.add(new DIEffectInfo(this, guid, guid_id, effect_type, static_params, dynamic_params, name));
}
private final void enumObjects() throws IOException {
int res = nEnumObjects(address, DIDFT_BUTTON | DIDFT_AXIS | DIDFT_POV);
if (res != DI_OK)
throw new IOException("Failed to enumerate objects (" + Integer.toHexString(res) + ")");
}
private final native int nEnumObjects(long address, int flags);
public final synchronized long[] getRangeProperty(int object_identifier) throws IOException {
checkReleased();
long[] range = new long[2];
int res = nGetRangeProperty(address, object_identifier, range);
if (res != DI_OK)
throw new IOException("Failed to get object range (" + res + ")");
return range;
}
private final static native int nGetRangeProperty(long address, int object_id, long[] range);
public final synchronized int getDeadzoneProperty(int object_identifier) throws IOException {
checkReleased();
return nGetDeadzoneProperty(address, object_identifier);
}
private final static native int nGetDeadzoneProperty(long address, int object_id) throws IOException;
/* Called from native side from nEnumObjects */
private final void addObject(byte[] guid, int guid_type, int identifier, int type, int instance, int flags, String name) throws IOException {
Component.Identifier id = getIdentifier(guid_type, type, instance);
int format_offset = current_format_offset++;
DIDeviceObject obj = new DIDeviceObject(this, id, guid, guid_type, identifier, type, instance, flags, name, format_offset);
objects.add(obj);
}
private final static Component.Identifier.Key getKeyIdentifier(int key_instance) {
return DIIdentifierMap.getKeyIdentifier(key_instance);
}
private final Component.Identifier.Button getNextButtonIdentifier() {
int button_id = button_counter++;
return DIIdentifierMap.getButtonIdentifier(button_id);
}
private final Component.Identifier getIdentifier(int guid_type, int type, int instance) {
switch (guid_type) {
case IDirectInputDevice.GUID_XAxis:
return Component.Identifier.Axis.X;
case IDirectInputDevice.GUID_YAxis:
return Component.Identifier.Axis.Y;
case IDirectInputDevice.GUID_ZAxis:
return Component.Identifier.Axis.Z;
case IDirectInputDevice.GUID_RxAxis:
return Component.Identifier.Axis.RX;
case IDirectInputDevice.GUID_RyAxis:
return Component.Identifier.Axis.RY;
case IDirectInputDevice.GUID_RzAxis:
return Component.Identifier.Axis.RZ;
case IDirectInputDevice.GUID_Slider:
return Component.Identifier.Axis.SLIDER;
case IDirectInputDevice.GUID_POV:
return Component.Identifier.Axis.POV;
case IDirectInputDevice.GUID_Key:
return getKeyIdentifier(instance);
case IDirectInputDevice.GUID_Button:
return getNextButtonIdentifier();
default:
return Component.Identifier.Axis.UNKNOWN;
}
}
public final synchronized void setBufferSize(int size) throws IOException {
checkReleased();
unacquire();
int res = nSetBufferSize(address, size);
if (res != DI_OK && res != DI_PROPNOEFFECT && res != DI_POLLEDDEVICE)
throw new IOException("Failed to set buffer size (" + Integer.toHexString(res) + ")");
queue = new DataQueue(size, DIDeviceObjectData.class);
queue.position(queue.limit());
acquire();
}
private final static native int nSetBufferSize(long address, int size);
public final synchronized void setCooperativeLevel(int flags) throws IOException {
checkReleased();
int res = nSetCooperativeLevel(address, window.getHwnd(), flags);
if (res != DI_OK)
throw new IOException("Failed to set cooperative level (" + Integer.toHexString(res) + ")");
}
private final static native int nSetCooperativeLevel(long address, long hwnd_address, int flags);
public synchronized final void release() {
if (!released) {
released = true;
for (int i = 0; i < rumblers.size(); i++) {
IDirectInputEffect effect = (IDirectInputEffect)rumblers.get(i);
effect.release();
}
nRelease(address);
}
}
private final static native void nRelease(long address);
private final void checkReleased() throws IOException {
if (released)
throw new IOException("Device is released");
}
protected void finalize() {
release();
}
}