BsWin32Mouse.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. DIDEVICEOBJECTDATA diBuff[DI_BUFFER_SIZE_MOUSE];
  78. DWORD numEntries = DI_BUFFER_SIZE_MOUSE;
  79. HRESULT hr = m->mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diBuff, &numEntries, 0);
  80. if (hr != DI_OK)
  81. {
  82. hr = m->mouse->Acquire();
  83. while (hr == DIERR_INPUTLOST)
  84. hr = m->mouse->Acquire();
  85. hr = m->mouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), diBuff, &numEntries, 0);
  86. if (FAILED(hr))
  87. return;
  88. }
  89. INT32 relX, relY, relZ;
  90. relX = relY = relZ = 0;
  91. bool axesMoved = false;
  92. for (UINT32 i = 0; i < numEntries; ++i)
  93. {
  94. switch (diBuff[i].dwOfs)
  95. {
  96. case DIMOFS_BUTTON0:
  97. doMouseClick(mOwner, BC_MOUSE_LEFT, diBuff[i]);
  98. break;
  99. case DIMOFS_BUTTON1:
  100. doMouseClick(mOwner, BC_MOUSE_RIGHT, diBuff[i]);
  101. break;
  102. case DIMOFS_BUTTON2:
  103. doMouseClick(mOwner, BC_MOUSE_MIDDLE, diBuff[i]);
  104. break;
  105. case DIMOFS_BUTTON3:
  106. doMouseClick(mOwner, BC_MOUSE_BTN4, diBuff[i]);
  107. break;
  108. case DIMOFS_BUTTON4:
  109. doMouseClick(mOwner, BC_MOUSE_BTN5, diBuff[i]);
  110. break;
  111. case DIMOFS_BUTTON5:
  112. doMouseClick(mOwner, BC_MOUSE_BTN6, diBuff[i]);
  113. break;
  114. case DIMOFS_BUTTON6:
  115. doMouseClick(mOwner, BC_MOUSE_BTN7, diBuff[i]);
  116. break;
  117. case DIMOFS_BUTTON7:
  118. doMouseClick(mOwner, BC_MOUSE_BTN8, diBuff[i]);
  119. break;
  120. case DIMOFS_X:
  121. relX += diBuff[i].dwData;
  122. axesMoved = true;
  123. break;
  124. case DIMOFS_Y:
  125. relY += diBuff[i].dwData;
  126. axesMoved = true;
  127. break;
  128. case DIMOFS_Z:
  129. relZ += diBuff[i].dwData;
  130. axesMoved = true;
  131. break;
  132. default: break;
  133. }
  134. }
  135. if (axesMoved)
  136. mOwner->_notifyMouseMoved(relX, relY, relZ);
  137. }
  138. void Mouse::changeCaptureContext(UINT64 windowHandle)
  139. {
  140. HWND newhWnd = (HWND)windowHandle;
  141. if(m->hWnd != newhWnd)
  142. {
  143. releaseDirectInput(m);
  144. initializeDirectInput(m, newhWnd);
  145. }
  146. }
  147. }