# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

di_game_device.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000-2002 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 #include "stdmisc.h"
00028 #include "misc/di_game_device.h"
00029 #include "nel/misc/game_device_events.h"
00030 #include <stddef.h>
00031 #include <memory>
00032 #include <algorithm>
00033 
00034 #ifdef NL_OS_WINDOWS
00035 
00036 namespace NLMISC 
00037 {
00038 
00039 //============================================================================
00040 CDIGameDevice::CDIGameDevice() : _Device(NULL)                                                           
00041 {       
00042         ::memset(&_CurrentState, 0, sizeof(_CurrentState));
00043 }
00044 
00045 //============================================================================
00046 CDIGameDevice::~CDIGameDevice()
00047 {
00048         if (_Device)
00049         {
00050                 _Device->Unacquire();
00051                 _Device->Release();
00052         }
00053 }
00054 
00055 //============================================================================
00056 CDIGameDevice *CDIGameDevice::createGameDevice(IDirectInput8 *di8,
00057                                                                                            HWND hwnd,
00058                                                                                            CDIEventEmitter *diEventEmitter,
00059                                                                                            const CGameDeviceDesc &desc,
00060                                                                                            REFGUID rguid) throw(EDirectInput)
00061 {
00062         nlassert(diEventEmitter);       
00063         nlassert(di8);
00064         std::auto_ptr<CDIGameDevice> dev(new CDIGameDevice);
00065         //
00066 
00067         HRESULT r = di8->CreateDevice(rguid, &dev->_Device, NULL);
00068         if (r != DI_OK) throw EDirectInputGameDeviceNotCreated();       
00069 
00070         r = dev->_Device->SetDataFormat(pJoyDataFormat);
00071         nlassert(r == DI_OK);
00072         //
00073         r = dev->_Device->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
00074         if (r != DI_OK) throw EDirectInputCooperativeLevelFailed();
00075         //      
00076         //                      
00077         dev->_Desc = desc;
00078         dev->_EventEmitter = diEventEmitter;
00079         dev->querryControls();  
00080         return dev.release();
00081 }
00082 
00083 //============================================================================
00084 void CDIGameDevice::begin(CEventServer *server)
00085 {
00086         nlassert(_Device);
00087         HRESULT r;
00088         r = _Device->Poll();
00089         if (r == DIERR_INPUTLOST  || r == DIERR_NOTACQUIRED)
00090         {                               
00091         r = _Device->Acquire();
00092                 if (r != DI_OK) return;
00093                 r = _Device->Poll();
00094                 if (r != DI_OK) return;
00095         }
00096 
00097         CDIJoyState     newState;       
00098         r = _Device->GetDeviceState(sizeof(CDIJoyState), &newState);
00099         if (r != DI_OK) return;
00100 
00101         uint k;
00103         // Axis //
00105         for (k = 0; k < MaxNumAxis; ++k)
00106         {
00107                 CAxis &axis = _Axis[k];
00108                 if (axis.Present)
00109                 {                       
00110                         
00111                         if (((LONG *) &newState)[k] != ((LONG *) &_CurrentState)[k]) // state changed ?
00112                         {                               
00113                                 // update position
00114                                 axis.Value              = 2.f * (((LONG *) &newState)[k] - axis.Min) / (float) (axis.Max - axis.Min) - 1.f;
00115                                 // create event
00116                                 CGDAxisMoved    *event = new CGDAxisMoved((IGameDevice::TAxis) k, axis.Value, this, _EventEmitter);
00117                                 // update state
00118                                 ((LONG *) &_CurrentState)[k] = ((LONG *) &newState)[k];
00119                                 //
00120                                 server->postEvent(event);
00121                                 //
00122                         }                                                       
00123                 }
00124         }
00125 
00126 
00128         // Buttons //
00130         for (k = 0; k < _Buttons.size(); ++k)
00131         {               
00132                 CButton &bt = _Buttons[k];              
00133                 if ((newState.rgbButtons[k] & 0x80) != (_CurrentState.rgbButtons[k] & 0x80))
00134                 {
00135                         bool pushed = (newState.rgbButtons[k] & 0x80) != 0;                     
00136                         // update the state of the button
00137                         bt.Pushed = pushed;
00138                         CGDButton *event;
00139                         if (pushed) event = new CGDButtonDown(k, this, _EventEmitter);
00140                         else event = new CGDButtonUp(k, this, _EventEmitter);                                   
00141                         // update state                 
00142                         _CurrentState.rgbButtons[k] = newState.rgbButtons[k];
00143                         server->postEvent(event);
00144                 }
00145         }
00146 
00148         // Sliders //
00150         for (k = 0; k < _Sliders.size(); ++k)
00151         {               
00152                 CSlider &sl = _Sliders[k];
00153                 if (newState.rglSlider[k] != _CurrentState.rglSlider[k]) // state changed ?
00154                 {                                                               
00155                         // update position
00156                         sl.Pos          = ( newState.rglSlider[k] - sl.Min) / (float) (sl.Max - sl.Min);
00157                         // create event
00158                         CGDSliderMoved  *event = new CGDSliderMoved(sl.Pos, k, this, _EventEmitter);
00159                         // update state
00160                         _CurrentState.rglSlider[k] = newState.rglSlider[k];
00161                         //
00162                         server->postEvent(event);
00163                 }
00164         }
00165 
00167         // POVs //
00169         for (k = 0; k < _POVs.size(); ++k)
00170         {
00171                 CPOV &pov = _POVs[k];           
00172                 if (newState.rgdwPOV[k] != _CurrentState.rgdwPOV[k]) // state changed ?
00173                 {                                                       
00174                         DWORD value = newState.rgdwPOV[k];
00175 
00176                         pov.Centered = (LOWORD(value) == 0xFFFF);
00177                         if (!pov.Centered)
00178                         {
00179                                 // update position
00180                                 pov.Angle               = value / 100.f;
00181                         }
00182                         // create event
00183                         CGDPOVChanged   *event = new CGDPOVChanged(pov.Centered, pov.Angle, k, this, _EventEmitter);
00184                         // update state
00185                         _CurrentState.rgdwPOV[k] = newState.rgdwPOV[k];
00186                         //
00187                         server->postEvent(event);
00188                 }
00189         }
00190 
00191 }
00192 
00193 //============================================================================
00194 void CDIGameDevice::poll(CInputDeviceServer *dev)
00195 {
00196         // buffered datas not supported
00197 }
00198 
00199 //============================================================================
00200 void CDIGameDevice::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
00201 {
00202         // should never be called, buffered datas not supported
00203         nlassert(0);
00204 }
00205 
00206 
00207 //============================================================================
00211 static void BuildCtrlName(LPCDIDEVICEOBJECTINSTANCE lpddoi,
00212                                                   std::string &destName,
00213                                                   const char *defaultName)
00214 {
00215         if (lpddoi->dwSize >= offsetof(DIDEVICEOBJECTINSTANCE, tszName) + sizeof(TCHAR[MAX_PATH]))
00216         {
00217                 destName = (::strcmp("N/A", lpddoi->tszName) == 0) ? defaultName
00218                                                                                                                   : lpddoi->tszName;            
00219         }
00220         else
00221         {
00222                 destName = defaultName; 
00223         }
00224 }
00225 
00226 //============================================================================
00227 // A callback to enumerate the controls of a device
00228 static BOOL CALLBACK DIEnumDeviceObjectsCallback
00229 (
00230   LPCDIDEVICEOBJECTINSTANCE lpddoi,
00231   LPVOID pvRef 
00232 )
00233 {
00234 
00235         CDIGameDevice *gd = (CDIGameDevice *) pvRef;
00236         return gd->processEnumObject(lpddoi);
00237 }
00238 
00239 
00240 
00241 //=======================================================================
00242 // get range for an axis
00243 static HRESULT  GetDIAxisRange(LPDIRECTINPUTDEVICE8 device, uint offset, DWORD type, sint &min, sint &max)
00244 {
00245         DIPROPRANGE diprg; 
00246     diprg.diph.dwSize       = sizeof(DIPROPRANGE); 
00247     diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER); 
00248     diprg.diph.dwHow        = DIPH_BYOFFSET; 
00249     diprg.diph.dwObj        = offset;
00250     
00251         // Set the range for the axis
00252         HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
00253 
00254         if (r == DIERR_OBJECTNOTFOUND)
00255         {
00256                 // try from its ID
00257                 diprg.diph.dwHow        = DIPH_BYID; 
00258                 diprg.diph.dwObj        = type;
00259 
00260                 // Set the range for the axis
00261                 HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
00262                 if (r !=  DI_OK)
00263                 {
00264                         // setup default values ...
00265                         min = 0;
00266                         max = 65535;
00267                         return r;
00268                 }
00269         }
00270         else if (r != DI_OK)
00271         {
00272                 min = 0;
00273                 max = 65535;
00274                 return r;
00275         }
00276                  
00277 
00278 /*      switch (r)
00279         {
00280                 default:
00281                         nlinfo("ok");
00282                 break;
00283                 case DIERR_INVALIDPARAM: 
00284                         nlinfo("invalid param");
00285                 break;
00286                 case DIERR_NOTEXCLUSIVEACQUIRED: 
00287                         nlinfo("DIERR_NOTEXCLUSIVEACQUIRED");
00288                 break;
00289                 case DIERR_NOTINITIALIZED: 
00290                         nlinfo("DIERR_NOTINITIALIZED");
00291                 break;
00292                 case DIERR_OBJECTNOTFOUND: 
00293                         nlinfo("DIERR_OBJECTNOTFOUND");
00294                 break;
00295                 case DIERR_UNSUPPORTED: 
00296                         nlinfo("DIERR_UNSUPPORTED");
00297                 break;
00298         }*/
00299 
00300         
00301         min = (sint) diprg.lMin;
00302         max = (sint) diprg.lMax;
00303         
00304         return r;
00305 }
00306 
00307 //============================================================================
00308 BOOL CDIGameDevice::processEnumObject(LPCDIDEVICEOBJECTINSTANCE lpddoi)
00309 {
00310         // the dwSize field gives us the size of the objects, and the available fields
00311         // has this object the field guidType and dwOfs ?
00312         if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwOfs) + sizeof(DWORD)) return DIENUM_CONTINUE;
00313 
00314         uint ctrlType = (uint) lpddoi->dwType;
00315 
00317         //      axis, we only support absolute ones  //
00319 
00320         if (lpddoi->guidType == GUID_XAxis && (ctrlType & DIDFT_ABSAXIS) )
00321         {               
00322                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[XAxis].Min, _Axis[XAxis].Max);
00323                 BuildCtrlName(lpddoi, _Axis[XAxis].Name, "X Axis");                             
00324                 _Axis[XAxis].Present = true;
00325                 return DIENUM_CONTINUE;
00326         }
00327         if (lpddoi->guidType == GUID_YAxis && (ctrlType & DIDFT_ABSAXIS))
00328         {               
00329                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[YAxis].Min, _Axis[YAxis].Max);
00330                 BuildCtrlName(lpddoi, _Axis[YAxis].Name, "Y Axis");                                                             
00331                 _Axis[YAxis].Present = true;
00332                 return DIENUM_CONTINUE;
00333         }
00334         
00335         if (lpddoi->guidType == GUID_ZAxis && (ctrlType & DIDFT_ABSAXIS))
00336         {        
00337                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[ZAxis].Min, _Axis[ZAxis].Max);
00338                 BuildCtrlName(lpddoi, _Axis[ZAxis].Name, "Z Axis");             
00339                 _Axis[ZAxis].Present = true;
00340                 return DIENUM_CONTINUE;
00341         }
00342         if (lpddoi->guidType == GUID_RxAxis && (ctrlType & DIDFT_ABSAXIS))
00343         {        
00344                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RXAxis].Min, _Axis[RXAxis].Max);
00345                 BuildCtrlName(lpddoi, _Axis[RXAxis].Name, "RX Axis");                           
00346                 _Axis[RXAxis].Present = true;
00347                 return DIENUM_CONTINUE;
00348         }
00349         if (lpddoi->guidType == GUID_RyAxis && (ctrlType & DIDFT_ABSAXIS))
00350         {        
00351                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RYAxis].Min, _Axis[RYAxis].Max);
00352                 BuildCtrlName(lpddoi, _Axis[RYAxis].Name, "RY Axis");           
00353                 _Axis[RYAxis].Present = true;
00354                 return DIENUM_CONTINUE;
00355         }
00356         if (lpddoi->guidType == GUID_RzAxis && (ctrlType & DIDFT_ABSAXIS))
00357         {        
00358                 GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Axis[RZAxis].Min, _Axis[RZAxis].Max);
00359                 BuildCtrlName(lpddoi, _Axis[RZAxis].Name, "RZ Axis");           
00360                 _Axis[RZAxis].Present = true;
00361                 return DIENUM_CONTINUE;
00362         }
00363 
00364 
00365         // has this object the field dwType ?
00366         if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwType) + sizeof(DWORD)) return DIENUM_CONTINUE;
00367 
00368 
00369         uint type = lpddoi->dwType;
00371         // Buttons //
00373         if (type & DIDFT_BUTTON)
00374         {
00375                 if (_Buttons.size() < MaxNumButtons)
00376                 {
00377                         _Buttons.push_back(CButton());
00378                         uint buttonIndex = _Buttons.size() - 1;
00379                         char defaultButtonName[32];
00380                         smprintf(defaultButtonName, 32, "BUTTON %d", buttonIndex + 1);
00381                         BuildCtrlName(lpddoi, _Buttons[buttonIndex].Name, defaultButtonName);           
00382                         return DIENUM_CONTINUE;
00383                 }
00384         }
00385 
00387         // Sliders //
00389         if (type & DIDFT_ABSAXIS)
00390         {
00391                 if (_Sliders.size() < MaxNumSliders)
00392                 {
00393                         _Sliders.push_back(CSlider());
00394                         uint sliderIndex = _Sliders.size() - 1;
00395                         GetDIAxisRange(_Device, lpddoi->dwOfs, lpddoi->dwType, _Sliders[sliderIndex].Min, _Sliders[sliderIndex].Max);
00396                         char defaultSliderName[32];
00397                         smprintf(defaultSliderName, 32, "SLIDER %d", sliderIndex + 1);
00398                         BuildCtrlName(lpddoi, _Sliders[sliderIndex].Name, defaultSliderName);                                   
00399                 }
00400                 return DIENUM_CONTINUE;
00401         }
00402 
00403 
00405         // POVs //
00407         if (type & DIDFT_POV)
00408         {
00409                 if (_POVs.size() < MaxNumPOVs)
00410                 {
00411                         _POVs.push_back(CPOV());
00412                         uint povIndex = _POVs.size() - 1;
00413                         char defaultPOVName[16];
00414                         smprintf(defaultPOVName, 16, "POV %d", povIndex + 1);
00415                         BuildCtrlName(lpddoi, _POVs[povIndex].Name, defaultPOVName);                            
00416                 }
00417                 return DIENUM_CONTINUE;
00418         }
00419         
00420         return DIENUM_CONTINUE;
00421 }
00422 
00423 //============================================================================
00424 void    CDIGameDevice::querryControls()
00425 {
00426         HRESULT r = _Device->EnumObjects(&DIEnumDeviceObjectsCallback, (LPVOID) this, DIDFT_ALL);
00427         nlassert(r == DI_OK);
00428 }
00429 
00430 //============================================================================
00431 bool  CDIGameDevice::setBufferSize(uint size)
00432 {
00433         // uisually not supported by this kind of devices
00434         return false;
00435 }
00436 
00437 //============================================================================
00438 uint  CDIGameDevice::getBufferSize() const
00439 {
00440         // uisually not supported by this kind of devices
00441         return 0;
00442 }
00443 
00444 //============================================================================
00445 uint  CDIGameDevice::getNumButtons() const
00446 {
00447         return _Buttons.size();
00448 }
00449 
00450 //============================================================================
00451 bool            CDIGameDevice::hasAxis(TAxis axis) const
00452 {
00453         nlassert(axis < MaxNumAxis);
00454         return _Axis[axis].Present;
00455 }
00456 
00457 //============================================================================
00458 uint            CDIGameDevice::getNumSliders() const
00459 {
00460         return _Sliders.size();
00461 }
00462 
00463 //============================================================================
00464 uint            CDIGameDevice::getNumPOV() const 
00465 {
00466         return _POVs.size();
00467 }
00468 //============================================================================
00469 const char *CDIGameDevice::getButtonName(uint index) const
00470 {
00471         nlassert(index < _Buttons.size());
00472         return _Buttons[index].Name.c_str();
00473 }
00474 
00475 //============================================================================
00476 const char *CDIGameDevice::getAxisName(TAxis axis) const
00477 {
00478         nlassert(axis < MaxNumAxis);
00479         nlassert(hasAxis(axis)); // ! Not an axis of this device
00480         return  _Axis[axis].Name.c_str();
00481 }
00482 
00483 //============================================================================
00484 const char *CDIGameDevice::getSliderName(uint index) const
00485 {
00486         nlassert(index < _Sliders.size());
00487         return _Sliders[index].Name.c_str();
00488 }
00489 
00490 //============================================================================
00491 const char *CDIGameDevice::getPOVName(uint index) const
00492 {
00493         nlassert(index < _POVs.size());
00494         return _POVs[index].Name.c_str();
00495 }
00496 
00497 //============================================================================
00498 bool            CDIGameDevice::getButtonState(uint index) const
00499 {
00500         nlassert(index < _Buttons.size());
00501         return _Buttons[index].Pushed;
00502 }
00503 
00504 //============================================================================
00505 float           CDIGameDevice::getAxisValue(TAxis axis) const
00506 {
00507         nlassert(axis < MaxNumAxis);
00508         nlassert(hasAxis(axis)); // ! Not an axis of this device
00509         return  _Axis[axis].Value;
00510 }
00511 
00512 //============================================================================
00513 float           CDIGameDevice::getSliderPos(uint index) const
00514 {
00515         nlassert(index < _Sliders.size());
00516         return _Sliders[index].Pos;
00517 }
00518 
00519 //============================================================================
00520 float           CDIGameDevice::getPOVAngle(uint index) const
00521 {
00522         nlassert(index < _POVs.size());
00523         return _POVs[index].Angle;
00524 }
00525 
00526 
00527 
00528 } // NLMISC
00529 
00530 
00531 #endif // NL_OS_WINDOWS