00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "stdmisc.h"
00027
00028 #include "misc/di_mouse_device.h"
00029 #include "nel/misc/game_device_events.h"
00030
00031
00032 #ifdef NL_OS_WINDOWS
00033
00034 #include <memory>
00035 #include <algorithm>
00036
00037
00038
00039
00040 namespace NLMISC
00041 {
00042
00043
00044
00045
00046
00047 CDIMouse::CDIMouse() : _MessageMode(RawMode),
00048 _MouseSpeed(1.0f),
00049 _Mouse(NULL),
00050 _XAcc(0),
00051 _YAcc(0),
00052 _XMousePos(0),
00053 _YMousePos(0),
00054 _LastMouseButtonClicked(-1),
00055 _DoubleClickDelay(300),
00056 _XFactor(1.f),
00057 _YFactor(1.f),
00058 OldDIXPos(0),
00059 OldDIYPos(0),
00060 OldDIZPos(0),
00061 _XRaw(0),
00062 _YRaw(0),
00063 _FirstX(true),
00064 _FirstY(true)
00065
00066 {
00067 std::fill(_MouseButtons, _MouseButtons + MaxNumMouseButtons, 0);
00068 std::fill(_MouseAxisMode, _MouseAxisMode + NumMouseAxis, Raw);
00069 _MouseFrame.setWH(0, 0, 640, 480);
00070 }
00071
00072
00073 CDIMouse::~CDIMouse()
00074 {
00075 if (_Mouse)
00076 {
00077 _Mouse->Unacquire();
00078 _Mouse->Release();
00079 }
00080 }
00081
00082
00083 void CDIMouse::setMouseMode(TAxis axis, TAxisMode axisMode)
00084 {
00085 nlassert(axisMode < AxisModeLast);
00086 nlassert(axis < AxisLast);
00087 _MouseAxisMode[axis] = axisMode;
00088 clampMouseAxis();
00089 }
00090
00091
00092 CDIMouse::TAxisMode CDIMouse::getMouseMode(TAxis axis) const
00093 {
00094 nlassert(axis < NumMouseAxis);
00095 return _MouseAxisMode[axis];
00096 }
00097
00098
00099 void CDIMouse::setMouseSpeed(float speed)
00100 {
00101 nlassert(_MessageMode == NormalMode);
00102 nlassert(speed > 0);
00103 _MouseSpeed = speed;
00104 }
00105
00106
00107 bool CDIMouse::setBufferSize(uint size)
00108 {
00109 nlassert(size > 0);
00110 nlassert(_Mouse);
00111 _Mouse->Unacquire();
00112 DIPROPDWORD dipdw;
00113 dipdw.diph.dwSize = sizeof(DIPROPDWORD);
00114 dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00115 dipdw.diph.dwObj = 0;
00116 dipdw.diph.dwHow = DIPH_DEVICE;
00117 dipdw.dwData = size;
00118 HRESULT r = _Mouse->SetProperty( DIPROP_BUFFERSIZE, &dipdw.diph );
00119 if (r != DI_OK) return false;
00120 _MouseBufferSize = size;
00121 return true;
00122 }
00123
00124
00125 uint CDIMouse::getBufferSize() const { return _MouseBufferSize; }
00126
00127
00128 void CDIMouse::setMousePos(float x, float y)
00129 {
00130 nlassert(_MessageMode == NormalMode);
00131 _XMousePos = (sint32) (x * (1 << 16));
00132 _YMousePos = (sint32) (y * (1 << 16));
00133 }
00134
00135
00136 CDIMouse *CDIMouse::createMouseDevice(IDirectInput8 *di8, HWND hwnd, CDIEventEmitter *diEventEmitter) throw(EDirectInput)
00137 {
00138 std::auto_ptr<CDIMouse> mouse(new CDIMouse);
00139 mouse->_DIEventEmitter = diEventEmitter;
00140 HRESULT result = di8->CreateDevice(GUID_SysMouse, &(mouse->_Mouse), NULL);
00141 if (result != DI_OK) throw EDirectInputNoMouse();
00142 result = mouse->_Mouse->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_EXCLUSIVE);
00143 if (result != DI_OK) throw EDirectInputCooperativeLevelFailed();
00144 mouse->_Mouse->SetDataFormat(&c_dfDIMouse2);
00145 mouse->setBufferSize(64);
00146
00147
00150 DIPROPDWORD prop;
00151 prop.diph.dwSize = sizeof(DIPROPDWORD);
00152 prop.diph.dwHeaderSize = sizeof(DIPROPHEADER);
00153 prop.diph.dwHow = DIPH_DEVICE;
00154 prop.diph.dwObj = 0;
00155 prop.dwData = DIPROPAXISMODE_ABS;
00156 HRESULT r = mouse->_Mouse->SetProperty(DIPROP_AXISMODE, &prop.diph);
00157 nlassert(r == DI_OK);
00158
00159 mouse->_Mouse->Acquire();
00160 mouse->_hWnd = hwnd;
00161 return mouse.release();
00162 }
00163
00164
00165 float CDIMouse::getMouseSpeed() const
00166 {
00167 nlassert(_MessageMode == NormalMode);
00168 return _MouseSpeed;
00169 }
00170
00171
00172 const CRect &CDIMouse::getMouseFrame() const
00173 {
00174 nlassert(_MessageMode == NormalMode);
00175 return _MouseFrame;
00176 }
00177
00178
00179 uint CDIMouse::getDoubleClickDelay() const { return _DoubleClickDelay; }
00180
00181
00182 inline void CDIMouse::clampMouseAxis()
00183 {
00184 if (_MouseAxisMode[XAxis] == Clamped) clamp(_XMousePos, (sint32) _MouseFrame.X << 16, (sint32) (_MouseFrame.X + _MouseFrame.Width - 1) << 16);
00185 if (_MouseAxisMode[YAxis] == Clamped) clamp(_YMousePos, (sint32) _MouseFrame.Y << 16, (sint32) (_MouseFrame.X + _MouseFrame.Height - 1) << 16);
00186 }
00187
00188
00189 void CDIMouse::poll(CInputDeviceServer *dev)
00190 {
00191 nlassert(_Mouse);
00192 nlassert(_MouseBufferSize > 0);
00193 static std::vector<DIDEVICEOBJECTDATA> datas;
00194 datas.resize(_MouseBufferSize);
00195 DWORD numElements = _MouseBufferSize;
00196 HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
00197 if (result == DIERR_NOTACQUIRED || result == DIERR_INPUTLOST)
00198 {
00199 result = _Mouse->Acquire();
00200 HRESULT result = _Mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), &datas[0], &numElements, 0);
00201 if (result != DI_OK) return;
00202 }
00203 else if (result != DI_OK) return;
00204
00205 if (::IsWindowEnabled(_hWnd) && ::IsWindowVisible(_hWnd))
00206 {
00207 for(uint k = 0; k < numElements; ++k)
00208 {
00209 CDIEvent *die = new CDIEvent;
00210 die->Emitter = this;
00211 die->Datas = datas[k];
00212 dev->submitEvent(die);
00213 }
00214 }
00215 }
00216
00217
00218
00219 TMouseButton CDIMouse::buildMouseButtonFlags() const
00220 {
00221 return (TMouseButton) (
00222 _DIEventEmitter->buildKeyboardButtonFlags()
00223 | (_MouseButtons[0] ? leftButton : 0)
00224 | (_MouseButtons[1] ? rightButton : 0)
00225 | (_MouseButtons[2] ? middleButton : 0)
00226 );
00227 }
00228
00229
00230 TMouseButton CDIMouse::buildMouseSingleButtonFlags(uint button)
00231 {
00232 static const TMouseButton mb[] = { leftButton, rightButton, middleButton };
00233 nlassert(button < MaxNumMouseButtons);
00234 return (TMouseButton) (_DIEventEmitter->buildKeyboardButtonFlags() | mb[button]);
00235 }
00236
00237
00238 void CDIMouse::onButtonClicked(uint button, CEventServer *server, uint32 date)
00239 {
00240
00241 if (_LastMouseButtonClicked == (sint) button)
00242 {
00243 if (date - _MouseButtonsLastClickDate < _DoubleClickDelay)
00244 {
00245 CEventMouseDblClk *emdc
00246 = new CEventMouseDblClk((float) (_XMousePos >> 16),
00247 (float) (_YMousePos >> 16),
00248 buildMouseSingleButtonFlags(button),
00249 _DIEventEmitter);
00250 server->postEvent(emdc);
00251 _LastMouseButtonClicked = -1;
00252 }
00253 else
00254 {
00255 _MouseButtonsLastClickDate = date;
00256 }
00257 }
00258 else
00259 {
00260 _LastMouseButtonClicked = button;
00261 _MouseButtonsLastClickDate = date;
00262 }
00263 }
00264
00265
00266 void CDIMouse::processButton(uint button, bool pressed, CEventServer *server, uint32 date)
00267 {
00268 updateMove(server);
00269 if (pressed)
00270 {
00271 CEventMouseDown *emd =
00272 new CEventMouseDown((float) (_XMousePos >> 16),
00273 (float) (_YMousePos >> 16),
00274 buildMouseSingleButtonFlags(button),
00275 _DIEventEmitter);
00276 server->postEvent(emd);
00277 }
00278 else
00279 {
00280 CEventMouseUp *emu =
00281 new CEventMouseUp((float) (_XMousePos >> 16),
00282 (float) (_YMousePos >> 16),
00283 buildMouseSingleButtonFlags(button),
00284 _DIEventEmitter);
00285 server->postEvent(emu);
00286 onButtonClicked(button, server, date);
00287 }
00288 _MouseButtons[button] = pressed;
00289 }
00290
00291
00292 void CDIMouse::submit(IInputDeviceEvent *deviceEvent, CEventServer *server)
00293 {
00294 CDIEvent *die = safe_cast<CDIEvent *>(deviceEvent);
00295 bool pressed;
00296 switch(die->Datas.dwOfs)
00297 {
00298 case DIMOFS_X:
00299 {
00300 if (!_FirstX)
00301 {
00302 sint dep = (sint32) die->Datas.dwData - OldDIXPos;
00303 _XAcc += dep;
00304 }
00305 else
00306 {
00307 _FirstX = false;
00308 }
00309 OldDIXPos = (sint32) die->Datas.dwData;
00310 }
00311 break;
00312 case DIMOFS_Y:
00313 {
00314 if (!_FirstY)
00315 {
00316 sint dep = (sint32) die->Datas.dwData - OldDIYPos;
00317 _YAcc -= dep;
00318 }
00319 else
00320 {
00321 _FirstY = false;
00322 }
00323 OldDIYPos = (sint32) die->Datas.dwData;
00324 }
00325 break;
00326 case DIMOFS_Z:
00327 {
00328 updateMove(server);
00329 sint dep = die->Datas.dwData - OldDIZPos;
00330 OldDIZPos = (sint32) die->Datas.dwData;
00331 CEventMouseWheel *emw =
00332 new CEventMouseWheel((float) (_XMousePos >> 16),
00333 (float) (_XMousePos >> 16),
00334 buildMouseButtonFlags(),
00335 dep > 0,
00336 _DIEventEmitter);
00337 server->postEvent(emw);
00338 }
00339 break;
00340 case DIMOFS_BUTTON0:
00341 pressed = (die->Datas.dwData & 0x80) != 0;
00342 processButton(0, pressed, server, die->Datas.dwTimeStamp);
00343 break;
00344 case DIMOFS_BUTTON1:
00345 pressed = (die->Datas.dwData & 0x80) != 0;
00346 processButton(1, pressed, server, die->Datas.dwTimeStamp);
00347 break;
00348 case DIMOFS_BUTTON2:
00349 pressed = (die->Datas.dwData & 0x80) != 0;
00350 processButton(2, pressed, server, die->Datas.dwTimeStamp);
00351 break;
00352 default:
00353 return;
00354 break;
00355 }
00356 }
00357
00358
00359 void CDIMouse::updateMove(CEventServer *server)
00360 {
00361 if (_XAcc != 0 || _YAcc != 0)
00362 {
00363 if (_MessageMode == NormalMode)
00364 {
00365 _XMousePos += (sint32) (_MouseSpeed * _XAcc * (1 << 16));
00366 _YMousePos += (sint32) (_MouseSpeed * _YAcc * (1 << 16));
00367 clampMouseAxis();
00368 CEventMouseMove *emm = new CEventMouseMove(_XFactor * (float) (_XMousePos >> 16), _YFactor *(float) (_YMousePos >> 16), buildMouseButtonFlags(), _DIEventEmitter);
00369 server->postEvent(emm);
00370 }
00371 else
00372 {
00373 _XRaw += _XAcc;
00374 _YRaw += _YAcc;
00375 CGDMouseMove *emm = new CGDMouseMove(_DIEventEmitter, this, _XRaw, _YRaw);
00376 server->postEvent(emm);
00377 }
00378 _XAcc = _YAcc = 0;
00379 }
00380 }
00381
00382
00383 void CDIMouse::transitionOccured(CEventServer *server, const IInputDeviceEvent *)
00384 {
00385 updateMove(server);
00386 }
00387
00388
00389 void CDIMouse::setButton(uint button, bool pushed)
00390 {
00391 nlassert(button < MaxNumMouseButtons);
00392 _MouseButtons[button] = pushed;
00393 }
00394
00395
00396 bool CDIMouse::getButton(uint button) const
00397 {
00398 nlassert(button < MaxNumMouseButtons);
00399 return _MouseButtons[button];
00400 }
00401
00402
00403 void CDIMouse::setDoubleClickDelay(uint ms)
00404 {
00405 nlassert(ms > 0);
00406 _DoubleClickDelay = ms;
00407 }
00408
00409
00410 void CDIMouse::setMouseFrame(const CRect &rect)
00411 {
00412 nlassert(_MessageMode == NormalMode);
00413 _MouseFrame = rect;
00414 }
00415
00416
00417 void CDIMouse::setMessagesMode(TMessageMode mode)
00418 {
00419 nlassert(mode < AxisModeLast);
00420 _MessageMode = mode;
00421 if (mode == RawMode)
00422 {
00423 _FirstX = _FirstY = false;
00424 }
00425 }
00426
00427
00428 }
00429
00430 #endif // NL_OS_WINDOWS
00431
00432