/* * Copyright (c) 2002 Lightweight Java Game Library Project * All rights reserved. * * 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. * * * Neither the name of 'Light Weight Java Game Library' nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "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 COPYRIGHT OWNER OR * CONTRIBUTORS 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. */ /** * $Id$ * * Win32 controller handling. * * @author Brian Matzon * @version $Revision$ */ #define WIN32_LEAN_AND_MEAN #include "org_lwjgl_input_Controller.h" #include #undef DIRECTINPUT_VERSION #define DIRECTINPUT_VERSION 0x0500 #include #define AXISMAX 1000 // Maxmimum range to which we'll gauge the swing #define AXISMIN -1000 // Minimum range to which we'll gauge the swing extern HWND hwnd; // Handle to window IDirectInput* lpDI; // DI instance IDirectInputDevice2* lpDIDevice; // DI Device instance DIJOYSTATE2 js; // State of Controller int buttoncount = 0; // Temporary buttoncount bool hasx; // Temporary xaxis check bool hasy; // Temporary yaxis check bool hasz; // Temporary zaxis check bool haspov; // Temporary pov check bool hasslider; // Temporary slider check JNIEnv* environment; // JNIEnvironment copy bool create_success; // bool used to determine successfull creation // Cached fields of Controller.java jclass clsController; jfieldID fidButtonCount; jfieldID fidHasXAxis; jfieldID fidHasYAxis; jfieldID fidHasZAxis; jfieldID fidHasPOV; jfieldID fidHasSlider; jfieldID fidButtons; jfieldID fidX; jfieldID fidY; jfieldID fidZ; jfieldID fidPOV; jfieldID fidSlider; // Function prototypes (defined in the cpp file, since header file is generic across platforms void EnumerateCapabilities(); void EnumerateControllers(); BOOL CALLBACK EnumControllerCallback(LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef); BOOL CALLBACK EnumControllerObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef); void Shutdown(); void CreateController(LPCDIDEVICEINSTANCE lpddi); void SetupController(); void InitializeFields(); void CacheFields(); void UpdateFields(); void SetCapabilities(); void PrintError(HRESULT error); /** * Initializes any field ids */ JNIEXPORT void JNICALL Java_org_lwjgl_input_Controller_initIDs(JNIEnv * env, jclass clazz) { environment = env; clsController = clazz; /* Cache fields in Controller */ CacheFields(); } /** * Called when the Controller instance is to be created */ JNIEXPORT jboolean JNICALL Java_org_lwjgl_input_Controller_nCreate(JNIEnv *env, jclass clazz) { // Create the DirectInput object. HRESULT hr; hr = DirectInputCreate(GetModuleHandle(NULL), DIRECTINPUT_VERSION, &lpDI, NULL); if (FAILED(hr)) { #if _DEBUG printf("DirectInputCreate failed\n"); #endif Shutdown(); return JNI_FALSE; } /* Find all Controllers */ EnumerateControllers(); if (!create_success) { #if _DEBUG printf("EnumerateControllers failed\n"); #endif Shutdown(); return JNI_FALSE; } /* Enumerate capabilities of Controller */ EnumerateCapabilities(); if (!create_success) { #if _DEBUG printf("EnumerateCapabilities failed\n"); #endif Shutdown(); return JNI_FALSE; } if(create_success) { /* Do setup of Controller */ SetupController(); } /* Initialize any fields on the Controller */ InitializeFields(); /* Set capabilities */ SetCapabilities(); /* Aquire the Controller */ hr = lpDIDevice->Acquire(); if(FAILED(hr)) { #if _DEBUG printf("Acquire failed\n"); #endif Shutdown(); return JNI_FALSE; } return create_success; } /* * Class: org_lwjgl_input_Controller * Method: nDestroy * Signature: ()V */ JNIEXPORT void JNICALL Java_org_lwjgl_input_Controller_nDestroy(JNIEnv *env, jclass clazz) { Shutdown(); } /* * Class: org_lwjgl_input_Controller * Method: nPoll * Signature: ()V */ JNIEXPORT void JNICALL Java_org_lwjgl_input_Controller_nPoll(JNIEnv * env, jclass clazz) { HRESULT hRes; // poll the Controller to read the current state hRes = lpDIDevice->Poll(); if (FAILED(hRes)) { #if _DEBUG printf("Poll fail\n"); #endif return; } UpdateFields(); } /** * Shutdown DI */ void Shutdown() { // release DI instance if (lpDI != NULL) { // release device if (lpDIDevice != NULL) { lpDIDevice->Unacquire(); lpDIDevice->Release(); lpDIDevice = NULL; } lpDI->Release(); lpDI = NULL; } } /** * Enumerates the capabilities of the Controller attached to the system */ void EnumerateCapabilities() { HRESULT hr; hr = lpDIDevice->EnumObjects(EnumControllerObjectsCallback, NULL, DIDFT_ALL); if FAILED(hr) { #if _DEBUG printf("EnumObjects failed\n"); #endif create_success = false; return; } create_success = true; } /** * Enumerates the Controllers attached to the system */ void EnumerateControllers() { HRESULT hr; hr = lpDI->EnumDevices(DIDEVTYPE_JOYSTICK, EnumControllerCallback, 0, DIEDFL_ATTACHEDONLY); if FAILED(hr) { #if _DEBUG printf("EnumDevices failed\n"); #endif create_success = false; return; } create_success = true; } /** * Callback from EnumDevices. Called for each Controller attached to the system */ BOOL CALLBACK EnumControllerCallback(LPCDIDEVICEINSTANCE pdinst, LPVOID pvRef) { /* Add the Controller */ CreateController(pdinst); /* just stop after 1st Controller */ return DIENUM_STOP; } /** * Callback from EnumObjects. Called for each "object" on the Controller. */ BOOL CALLBACK EnumControllerObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVOID pvRef) { #if _DEBUG printf("found %s\n", lpddoi->tszName); #endif if(lpddoi->guidType == GUID_Button) { buttoncount++; } else if(lpddoi->guidType == GUID_XAxis) { hasx = true; } else if(lpddoi->guidType == GUID_YAxis) { hasy = true; } else if(lpddoi->guidType == GUID_ZAxis){ hasz = true; } else if (lpddoi->guidType == GUID_POV){ haspov = true; } else if (lpddoi->guidType == GUID_Slider){ hasslider = true; #if _DEBUG } else { printf("Unhandled object found: %s\n", lpddoi->tszName); #endif } return DIENUM_CONTINUE; } /** * Creates the specified device as a Controller */ void CreateController(LPCDIDEVICEINSTANCE lpddi) { HRESULT hr; hr = lpDI->CreateDevice(lpddi->guidInstance, (LPDIRECTINPUTDEVICE*) &lpDIDevice, NULL); if FAILED(hr) { #if _DEBUG printf("CreateDevice failed\n"); #endif create_success = false; return; } create_success = true; } /** * Sets up the Controller properties */ void SetupController() { // set Controller data format if(lpDIDevice->SetDataFormat(&c_dfDIJoystick2) != DI_OK) { #if _DEBUG printf("SetDataFormat failed\n"); #endif create_success = false; return; } // set the cooperative level if(lpDIDevice->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_BACKGROUND) != DI_OK) { #if _DEBUG printf("SetCooperativeLevel failed\n"); #endif create_success = false; return; } // set X-axis range to (-1000 ... +1000) // This lets us test against 0 to see which way the stick is pointed. DIPROPRANGE diprg; diprg.diph.dwSize = sizeof(diprg); diprg.diph.dwHeaderSize = sizeof(diprg.diph); diprg.diph.dwObj = DIJOFS_X; diprg.diph.dwHow = DIPH_BYOFFSET; diprg.lMin = AXISMIN; diprg.lMax = AXISMAX; if(hasx) { if(lpDIDevice->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK) { #if _DEBUG printf("SetProperty(DIJOFS_X) failed\n"); #endif create_success = false; return; } } // // And again for Y-axis range // if(hasy) { diprg.diph.dwObj = DIJOFS_Y; if(lpDIDevice->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK) { #if _DEBUG printf("SetProperty(DIJOFS_Y) failed\n"); #endif create_success = false; return; } } // // And again for Z-axis range // if(hasz) { diprg.diph.dwObj = DIJOFS_Z; if(lpDIDevice->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK) { #if _DEBUG printf("SetProperty(DIJOFS_Z) failed\n"); #endif create_success = false; return; } } // // Lastly slider // using z axis since we're running dx 5 // if(hasslider) { diprg.diph.dwObj = DIJOFS_Z; if(lpDIDevice->SetProperty(DIPROP_RANGE, &diprg.diph) != DI_OK) { #if _DEBUG printf("SetProperty(DIJOFS_Z(SLIDER)) failed\n"); #endif create_success = false; return; } } create_success = true; } /** * Sets the fields on the Controller */ void InitializeFields() { //set buttons array jbooleanArray buttonsArray = environment->NewBooleanArray(buttoncount); environment->SetStaticObjectField(clsController, fidButtons, buttonsArray); } /** * Updates the fields on the Controller */ void UpdateFields() { HRESULT hRes; // get data from the Controller hRes = lpDIDevice->GetDeviceState(sizeof(DIJOYSTATE2), &js); if (hRes != DI_OK) { // did the read fail because we lost input for some reason? // if so, then attempt to reacquire. if(hRes == DIERR_INPUTLOST) { lpDIDevice->Acquire(); #if _DEBUG printf("DIERR_INPUTLOST, reaquiring input : create_success=%d\n", create_success); #endif } return; } //axis's if(hasx) { environment->SetStaticIntField(clsController, fidX, js.lX); } if(hasy) { environment->SetStaticIntField(clsController, fidY, js.lY); } if(hasz) { environment->SetStaticIntField(clsController, fidZ, js.lZ); } //buttons jbooleanArray buttonsArray = (jbooleanArray) environment->GetStaticObjectField(clsController, fidButtons); BYTE * buttons = (BYTE *) environment->GetPrimitiveArrayCritical(buttonsArray, NULL); memcpy(buttons, js.rgbButtons, buttoncount); environment->ReleasePrimitiveArrayCritical(buttonsArray, buttons, 0); //pov if(haspov) { environment->SetStaticIntField(clsController, fidPOV, js.rgdwPOV[0]); } //slider if(hasslider) { environment->SetStaticIntField(clsController, fidSlider, js.lZ); } } /** * Sets the capabilities of the Controller */ void SetCapabilities() { //set buttoncount environment->SetStaticIntField(clsController, fidButtonCount, buttoncount); //set axis environment->SetStaticIntField(clsController, fidHasXAxis, hasx); environment->SetStaticIntField(clsController, fidHasYAxis, hasy); environment->SetStaticIntField(clsController, fidHasZAxis, hasz); //set pov environment->SetStaticIntField(clsController, fidHasPOV, haspov); //set slider environment->SetStaticIntField(clsController, fidHasSlider, hasslider); } /** * Caches the field ids for quicker access */ void CacheFields() { fidButtonCount = environment->GetStaticFieldID(clsController, "buttonCount", "I"); fidHasXAxis = environment->GetStaticFieldID(clsController, "hasXAxis", "Z"); fidHasYAxis = environment->GetStaticFieldID(clsController, "hasYAxis", "Z"); fidHasZAxis = environment->GetStaticFieldID(clsController, "hasZAxis", "Z"); fidHasPOV = environment->GetStaticFieldID(clsController, "hasPOV", "Z"); fidHasSlider = environment->GetStaticFieldID(clsController, "hasSlider", "Z"); fidButtons = environment->GetStaticFieldID(clsController, "buttons", "[Z"); fidX = environment->GetStaticFieldID(clsController, "x", "I"); fidY = environment->GetStaticFieldID(clsController, "y", "I"); fidZ = environment->GetStaticFieldID(clsController, "z", "I"); fidPOV = environment->GetStaticFieldID(clsController, "pov", "I"); fidSlider = environment->GetStaticFieldID(clsController, "slider", "I"); }