Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/dxgsg8/dxInput8.cxx

Go to the documentation of this file.
00001 // Filename: dxInput8.cxx
00002 // Created by:  angelina jolie (07Oct99)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "config_wdxdisplay8.h"
00020 #include <dxInput8.h>
00021 
00022 #define AXIS_RESOLUTION 2000   // use this many levels of resolution by default (could be more if needed and device supported it)
00023 #define AXIS_RANGE_CENTERED    // if defined, axis range is centered on 0, instead of starting on 0
00024 
00025 BOOL CALLBACK EnumGameCtrlsCallback( const DIDEVICEINSTANCE* pdidInstance,
00026                                      VOID* pContext ) {
00027     DI_DeviceInfos *pDevInfos = (DI_DeviceInfos *)pContext;
00028 
00029     (*pDevInfos).push_back(*pdidInstance);
00030 
00031     if(wdxdisplay_cat.is_debug())
00032         wdxdisplay_cat.debug() << "Found DevType 0x" << (void*)pdidInstance->dwDevType << ": " << pdidInstance->tszInstanceName << ": " << pdidInstance->tszProductName <<endl;
00033 
00034     return DIENUM_CONTINUE;
00035 }
00036 
00037 extern BOOL CALLBACK EnumObjectsCallbackJoystick(const DIDEVICEOBJECTINSTANCE* pdidoi,VOID* pContext);
00038 
00039 DInput8Info::DInput8Info() {
00040     _pDInput8 = NULL;
00041     _hDInputDLL = NULL;
00042     _JoystickPollTimer = NULL;
00043 }
00044 
00045 DInput8Info::~DInput8Info() {
00046   for(UINT i=0;i<_DeviceList.size();i++) {
00047       _DeviceList[i]->Unacquire();
00048       SAFE_RELEASE(_DeviceList[i]);
00049   }
00050 
00051   // bugbug: need to handle this
00052   // if(_JoystickPollTimer!=NULL)
00053   //   KillTimer(...)
00054 
00055   SAFE_RELEASE(_pDInput8);
00056   if(_hDInputDLL) {
00057       FreeLibrary(_hDInputDLL);
00058       _hDInputDLL=NULL;
00059   }
00060 }
00061 
00062 bool DInput8Info::InitDirectInput(void) {
00063     HRESULT hr;
00064 
00065     // assumes dx8 exists
00066     // use dynamic load so non-dinput programs dont have to load dinput
00067     #define DLLNAME "dinput8.dll"
00068     #define DINPUTCREATE "DirectInput8Create"
00069 
00070     HINSTANCE _hDInputDLL = LoadLibrary(DLLNAME);
00071     if(_hDInputDLL == 0) {
00072         wdxdisplay_cat.fatal() << "LoadLibrary(" << DLLNAME <<") failed!, error=" << GetLastError() << endl;
00073         exit(1);
00074     }
00075 
00076     typedef HRESULT (WINAPI * LPDIRECTINPUT8CREATE)(HINSTANCE hinst, DWORD dwVersion, REFIID riidltf, LPVOID *ppvOut, LPUNKNOWN punkOuter);
00077     LPDIRECTINPUT8CREATE pDInputCreate8;
00078 
00079     pDInputCreate8 = (LPDIRECTINPUT8CREATE) GetProcAddress(_hDInputDLL,DINPUTCREATE);
00080     if(pDInputCreate8 == NULL) {
00081         wdxdisplay_cat.fatal() << "GetProcAddr failed for " << DINPUTCREATE << endl;
00082         exit(1);
00083     }
00084 
00085     // Register with the DirectInput subsystem and get a pointer
00086     // to a IDirectInput interface we can use.
00087     // Create a DInput object
00088     if( FAILED( hr = (*pDInputCreate8)(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
00089                                          IID_IDirectInput8, (VOID**)&_pDInput8, NULL ) ) ) {
00090         wdxdisplay_cat.error() << DINPUTCREATE << "failed" << D3DERRORSTRING(hr);
00091         return false;
00092     }
00093 
00094     // enum all the joysticks,etc  (but not keybd/mouse)
00095     if( FAILED( hr = _pDInput8->EnumDevices(DI8DEVCLASS_GAMECTRL,
00096                                          EnumGameCtrlsCallback,
00097                                          (LPVOID)&_DevInfos, DIEDFL_ATTACHEDONLY ) ) ) {
00098         wdxdisplay_cat.error() << "EnumDevices failed" << D3DERRORSTRING(hr);
00099         return false;
00100     }
00101 
00102     return true;
00103 }
00104 
00105 bool DInput8Info::CreateJoystickOrPad(HWND hWnd) {
00106     bool bFoundDev = false;
00107     UINT devnum=0;
00108     char *errstr=NULL;
00109 
00110     // look through the list for the first joystick or gamepad
00111     for(;devnum<_DevInfos.size();devnum++) {
00112         DWORD devType = GET_DIDEVICE_TYPE(_DevInfos[devnum].dwDevType);
00113         if((devType==DI8DEVTYPE_GAMEPAD) ||(devType==DI8DEVTYPE_JOYSTICK)) {
00114           bFoundDev=true;
00115           break;
00116         }
00117     }
00118 
00119     if(!bFoundDev) {
00120         wdxdisplay_cat.error() << "Cant find an attached Joystick or GamePad!\n";
00121         return false;
00122     }
00123 
00124     LPDIRECTINPUTDEVICE8 pJoyDevice;
00125 
00126     // Obtain an interface to the enumerated joystick.
00127     HRESULT hr = _pDInput8->CreateDevice(_DevInfos[devnum].guidInstance, &pJoyDevice, NULL );
00128     if(FAILED(hr)) {
00129         errstr="CreateDevice";
00130         goto handle_error;
00131     }
00132 
00133     assert(pJoyDevice!=NULL);
00134     _DeviceList.push_back(pJoyDevice);
00135 
00136     // Set the data format to "simple joystick" - a predefined data format
00137     //
00138     // A data format specifies which controls on a device we are interested in,
00139     // and how they should be reported. This tells DInput that we will be
00140     // passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
00141     hr = pJoyDevice->SetDataFormat(&c_dfDIJoystick2);
00142     if(FAILED(hr)) {
00143         errstr="SetDataFormat";
00144         goto handle_error;
00145     }
00146 
00147     // must be called AFTER SetDataFormat to get all the proper flags
00148     DX_DECLARE_CLEAN(DIDEVCAPS, DIDevCaps);
00149     hr = pJoyDevice->GetCapabilities(&DIDevCaps);
00150     assert(SUCCEEDED(hr));
00151 
00152     _DevCaps.push_back(DIDevCaps);
00153 
00154     if(wdxdisplay_cat.is_debug())
00155         wdxdisplay_cat.debug() << "Joy/Pad has " << DIDevCaps.dwAxes << " Axes, " <<  DIDevCaps.dwButtons << " Buttons, " <<  DIDevCaps.dwPOVs << " POVs" << endl;
00156 
00157     // Set the cooperative level to let DInput know how this device should
00158     // interact with the system and with other DInput applications.
00159     hr = pJoyDevice->SetCooperativeLevel( hWnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND);
00160     if(FAILED(hr)) {
00161         errstr="SetCooperativeLevel";
00162         goto handle_error;
00163     }
00164 
00165     // set the min/max values property for discovered axes.
00166     hr = pJoyDevice->EnumObjects(EnumObjectsCallbackJoystick, (LPVOID)pJoyDevice, DIDFT_AXIS);
00167     if(FAILED(hr)) {
00168         errstr="EnumObjects";
00169         goto handle_error;
00170     }
00171 
00172     return true;
00173 
00174   handle_error:
00175     wdxdisplay_cat.error() << errstr << " failed for (" << _DevInfos[devnum].tszInstanceName << ":" << _DevInfos[devnum].tszProductName << ")" << D3DERRORSTRING(hr);
00176     return false;
00177 }
00178 
00179 //-----------------------------------------------------------------------------
00180 // Name: EnumObjectsCallback()
00181 // Desc: Callback function for enumerating objects (axes, buttons, POVs) on a
00182 //       joystick. This function enables user interface elements for objects
00183 //       that are found to exist, and scales axes min/max values.
00184 //-----------------------------------------------------------------------------
00185 BOOL CALLBACK EnumObjectsCallbackJoystick( const DIDEVICEOBJECTINSTANCE* pdidoi,
00186                                    VOID* pContext ) {
00187 
00188     LPDIRECTINPUTDEVICE8 pJoyDevice = (LPDIRECTINPUTDEVICE8) pContext;
00189     HRESULT hr;
00190 
00191     // For axes that are returned, set the DIPROP_RANGE property for the
00192     // enumerated axis in order to scale min/max values.
00193     if( pdidoi->dwType & DIDFT_AXIS ) {
00194         DIPROPRANGE diprg;
00195         diprg.diph.dwSize       = sizeof(DIPROPRANGE);
00196         diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00197         diprg.diph.dwHow        = DIPH_BYID;
00198         diprg.diph.dwObj        = pdidoi->dwType; // Specify the enumerated axis
00199 
00200      #ifdef AXIS_RANGE_CENTERED
00201         diprg.lMin              = -AXIS_RESOLUTION/2;
00202         diprg.lMax              = +AXIS_RESOLUTION/2;
00203      #else
00204         diprg.lMin              = 0;
00205         diprg.lMax              = +AXIS_RESOLUTION;
00206      #endif
00207 
00208         // Set the range for the axis
00209         hr = pJoyDevice->SetProperty( DIPROP_RANGE, &diprg.diph);
00210         if(FAILED(hr)) {
00211           wdxdisplay_cat.error() << "SetProperty on axis failed" << D3DERRORSTRING(hr);
00212           return DIENUM_STOP;
00213         }
00214     }
00215 
00216     return DIENUM_CONTINUE;
00217 }
00218 
00219 bool DInput8Info::ReadJoystick(int devnum, DIJOYSTATE2 &js) {
00220     LPDIRECTINPUTDEVICE8 pJoystick = _DeviceList[devnum];
00221     assert(pJoystick!=NULL);
00222     HRESULT hr;
00223     char *errstr;
00224 
00225     // Poll the device to read the current state
00226 
00227     hr = pJoystick->Poll();
00228 
00229     if( FAILED(hr) ) {
00230         // DInput is telling us that the input stream has been
00231         // interrupted. We aren't tracking any state between polls, so
00232         // we don't have any special reset that needs to be done. We
00233         // just re-acquire and try again.
00234 
00235         if((hr==DIERR_NOTACQUIRED)||(hr == DIERR_INPUTLOST)) {
00236             hr = pJoystick->Acquire();
00237 
00238             if(FAILED(hr)) {
00239                 if(wdxdisplay_cat.is_spam())
00240                    wdxdisplay_cat.spam() << "Acquire failed" << D3DERRORSTRING(hr);
00241 
00242                 // hr may be DIERR_OTHERAPPHASPRIO or other errors.  This
00243                 // may occur when the app is minimized or in the process of
00244                 // switching, so just try again later
00245                 return false;
00246             }
00247 
00248             hr = pJoystick->Poll();
00249             if(FAILED(hr)) {
00250                 // should never happen!
00251                 errstr = "Poll after successful Acquire failed";
00252                 goto handle_error;
00253             }
00254         } else {
00255             errstr =  "Unknown Poll failure";
00256             goto handle_error;
00257         }
00258     }
00259 
00260     // should we make a vector of devstate dataformats to generalize this fn for all device types?
00261 
00262     // Get the input's device state
00263     hr = pJoystick->GetDeviceState( sizeof(DIJOYSTATE2), &js);
00264     if(FAILED(hr)) {
00265         errstr =  "GetDeviceState failed";
00266         goto handle_error;
00267     }
00268 
00269     return true;
00270 
00271   handle_error:
00272      wdxdisplay_cat.fatal() << errstr << D3DERRORSTRING(hr);
00273      return false;
00274 }
00275 
00276 

Generated on Fri May 2 00:37:17 2003 for Panda by doxygen1.3