00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
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
00105
00106 {
00107 CAxis &axis = _Axis[k];
00108 if (axis.Present)
00109 {
00110
00111 if (((LONG *) &newState)[k] != ((LONG *) &_CurrentState)[k])
00112 {
00113
00114 axis.Value = 2.f * (((LONG *) &newState)[k] - axis.Min) / (float) (axis.Max - axis.Min) - 1.f;
00115
00116 CGDAxisMoved *event = new CGDAxisMoved((IGameDevice::TAxis) k, axis.Value, this, _EventEmitter);
00117
00118 ((LONG *) &_CurrentState)[k] = ((LONG *) &newState)[k];
00119
00120 server->postEvent(event);
00121
00122 }
00123 }
00124 }
00125
00126
00128
00130
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
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
00142 _CurrentState.rgbButtons[k] = newState.rgbButtons[k];
00143 server->postEvent(event);
00144 }
00145 }
00146
00148
00150
00151 {
00152 CSlider &sl = _Sliders[k];
00153 if (newState.rglSlider[k] != _CurrentState.rglSlider[k])
00154 {
00155
00156 sl.Pos = ( newState.rglSlider[k] - sl.Min) / (float) (sl.Max - sl.Min);
00157
00158 CGDSliderMoved *event = new CGDSliderMoved(sl.Pos, k, this, _EventEmitter);
00159
00160 _CurrentState.rglSlider[k] = newState.rglSlider[k];
00161
00162 server->postEvent(event);
00163 }
00164 }
00165
00167
00169
00170 {
00171 CPOV &pov = _POVs[k];
00172 if (newState.rgdwPOV[k] != _CurrentState.rgdwPOV[k])
00173 {
00174 DWORD value = newState.rgdwPOV[k];
00175
00176 pov.Centered = (LOWORD(value) == 0xFFFF);
00177 if (!pov.Centered)
00178 {
00179
00180 pov.Angle = value / 100.f;
00181 }
00182
00183 CGDPOVChanged *event = new CGDPOVChanged(pov.Centered, pov.Angle, k, this, _EventEmitter);
00184
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
00197 }
00198
00199
00200 void CDIGameDevice::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
00201 {
00202
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
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
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
00252 HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
00253
00254 if (r == DIERR_OBJECTNOTFOUND)
00255 {
00256
00257 diprg.diph.dwHow = DIPH_BYID;
00258 diprg.diph.dwObj = type;
00259
00260
00261 HRESULT r = device->GetProperty(DIPROP_RANGE, &diprg.diph);
00262 if (r != DI_OK)
00263 {
00264
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
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296
00297
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
00311
00312 if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwOfs) + sizeof(DWORD)) return DIENUM_CONTINUE;
00313
00314 uint ctrlType = (uint) lpddoi->dwType;
00315
00317
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
00366 if (lpddoi->dwSize < offsetof(DIDEVICEOBJECTINSTANCE, dwType) + sizeof(DWORD)) return DIENUM_CONTINUE;
00367
00368
00369 uint type = lpddoi->dwType;
00371
00373
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
00389
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
00407
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
00434 return false;
00435 }
00436
00437
00438 uint CDIGameDevice::getBufferSize() const
00439 {
00440
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));
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));
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 }
00529
00530
00531 #endif // NL_OS_WINDOWS