From c6a3dffe69834c25788c7dcef5e61360cb93e3c3 Mon Sep 17 00:00:00 2001 From: endolf Date: Mon, 1 Dec 2003 23:42:30 +0000 Subject: Initial rumbler support git-svn-id: file:///home/sven/projects/JOGL/git-svn/svn-server-sync/jinput/trunk@63 e343933a-64c8-49c5-92b1-88f2ce3e89e8 --- .../net/java/games/input/DirectInputDevice.java | 20 +++ .../net/java/games/input/DirectInputRumbler.java | 31 ++++ plugins/DX8/src/native/input.cpp | 159 +++++++++++++++++++-- 3 files changed, 198 insertions(+), 12 deletions(-) create mode 100644 plugins/DX8/src/java/net/java/games/input/DirectInputRumbler.java (limited to 'plugins/DX8/src') diff --git a/plugins/DX8/src/java/net/java/games/input/DirectInputDevice.java b/plugins/DX8/src/java/net/java/games/input/DirectInputDevice.java index f31c66e..993ab93 100644 --- a/plugins/DX8/src/java/net/java/games/input/DirectInputDevice.java +++ b/plugins/DX8/src/java/net/java/games/input/DirectInputDevice.java @@ -86,6 +86,9 @@ class DirectInputDevice extends AbstractController { * @see DirectInputAxis for a breakdown of this structure */ int[] data = new int[32]; + + /** Array list of rumblers */ + private ArrayList rumblerList = new ArrayList(); /** * Private constructor @@ -150,6 +153,16 @@ class DirectInputDevice extends AbstractController { list.add(DirectInputAxis.createAxis(this, id, didft, name)); } + /** + * Callback called by enumDevice to add a rumbler + * + * @param effect the natie effect id + * @param axisID The axis ID + */ + private void addRumbler(long effect, Axis.Identifier axisID) { + rumblerList.add(new DirectInputRumbler(this, effect, axisID)); + } + /** Polls axes for data. Returns false if the controller is no longer valid. * Polling reflects the current state of the device when polled, and is * unbuffered. @@ -174,6 +187,13 @@ class DirectInputDevice extends AbstractController { return 0; } + /** + * Returns the rumbler array + */ + public Rumbler[] getRumblers() { + return (Rumbler[]) rumblerList.toArray(new Rumbler[0]); + } + /** * Polls the device; native method. The data from the poll is stored in * the data array. diff --git a/plugins/DX8/src/java/net/java/games/input/DirectInputRumbler.java b/plugins/DX8/src/java/net/java/games/input/DirectInputRumbler.java new file mode 100644 index 0000000..de04724 --- /dev/null +++ b/plugins/DX8/src/java/net/java/games/input/DirectInputRumbler.java @@ -0,0 +1,31 @@ +/* + * DirectInputRumbler.java + * + * Created on 01 December 2003, 21:39 + */ + +package net.java.games.input; + +/** + * + * @author Jeremy + */ +public class DirectInputRumbler implements net.java.games.input.Rumbler { + + private DirectInputDevice device; + private long effect; + private Axis.Identifier axisID; + + /** Creates a new instance of DirectInputRumbler */ + public DirectInputRumbler(DirectInputDevice device, long effect, Axis.Identifier axisID) { + this.device = device; + this.effect = effect; + this.axisID = axisID; + } + + public void rumble(float intensity) { + setRumble(effect, intensity); + } + + private native void setRumble(long effect, float intensity); +} diff --git a/plugins/DX8/src/native/input.cpp b/plugins/DX8/src/native/input.cpp index b667f1d..9fe577b 100644 --- a/plugins/DX8/src/native/input.cpp +++ b/plugins/DX8/src/native/input.cpp @@ -29,6 +29,7 @@ jclass CLASS_DirectInputKeyboard = NULL; jclass CLASS_DirectInputMouse = NULL; jmethodID MID_AddDevice = NULL; jmethodID MID_AddAxis = NULL; +jmethodID MID_AddRumbler = NULL; jmethodID MID_RenameKey = NULL; jmethodID MID_RenameAxis = NULL; jfieldID FID_X = NULL; @@ -261,6 +262,11 @@ BOOL InitIDs(JNIEnv* env) { if (MID_AddAxis == NULL) { return FALSE; } + MID_AddRumbler = env->GetMethodID(CLASS_DirectInputDevice, "addRumbler", + "(JLnet/java/games/input/Axis$Identifier;)V"); + if (MID_AddRumbler == NULL) { + return FALSE; + } CLASS_DirectInputKeyboard = env->FindClass("net/java/games/input/DirectInputKeyboard"); if (CLASS_DirectInputKeyboard == NULL) { @@ -359,6 +365,19 @@ Java_net_java_games_input_DirectInputEnvironmentPlugin_directInputCreate return (jlong)(long)lpDirectInput; } +BOOL CALLBACK CountFFAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, + VOID* pContext ) +{ + DWORD* pdwNumForceFeedbackAxis = (DWORD*) pContext; + + if( (pdidoi->dwFlags & DIDOI_FFACTUATOR) != 0 ) { + //printf("%s is ff enabled\n", pdidoi->tszName); + (*pdwNumForceFeedbackAxis)++; + } + + return DIENUM_CONTINUE; +} + /* * Enumeration callback for devices * @@ -396,6 +415,14 @@ BOOL CALLBACK EnumDeviceCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) } */ + //find out if this device is ff enabled + DWORD numForceFeedbackAxis = 0; + res = lpDevice->EnumObjects( CountFFAxesCallback, + (VOID*)&numForceFeedbackAxis, DIDFT_AXIS ); + if(FAILED(res)) { + PrintDIError("getting ff devices", res); + } + // Set the data format LPCDIDATAFORMAT lpDataFormat; DWORD category = GET_DIDEVICE_TYPE(lpddi->dwDevType)&0xFF; @@ -417,10 +444,10 @@ BOOL CALLBACK EnumDeviceCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) if (FAILED( res = lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipropdw.diph))) { - PrintDIError("SetProperty", res); - lpDevice->Release(); - return DIENUM_STOP; - } + PrintDIError("SetProperty", res); + lpDevice->Release(); + return DIENUM_STOP; + } break; case DI8DEVTYPE_JOYSTICK: default: @@ -435,13 +462,23 @@ BOOL CALLBACK EnumDeviceCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef) return DIENUM_STOP; } - // Set the cooperative level - if(FAILED(res = lpDevice->SetCooperativeLevel(hwndDummy, - DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))){ - PrintDIError("SetCooperativeLevel", res); - lpDevice->Release(); - return DIENUM_STOP; - } + if(numForceFeedbackAxis>0) { + // Set the cooperative level + if(FAILED(res = lpDevice->SetCooperativeLevel(hwndDummy, + DISCL_EXCLUSIVE | DISCL_BACKGROUND))){ + PrintDIError("SetCooperativeLevel", res); + lpDevice->Release(); + return DIENUM_STOP; + } + } else { + // Set the cooperative level + if(FAILED(res = lpDevice->SetCooperativeLevel(hwndDummy, + DISCL_NONEXCLUSIVE | DISCL_BACKGROUND))){ + PrintDIError("SetCooperativeLevel", res); + lpDevice->Release(); + return DIENUM_STOP; + } + } // get polling DIDEVCAPS didc; @@ -567,6 +604,8 @@ BOOL CALLBACK EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, jobject obj = pData->obj; jobject list = pData->list; jobject identifier = NULL; + char ffEnabled = 0; + HRESULT res; if (lpddoi->guidType == GUID_XAxis) { identifier = env->GetStaticObjectField(CLASS_AxisIdentifier, FID_X); @@ -606,15 +645,111 @@ BOOL CALLBACK EnumObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, res=lpDevice->SetProperty(DIPROP_RANGE,&joy_axis_range.diph))){ PrintDIError("SetProperty", res); } + + //check if this axis is ff enabled + if( (lpddoi->dwFlags & DIDOI_FFACTUATOR) != 0 ) { + //printf("%s is ff enabled\n", lpddoi->tszName); + ffEnabled = 1; + } } - jint didft = (jint)lpddoi->dwType; + + jint didft = (jint)lpddoi->dwType; jstring name = env->NewStringUTF(lpddoi->tszName); // Add the axis into our list env->CallVoidMethod(obj, MID_AddAxis, list, identifier, didft, name); + + if(ffEnabled) { + // This application needs only one effect: Applying raw forces. + DWORD rgdwAxes; + LONG rglDirection = 0; + if(lpddoi->guidType == GUID_XAxis) { + //printf("effect is in the x axis\n"); + rgdwAxes = DIJOFS_X; + } else if(lpddoi->guidType == GUID_YAxis) { + //printf("effect is in the y axis\n"); + rgdwAxes = DIJOFS_Y; + } + + DICONSTANTFORCE cf = { DI_FFNOMINALMAX }; + + DIEFFECT eff; + ZeroMemory( &eff, sizeof(eff) ); + eff.dwSize = sizeof(DIEFFECT); + eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS; + eff.dwDuration = INFINITE; + eff.dwSamplePeriod = 0; + eff.dwGain = DI_FFNOMINALMAX; + eff.dwTriggerButton = DIEB_NOTRIGGER; + eff.dwTriggerRepeatInterval = 0; + eff.cAxes = 1; + eff.rgdwAxes = &rgdwAxes; + eff.rglDirection = &rglDirection; + eff.lpEnvelope = 0; + eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &cf; + eff.dwStartDelay = 0; + cf.lMagnitude = (long) (0); + + LPDIRECTINPUTEFFECT g_pEffect; + // Create the prepared effect + if( FAILED( res = lpDevice->CreateEffect( GUID_ConstantForce, + &eff, &g_pEffect, NULL ) ) ) + { + PrintDIError("Create effect", res); + return res; + } + + env->CallVoidMethod(obj, MID_AddRumbler, (jlong)(long)g_pEffect, identifier); + } return DIENUM_CONTINUE; } +/* + * Class: org_java_games_input_DirectInputRumbler + * Method setRumble + * Signature (JF)Z + */ +extern "C" JNIEXPORT jboolean JNICALL +Java_net_java_games_input_DirectInputRumbler_setRumble + (JNIEnv *env, jobject obj, jlong effect, jfloat value) +{ + LPDIRECTINPUTEFFECT g_pEffect = (LPDIRECTINPUTEFFECT)(long)effect; + float force = (float)value; + HRESULT hr; + + DICONSTANTFORCE cf = { DI_FFNOMINALMAX }; + + DIEFFECT eff; + ZeroMemory( &eff, sizeof(eff) ); + eff.dwSize = sizeof(DIEFFECT); + eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE); + eff.lpvTypeSpecificParams = &cf; + cf.lMagnitude = (long) (((float)DI_FFNOMINALMAX)*force); + + //printf("force: %f, mag: %d\n", force, cf.lMagnitude); + + hr = g_pEffect->SetParameters( &eff, DIEP_TYPESPECIFICPARAMS ); + if (FAILED(hr)) { + PrintDIError("set parameters", hr); + return hr; + } + + if(force!=0) { + hr = g_pEffect->Start(1,0); + if (FAILED(hr)) { + PrintDIError("start", hr); + return hr; + } + } else { + hr = g_pEffect->Stop(); + if (FAILED(hr)) { + PrintDIError("stop", hr); + return hr; + } + } +} + /* * Class: org_java_games_input_DirectInputDevice * Method: enumObjects -- cgit v1.2.3