# 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_event_emitter.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 
00029 #include "nel/misc/di_event_emitter.h"
00030 #include "nel/misc/events.h"
00031 #include "nel/misc/win_event_emitter.h"
00032 //
00033 #include "misc/di_mouse_device.h"
00034 #include "misc/di_keyboard_device.h"
00035 #include "misc/di_game_device.h"
00036 //
00037 #include <memory>
00038 #include <algorithm>
00039 
00040 #ifdef NL_OS_WINDOWS
00041 
00042 
00043 
00044 namespace NLMISC
00045 {
00046 
00047 #ifdef NL_DEBUG
00048         static const char DirectInputLibName[] = "dinput8.dll";
00049 #else
00050         static const char DirectInputLibName[] = "dinput8d.dll";
00051 #endif
00052 
00053 
00055 //      CDIEventEmitter statics    //
00057 
00058 HMODULE CDIEventEmitter::_DirectInputLibHandle = 0;
00059 CDIEventEmitter::TPDirectInput8Create CDIEventEmitter::_PDirectInput8Create = NULL;
00060 uint CDIEventEmitter::_NumCreatedInterfaces = 0;
00061 
00064 
00066 // CDIEventEmitter implementation //
00068 
00069 
00070 //======================================================
00071 CDIEventEmitter::CDIEventEmitter(HWND hwnd, CWinEventEmitter *we) 
00072 :
00073  _hWnd(hwnd),
00074  _WE(we),
00075  _DInput8(NULL),
00076  _Keyboard(NULL),
00077  _Mouse(NULL),
00078  _ButtonsFlags(noButton)
00079 {               
00080 }
00081 //======================================================
00082 CDIEventEmitter::~CDIEventEmitter()
00083 {       
00084         releaseMouse();
00085         releaseKeyboard();
00086         // release all devices
00087         while (_DeviceServer.getNumDevices() != 0)
00088         {
00089                 IInputDevice *dev = _DeviceServer.getDevice(0);
00090                 _DeviceServer.removeDevice(dev);
00091                 delete dev;
00092         }
00093         if (_DInput8) _DInput8->Release();
00094         -- _NumCreatedInterfaces;
00095         if (_NumCreatedInterfaces == 0) unloadLib();
00096 }
00097 
00098 //======================================================
00099 CDIEventEmitter *CDIEventEmitter::create(HINSTANCE hinst, HWND hwnd, CWinEventEmitter *we) throw(EDirectInput)
00100 {
00101         if (!loadLib()) throw EDirectInputLibNotFound();        
00102         std::auto_ptr<CDIEventEmitter> dxee(new CDIEventEmitter(hwnd, we));
00103         HRESULT result = _PDirectInput8Create(hinst, 
00104                                                                                   DIRECTINPUT_VERSION,
00105                                                                                   IID_IDirectInput8A,
00106                                                                                   (void **) &dxee->_DInput8,
00107                                                                                   NULL);
00108         if (result != DI_OK) throw EDirectInputInitFailed();    
00109 
00110         // ok, everything's fine, commit changes
00111         ++_NumCreatedInterfaces;
00112         return dxee.release();
00113 }
00114 
00115 
00116 //======================================================
00117 bool CDIEventEmitter::loadLib()
00118 {
00119         if (_DirectInputLibHandle != 0) return true; // library already loaded ?
00120         HMODULE handle = ::LoadLibrary(DirectInputLibName);
00121         if (handle == 0) return false;  
00122         //      try to get the creation function
00123         TPDirectInput8Create cf = (TPDirectInput8Create) ::GetProcAddress(handle, "DirectInput8Create");
00124         if (!cf)
00125         {
00126                 ::FreeLibrary(handle);          
00127                 return false;
00128         }
00129         // commit changes
00130         _DirectInputLibHandle = handle;
00131         _PDirectInput8Create  = cf;
00132         return true;
00133 }
00134 
00135 
00136 //======================================================
00137 void CDIEventEmitter::unloadLib()
00138 {
00139         nlassert(_DirectInputLibHandle != 0);
00140         ::FreeLibrary(_DirectInputLibHandle);
00141         _DirectInputLibHandle = 0;
00142         _PDirectInput8Create = NULL;
00143 }
00144 
00145 //======================================================
00146 void CDIEventEmitter::poll(CEventServer *server)
00147 {
00148         if (_WE) _ButtonsFlags = _WE->buildFlags();
00149         if (!server)
00150                 server=&_InternalServer;        
00151         _DeviceServer.poll(server);     
00152 }
00153 
00154 
00155 //======================================================
00156 TMouseButton    CDIEventEmitter::buildButtonsFlags() const
00157 {
00158         uint mouseFlags;
00159         uint keybFlags;
00160         // 
00161         if (_Mouse) // takes the flags from the direct input mouse
00162         {
00163                 mouseFlags = (_Mouse->getButton(0) ? leftButton         : 0)
00164                                          | (_Mouse->getButton(1) ? rightButton  : 0)
00165                                          | (_Mouse->getButton(2) ? middleButton : 0);
00166         }
00167         else // takes the flags from the system mouse
00168         {
00169                 mouseFlags = _ButtonsFlags & (leftButton | rightButton | middleButton);
00170         }
00171         //
00172         if (_Keyboard) // takes the flags from the direct input keyboard
00173         {
00174                 keybFlags = (_Keyboard->ShiftPressed      ? shiftButton         : 0)
00175                                         | (_Keyboard->AltPressed          ? altButton           : 0)
00176                                         | (_Keyboard->CtrlPressed         ? ctrlButton          : 0);
00177         }
00178         else // takes the flags from the system keyboard
00179         {
00180                 keybFlags = _ButtonsFlags & (shiftButton | altButton | ctrlButton);
00181         }
00182         return (TMouseButton) (keybFlags | mouseFlags);
00183 }
00184 
00185 //======================================================
00186 IMouseDevice    *CDIEventEmitter::getMouseDevice() throw(EInputDevice)
00187 {
00188         if (_Mouse) return _Mouse;      // already created ?
00189         try
00190         {
00191                 // Create a mouse
00192                 std::auto_ptr<CDIMouse> mouse(CDIMouse::createMouseDevice(_DInput8, _hWnd, this));      
00193                 // register to the device server
00194                 _DeviceServer.registerDevice(mouse.get());
00195                 _Mouse = mouse.get();   
00196                 if (_WE)        _WE->enableMouseEvents(false);          
00197                 return mouse.release();
00198         }
00199         catch (...)
00200         {
00201                 if (_WE)        _WE->enableMouseEvents(true);
00202                 throw;
00203         }
00204 }
00205 
00206 //======================================================
00207 void    CDIEventEmitter::releaseMouse()
00208 {
00209         if (!_Mouse) return;
00210         // reupdate the system keyboard flags
00211         if (_WE)
00212         {
00213                 _WE->resetButtonFlagState();
00214                 _WE->enableMouseEvents(true);
00215         }
00216         // remove the device
00217         _DeviceServer.removeDevice(_Mouse);
00218         delete _Mouse;
00219         _Mouse = NULL;
00220 }
00221 
00222 //===========================================================================
00223 IKeyboardDevice *CDIEventEmitter::getKeyboardDevice() throw(EInputDevice)
00224 {
00225         if (_Keyboard) return _Keyboard;
00226         // create a keyboard
00227         std::auto_ptr<CDIKeyboard> keyboard(CDIKeyboard::createKeyboardDevice(_DInput8, _hWnd, this, _WE));
00228         // register to the device server
00229         _DeviceServer.registerDevice(keyboard.get());
00230         _Keyboard = keyboard.get();             
00231         return keyboard.release();
00232 }
00233 
00234 //==========================================================================
00235 void    CDIEventEmitter::releaseKeyboard()
00236 {
00237         if (!_Keyboard) return;
00238         // reupdate the system keyboard flags
00239         if (_WE)        _WE->resetButtonFlagState();
00240         //
00241         _DeviceServer.removeDevice(_Keyboard);
00242         delete _Keyboard;
00243         _Keyboard = NULL;
00244 }
00245 
00246 
00247 //==========================================================================
00248 void    CDIEventEmitter::submitEvents(CEventServer &server)
00249 {
00250         _InternalServer.setServer(&server);
00251         _InternalServer.pump();
00252 }
00253 
00254 //==========================================================================
00256 static BOOL CALLBACK DIEnumDevicesDescCallback
00257 (
00258   LPCDIDEVICEINSTANCE lpddi,  
00259   LPVOID pvRef  
00260 )
00261 {
00262         CGameDeviceDesc desc;
00263         desc.InstanceName = lpddi->tszInstanceName;
00264         desc.ProductName  = lpddi->tszProductName;
00265         switch (lpddi->wUsage & 0xff)
00266         {
00267                 case DI8DEVTYPE_JOYSTICK: desc.DevType = CGameDeviceDesc::Joystick;  break;
00268                 case DI8DEVTYPE_GAMEPAD:  desc.DevType = CGameDeviceDesc::GamePad;       break;
00269                 default: desc.DevType = CGameDeviceDesc::DontKnow; break;
00270         }
00271         TDeviceDescVect *dv = (TDeviceDescVect *) pvRef;
00272         dv->push_back(desc);
00273         return DIENUM_CONTINUE;
00274 }
00275 
00276 
00277 //==========================================================================
00279 static BOOL CALLBACK DIEnumDevicesGUIDCallback
00280 (
00281   LPCDIDEVICEINSTANCE lpddi,  
00282   LPVOID pvRef  
00283 )
00284 {       
00285         std::vector<GUID> *gv = (std::vector<GUID> *) pvRef;
00286         gv->push_back(lpddi->guidInstance);
00287         return DIENUM_CONTINUE;
00288 }
00289 
00290 
00291 //==========================================================================
00292 void    CDIEventEmitter::enumerateGameDevice(TDeviceDescVect &descs) throw(EInputDevice)
00293 {
00294         uint k;
00295         nlassert(_DInput8);
00296         descs.clear();
00297         // enum all devices of interest
00298         _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &descs, DIEDFL_ALLDEVICES);
00299         for (k = 0; k < descs.size(); ++k) descs[k].Connected = false;
00300         // enum all connected devices
00301         static TDeviceDescVect connecteds;
00302         _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesDescCallback, (LPVOID) &connecteds, DIEDFL_ATTACHEDONLY);
00303         // see which devices are connected
00304         for (k = 0; k < connecteds.size(); ++k)
00305         {
00306                 TDeviceDescVect::iterator it = std::find(descs.begin(), descs.end(), connecteds[k]);
00307                 it->Connected = true;
00308         }
00309 }
00310 
00311 //==========================================================================
00312 IGameDevice     *CDIEventEmitter::createGameDevice(const std::string &instanceName) throw(EInputDevice)
00313 {
00314         static TDeviceDescVect          deviceDescs;
00315         static std::vector<GUID>        deviceGUID;
00316 
00317         nlassert(_DInput8);     
00318         enumerateGameDevice(deviceDescs);
00319         // get the ID for each device
00320         deviceGUID.clear();
00321         HRESULT r = _DInput8->EnumDevices(DI8DEVCLASS_GAMECTRL, &DIEnumDevicesGUIDCallback, (LPVOID) &deviceGUID, DIEDFL_ALLDEVICES);
00322         nlassert(r == DI_OK);
00323         nlassert(deviceDescs.size() == deviceGUID.size());
00324 
00325         // search the device that match the instance name
00326         for (uint k = 0;  k < deviceDescs.size(); ++k)
00327         {
00328                 if (deviceDescs[k].InstanceName == instanceName)
00329                 {
00330                         std::auto_ptr<CDIGameDevice> gd(CDIGameDevice::createGameDevice(_DInput8, _hWnd, this, deviceDescs[k], deviceGUID[k]));
00331                         // insert in the device server
00332                         _DeviceServer.registerDevice(gd.get());                 
00333                         return gd.release();
00334                 }
00335         }
00336         return NULL;
00337 }       
00338 
00339 //==========================================================================
00340 void    CDIEventEmitter::releaseGameDevice(IGameDevice  *gd)
00341 {
00342         nlassert(gd);
00343         CDIGameDevice *digd = safe_cast<CDIGameDevice *>(gd);
00344         _DeviceServer.removeDevice(digd);
00345         delete gd;
00346 }
00347 
00348 
00349 } // NLMISC
00350 
00351 #endif // NL_OS_WINDOWS