BsWin32Mouse.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Input/BsMouse.h"
  4. #include "Input/BsInput.h"
  5. #include "Win32/BsWin32Input.h"
  6. #include "Error/BsException.h"
  7. namespace bs
  8. {
  9. /** Contains private data for the Win32 Mouse implementation. */
  10. struct Mouse::Pimpl
  11. {
  12. IDirectInput8* directInput;
  13. IDirectInputDevice8* mouse;
  14. DWORD coopSettings;
  15. HWND hWnd;
  16. };
  17. /**
  18. * Initializes DirectInput mouse device for a window with the specified handle. Only input from that window will be
  19. * reported.
  20. */
  21. void initializeDirectInput(Mouse::Pimpl* m, HWND hWnd)
  22. {
  23. DIPROPDWORD dipdw;
  24. dipdw.diph.dwSize = sizeof(DIPROPDWORD);
  25. dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
  26. dipdw.diph.dwObj = 0;
  27. dipdw.diph.dwHow = DIPH_DEVICE;
  28. dipdw.dwData = DI_BUFFER_SIZE_MOUSE;
  29. if (FAILED(m->directInput->CreateDevice(GUID_SysMouse, &m->mouse, nullptr)))
  30. BS_EXCEPT(InternalErrorException, "DirectInput mouse init: Failed to create device.");
  31. if (FAILED(m->mouse->SetDataFormat(&c_dfDIMouse2)))
  32. BS_EXCEPT(InternalErrorException, "DirectInput mouse init: Failed to set format.");
  33. if (FAILED(m->mouse->SetCooperativeLevel(hWnd, m->coopSettings)))
  34. BS_EXCEPT(InternalErrorException, "DirectInput mouse init: Failed to set coop level.");
  35. if (FAILED(m->mouse->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph)))
  36. BS_EXCEPT(InternalErrorException, "DirectInput mouse init: Failed to set property.");
  37. HRESULT hr = m->mouse->Acquire();
  38. if (FAILED(hr) && hr != DIERR_OTHERAPPHASPRIO)
  39. BS_EXCEPT(InternalErrorException, "DirectInput mouse init: Failed to acquire device.");
  40. m->hWnd = hWnd;
  41. }
  42. /** Releases DirectInput resources for the provided device */
  43. void releaseDirectInput(Mouse::Pimpl* m)
  44. {
  45. if(m->mouse)
  46. {
  47. m->mouse->Unacquire();
  48. m->mouse->Release();
  49. m->mouse = nullptr;
  50. }
  51. }
  52. /** Notifies the input handler that a mouse press or release occurred. Triggers an event in the input handler. */
  53. void doMouseClick(Input* owner, ButtonCode mouseButton, const DIDEVICEOBJECTDATA& data)
  54. {
  55. if (data.dwData & 0x80)
  56. owner->_notifyButtonPressed(0, mouseButton, data.dwTimeStamp);
  57. else
  58. owner->_notifyButtonReleased(0, mouseButton, data.dwTimeStamp);
  59. }
  60. Mouse::Mouse(const String& name, Input* owner)
  61. : mName(name), mOwner(owner)
  62. {
  63. InputPrivateData* pvtData = owner->_getPrivateData();
  64. m = bs_new<Pimpl>();
  65. m->directInput = pvtData->directInput;
  66. m->coopSettings = pvtData->mouseSettings;
  67. m->mouse = nullptr;
  68. initializeDirectInput(m, (HWND)owner->_getWindowHandle());
  69. }
  70. Mouse::~Mouse()
  71. {
  72. releaseDirectInput(m);
  73. bs_delete(m);
  74. }
  75. void Mouse::capture()
  76. {
  77. if (m->mouse == nullptr)
  78. return;
  79. DIDEVICEOBJECTDATA diBuff[DI_BUFFER_SIZE_MOUSE];
  80. DWORD numEntries = DI_BUFFER_SIZE_MOUSE;
  81. HRESULT hr = m->mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diBuff, &numEntries, 0);
  82. if (hr != DI_OK)
  83. {
  84. hr = m->mouse->Acquire();
  85. while (hr == DIERR_INPUTLOST)
  86. hr = m->mouse->Acquire();
  87. hr = m->mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diBuff, &numEntries, 0);
  88. if (FAILED(hr))
  89. return;
  90. }
  91. INT32 relX, relY, relZ;
  92. relX = relY = relZ = 0;
  93. bool axesMoved = false;
  94. for (UINT32 i = 0; i < numEntries; ++i)
  95. {
  96. switch (diBuff[i].dwOfs)
  97. {
  98. case DIMOFS_BUTTON0:
  99. doMouseClick(mOwner, BC_MOUSE_LEFT, diBuff[i]);
  100. break;
  101. case DIMOFS_BUTTON1:
  102. doMouseClick(mOwner, BC_MOUSE_RIGHT, diBuff[i]);
  103. break;
  104. case DIMOFS_BUTTON2:
  105. doMouseClick(mOwner, BC_MOUSE_MIDDLE, diBuff[i]);
  106. break;
  107. case DIMOFS_BUTTON3:
  108. doMouseClick(mOwner, BC_MOUSE_BTN4, diBuff[i]);
  109. break;
  110. case DIMOFS_BUTTON4:
  111. doMouseClick(mOwner, BC_MOUSE_BTN5, diBuff[i]);
  112. break;
  113. case DIMOFS_BUTTON5:
  114. doMouseClick(mOwner, BC_MOUSE_BTN6, diBuff[i]);
  115. break;
  116. case DIMOFS_BUTTON6:
  117. doMouseClick(mOwner, BC_MOUSE_BTN7, diBuff[i]);
  118. break;
  119. case DIMOFS_BUTTON7:
  120. doMouseClick(mOwner, BC_MOUSE_BTN8, diBuff[i]);
  121. break;
  122. case DIMOFS_X:
  123. relX += diBuff[i].dwData;
  124. axesMoved = true;
  125. break;
  126. case DIMOFS_Y:
  127. relY += diBuff[i].dwData;
  128. axesMoved = true;
  129. break;
  130. case DIMOFS_Z:
  131. relZ += diBuff[i].dwData;
  132. axesMoved = true;
  133. break;
  134. default: break;
  135. }
  136. }
  137. if (axesMoved)
  138. mOwner->_notifyMouseMoved(relX, relY, relZ);
  139. }
  140. void Mouse::changeCaptureContext(UINT64 windowHandle)
  141. {
  142. HWND newhWnd = (HWND)windowHandle;
  143. if(m->hWnd != newhWnd)
  144. {
  145. releaseDirectInput(m);
  146. if (windowHandle != (UINT64)-1)
  147. initializeDirectInput(m, newhWnd);
  148. else
  149. m->hWnd = (HWND)-1;
  150. }
  151. }
  152. }