BsInput.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #include "Input/BsInput.h"
  4. #include "Input/BsMouse.h"
  5. #include "Input/BsKeyboard.h"
  6. #include "Input/BsGamepad.h"
  7. #include "Utility/BsTime.h"
  8. #include "Math/BsMath.h"
  9. #include "Managers/BsRenderWindowManager.h"
  10. #include "BsCoreApplication.h"
  11. using namespace std::placeholders;
  12. namespace bs
  13. {
  14. // Note: Input polling methods for button/axis could be re-written so their query immediate state
  15. // instead of returning cached state from event callbacks. This /might/ result in even less input lag?
  16. const int Input::HISTORY_BUFFER_SIZE = 10; // Size of buffer used for input smoothing
  17. const float Input::WEIGHT_MODIFIER = 0.5f;
  18. Input::DeviceData::DeviceData()
  19. {
  20. for (UINT32 i = 0; i < BC_Count; i++)
  21. keyStates[i] = ButtonState::Off;
  22. }
  23. Input::Input()
  24. : mPointerDoubleClicked(false), mLastPositionSet(false), mMouseScroll(0.0f), mMouseSmoothingEnabled(false)
  25. , mMouse(nullptr), mKeyboard(nullptr)
  26. {
  27. SPtr<RenderWindow> primaryWindow = gCoreApplication().getPrimaryWindow();
  28. primaryWindow->getCustomAttribute("WINDOW", &mWindowHandle);
  29. // Subscribe to events
  30. mCharInputConn = Platform::onCharInput.connect(std::bind(&Input::charInput, this, _1));
  31. mCursorMovedConn = Platform::onCursorMoved.connect(std::bind(&Input::cursorMoved, this, _1, _2));
  32. mCursorPressedConn = Platform::onCursorButtonPressed.connect(std::bind(&Input::cursorPressed, this, _1, _2, _3));
  33. mCursorReleasedConn = Platform::onCursorButtonReleased.connect(std::bind(&Input::cursorReleased, this, _1, _2, _3));
  34. mCursorDoubleClickConn = Platform::onCursorDoubleClick.connect(std::bind(&Input::cursorDoubleClick, this, _1, _2));
  35. mInputCommandConn = Platform::onInputCommand.connect(std::bind(&Input::inputCommandEntered, this, _1));
  36. mMouseWheelScrolledConn = Platform::onMouseWheelScrolled.connect(std::bind(&Input::mouseWheelScrolled, this, _1));
  37. RenderWindowManager::instance().onFocusGained.connect(std::bind(&Input::inputWindowChanged, this, _1));
  38. RenderWindowManager::instance().onFocusLost.connect(std::bind(&Input::inputFocusLost, this));
  39. for (int i = 0; i < 3; i++)
  40. mPointerButtonStates[i] = ButtonState::Off;
  41. // Mouse smoothing
  42. mMouseSampleAccumulator[0] = 0;
  43. mMouseSampleAccumulator[1] = 0;
  44. mTotalMouseSamplingTime[0] = 1.0f / 125.0f; // Use 125Hz as initial pooling rate for mice
  45. mTotalMouseSamplingTime[1] = 1.0f / 125.0f;
  46. mTotalMouseNumSamples[0] = 1;
  47. mTotalMouseNumSamples[1] = 1;
  48. mMouseSmoothedAxis[0] = 0.0f;
  49. mMouseSmoothedAxis[1] = 0.0f;
  50. mMouseZeroTime[0] = 0.0f;
  51. mMouseZeroTime[1] = 0.0f;
  52. // Raw input
  53. initRawInput();
  54. }
  55. Input::~Input()
  56. {
  57. cleanUpRawInput();
  58. mCharInputConn.disconnect();
  59. mCursorMovedConn.disconnect();
  60. mCursorPressedConn.disconnect();
  61. mCursorReleasedConn.disconnect();
  62. mCursorDoubleClickConn.disconnect();
  63. mInputCommandConn.disconnect();
  64. mMouseWheelScrolledConn.disconnect();
  65. }
  66. void Input::_update()
  67. {
  68. // Toggle states only remain active for a single frame before they are transitioned
  69. // into permanent state
  70. for (auto& deviceData : mDevices)
  71. {
  72. for (UINT32 i = 0; i < BC_Count; i++)
  73. {
  74. if (deviceData.keyStates[i] == ButtonState::ToggledOff || deviceData.keyStates[i] == ButtonState::ToggledOnOff)
  75. deviceData.keyStates[i] = ButtonState::Off;
  76. else if (deviceData.keyStates[i] == ButtonState::ToggledOn)
  77. deviceData.keyStates[i] = ButtonState::On;
  78. }
  79. UINT32 numAxes = (UINT32)deviceData.axes.size();
  80. for (UINT32 i = 0; i < numAxes; i++)
  81. deviceData.axes[i] = 0.0f;
  82. }
  83. for (UINT32 i = 0; i < 3; i++)
  84. {
  85. if (mPointerButtonStates[i] == ButtonState::ToggledOff || mPointerButtonStates[i] == ButtonState::ToggledOnOff)
  86. mPointerButtonStates[i] = ButtonState::Off;
  87. else if (mPointerButtonStates[i] == ButtonState::ToggledOn)
  88. mPointerButtonStates[i] = ButtonState::On;
  89. }
  90. mPointerDelta = Vector2I::ZERO; // Reset delta in case we don't receive any mouse input this frame
  91. mPointerDoubleClicked = false;
  92. // Capture raw input
  93. if (mMouse != nullptr)
  94. mMouse->capture();
  95. if (mKeyboard != nullptr)
  96. mKeyboard->capture();
  97. for (auto& gamepad : mGamepads)
  98. gamepad->capture();
  99. float rawXValue = 0.0f;
  100. float rawYValue = 0.0f;
  101. // Smooth mouse axes if needed
  102. if (mMouseSmoothingEnabled)
  103. {
  104. rawXValue = smoothMouse((float)mMouseSampleAccumulator[0], 0);
  105. rawYValue = smoothMouse((float)mMouseSampleAccumulator[1], 1);
  106. }
  107. else
  108. {
  109. rawXValue = (float)mMouseSampleAccumulator[0];
  110. rawYValue = (float)mMouseSampleAccumulator[1];
  111. }
  112. rawXValue *= 0.1f;
  113. rawYValue *= 0.1f;
  114. mMouseSampleAccumulator[0] = 0;
  115. mMouseSampleAccumulator[1] = 0;
  116. axisMoved(0, -rawXValue, (UINT32)InputAxis::MouseX);
  117. axisMoved(0, -rawYValue, (UINT32)InputAxis::MouseY);
  118. }
  119. void Input::_triggerCallbacks()
  120. {
  121. Vector2I pointerPos;
  122. float mouseScroll;
  123. OSPointerButtonStates pointerState;
  124. {
  125. Lock lock(mMutex);
  126. std::swap(mQueuedEvents[0], mQueuedEvents[1]);
  127. std::swap(mButtonDownEvents[0], mButtonDownEvents[1]);
  128. std::swap(mButtonUpEvents[0], mButtonUpEvents[1]);
  129. std::swap(mPointerPressedEvents[0], mPointerPressedEvents[1]);
  130. std::swap(mPointerReleasedEvents[0], mPointerReleasedEvents[1]);
  131. std::swap(mPointerDoubleClickEvents[0], mPointerDoubleClickEvents[1]);
  132. std::swap(mTextInputEvents[0], mTextInputEvents[1]);
  133. std::swap(mCommandEvents[0], mCommandEvents[1]);
  134. pointerPos = mPointerPosition;
  135. mouseScroll = mMouseScroll;
  136. pointerState = mPointerState;
  137. mMouseScroll = 0.0f;
  138. }
  139. if(pointerPos != mLastPointerPosition || mouseScroll != 0.0f)
  140. {
  141. PointerEvent event;
  142. event.alt = false;
  143. event.shift = pointerState.shift;
  144. event.control = pointerState.ctrl;
  145. event.buttonStates[0] = pointerState.mouseButtons[0];
  146. event.buttonStates[1] = pointerState.mouseButtons[1];
  147. event.buttonStates[2] = pointerState.mouseButtons[2];
  148. event.mouseWheelScrollAmount = mouseScroll;
  149. event.type = PointerEventType::CursorMoved;
  150. event.screenPos = pointerPos;
  151. onPointerMoved(event);
  152. if (mLastPositionSet)
  153. mPointerDelta = event.screenPos - mLastPointerPosition;
  154. mLastPointerPosition = event.screenPos;
  155. mLastPositionSet = true;
  156. }
  157. for (auto& event : mQueuedEvents[1])
  158. {
  159. switch (event.type)
  160. {
  161. case EventType::ButtonDown:
  162. {
  163. const ButtonEvent& eventData = mButtonDownEvents[1][event.idx];
  164. mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOn;
  165. onButtonDown(mButtonDownEvents[1][event.idx]);
  166. }
  167. break;
  168. case EventType::ButtonUp:
  169. {
  170. const ButtonEvent& eventData = mButtonUpEvents[1][event.idx];
  171. while (eventData.deviceIdx >= (UINT32)mDevices.size())
  172. mDevices.push_back(DeviceData());
  173. if (mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] == ButtonState::ToggledOn)
  174. mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOnOff;
  175. else
  176. mDevices[eventData.deviceIdx].keyStates[eventData.buttonCode & 0x0000FFFF] = ButtonState::ToggledOff;
  177. onButtonUp(mButtonUpEvents[1][event.idx]);
  178. }
  179. break;
  180. case EventType::PointerDown:
  181. {
  182. const PointerEvent& eventData = mPointerPressedEvents[1][event.idx];
  183. mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOn;
  184. onPointerPressed(eventData);
  185. }
  186. break;
  187. case EventType::PointerUp:
  188. {
  189. const PointerEvent& eventData = mPointerReleasedEvents[1][event.idx];
  190. if (mPointerButtonStates[(UINT32)eventData.button] == ButtonState::ToggledOn)
  191. mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOnOff;
  192. else
  193. mPointerButtonStates[(UINT32)eventData.button] = ButtonState::ToggledOff;
  194. onPointerReleased(eventData);
  195. }
  196. break;
  197. case EventType::PointerDoubleClick:
  198. mPointerDoubleClicked = true;
  199. onPointerDoubleClick(mPointerDoubleClickEvents[1][event.idx]);
  200. break;
  201. case EventType::TextInput:
  202. onCharInput(mTextInputEvents[1][event.idx]);
  203. break;
  204. case EventType::Command:
  205. onInputCommand(mCommandEvents[1][event.idx]);
  206. break;
  207. default:
  208. break;
  209. }
  210. }
  211. mQueuedEvents[1].clear();
  212. mButtonDownEvents[1].clear();
  213. mButtonUpEvents[1].clear();
  214. mPointerPressedEvents[1].clear();
  215. mPointerReleasedEvents[1].clear();
  216. mPointerDoubleClickEvents[1].clear();
  217. mTextInputEvents[1].clear();
  218. mCommandEvents[1].clear();
  219. }
  220. void Input::inputWindowChanged(RenderWindow& win)
  221. {
  222. UINT64 hWnd = 0;
  223. win.getCustomAttribute("WINDOW", &hWnd);
  224. mKeyboard->changeCaptureContext(hWnd);
  225. mMouse->changeCaptureContext(hWnd);
  226. for (auto& gamepad : mGamepads)
  227. gamepad->changeCaptureContext(hWnd);
  228. }
  229. void Input::inputFocusLost()
  230. {
  231. mKeyboard->changeCaptureContext((UINT64)-1);
  232. mMouse->changeCaptureContext((UINT64)-1);
  233. for (auto& gamepad : mGamepads)
  234. gamepad->changeCaptureContext((UINT64)-1);
  235. }
  236. void Input::_notifyMouseMoved(INT32 relX, INT32 relY, INT32 relZ)
  237. {
  238. mMouseSampleAccumulator[0] += relX;
  239. mMouseSampleAccumulator[1] += relY;
  240. mTotalMouseNumSamples[0] += Math::roundToInt(Math::abs((float)relX));
  241. mTotalMouseNumSamples[1] += Math::roundToInt(Math::abs((float)relY));
  242. // Update sample times used for determining sampling rate. But only if something was
  243. // actually sampled, and only if this isn't the first non-zero sample.
  244. if (mLastMouseUpdateFrame != gTime().getFrameIdx())
  245. {
  246. if (relX != 0 && !Math::approxEquals(mMouseSmoothedAxis[0], 0.0f))
  247. mTotalMouseSamplingTime[0] += gTime().getFrameDelta();
  248. if (relY != 0 && !Math::approxEquals(mMouseSmoothedAxis[1], 0.0f))
  249. mTotalMouseSamplingTime[1] += gTime().getFrameDelta();
  250. mLastMouseUpdateFrame = gTime().getFrameIdx();
  251. }
  252. axisMoved(0, (float)relZ, (UINT32)InputAxis::MouseZ);
  253. }
  254. void Input::_notifyAxisMoved(UINT32 gamepadIdx, UINT32 axisIdx, INT32 value)
  255. {
  256. // Move axis values into [-1.0f, 1.0f] range
  257. float axisRange = Math::abs((float)Gamepad::MAX_AXIS) + Math::abs((float)Gamepad::MIN_AXIS);
  258. float axisValue = ((value + Math::abs((float)Gamepad::MIN_AXIS)) / axisRange) * 2.0f - 1.0f;
  259. axisMoved(gamepadIdx, axisValue, axisIdx);
  260. }
  261. void Input::_notifyButtonPressed(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
  262. {
  263. buttonDown(deviceIdx, code, timestamp - mTimestampClockOffset);
  264. }
  265. void Input::_notifyButtonReleased(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
  266. {
  267. buttonUp(deviceIdx, code, timestamp - mTimestampClockOffset);
  268. }
  269. void Input::buttonDown(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
  270. {
  271. Lock lock(mMutex);
  272. while (deviceIdx >= (UINT32)mDevices.size())
  273. mDevices.push_back(DeviceData());
  274. ButtonEvent btnEvent;
  275. btnEvent.buttonCode = code;
  276. btnEvent.timestamp = timestamp;
  277. btnEvent.deviceIdx = deviceIdx;
  278. mQueuedEvents[0].push_back(QueuedEvent(EventType::ButtonDown, (UINT32)mButtonDownEvents[0].size()));
  279. mButtonDownEvents[0].push_back(btnEvent);
  280. }
  281. void Input::buttonUp(UINT32 deviceIdx, ButtonCode code, UINT64 timestamp)
  282. {
  283. Lock lock(mMutex);
  284. ButtonEvent btnEvent;
  285. btnEvent.buttonCode = code;
  286. btnEvent.timestamp = timestamp;
  287. btnEvent.deviceIdx = deviceIdx;
  288. mQueuedEvents[0].push_back(QueuedEvent(EventType::ButtonUp, (UINT32)mButtonUpEvents[0].size()));
  289. mButtonUpEvents[0].push_back(btnEvent);
  290. }
  291. void Input::axisMoved(UINT32 deviceIdx, float value, UINT32 axis)
  292. {
  293. // Note: This method must only ever be called from the main thread, as we don't lock access to axis data
  294. while (deviceIdx >= (UINT32)mDevices.size())
  295. mDevices.push_back(DeviceData());
  296. Vector<float>& axes = mDevices[deviceIdx].axes;
  297. while (axis >= (UINT32)axes.size())
  298. axes.push_back(0.0f);
  299. mDevices[deviceIdx].axes[axis] = value;
  300. }
  301. void Input::cursorMoved(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
  302. {
  303. Lock lock(mMutex);
  304. mPointerPosition = cursorPos;
  305. mPointerState = btnStates;
  306. }
  307. void Input::cursorPressed(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates)
  308. {
  309. Lock lock(mMutex);
  310. PointerEvent event;
  311. event.alt = false;
  312. event.shift = btnStates.shift;
  313. event.control = btnStates.ctrl;
  314. event.buttonStates[0] = btnStates.mouseButtons[0];
  315. event.buttonStates[1] = btnStates.mouseButtons[1];
  316. event.buttonStates[2] = btnStates.mouseButtons[2];
  317. switch(button)
  318. {
  319. case OSMouseButton::Left:
  320. event.button = PointerEventButton::Left;
  321. break;
  322. case OSMouseButton::Middle:
  323. event.button = PointerEventButton::Middle;
  324. break;
  325. case OSMouseButton::Right:
  326. event.button = PointerEventButton::Right;
  327. break;
  328. default:
  329. break;
  330. }
  331. event.screenPos = cursorPos;
  332. event.type = PointerEventType::ButtonPressed;
  333. mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerDown, (UINT32)mPointerPressedEvents[0].size()));
  334. mPointerPressedEvents[0].push_back(event);
  335. }
  336. void Input::cursorReleased(const Vector2I& cursorPos, OSMouseButton button, const OSPointerButtonStates& btnStates)
  337. {
  338. Lock lock(mMutex);
  339. PointerEvent event;
  340. event.alt = false;
  341. event.shift = btnStates.shift;
  342. event.control = btnStates.ctrl;
  343. event.buttonStates[0] = btnStates.mouseButtons[0];
  344. event.buttonStates[1] = btnStates.mouseButtons[1];
  345. event.buttonStates[2] = btnStates.mouseButtons[2];
  346. switch(button)
  347. {
  348. case OSMouseButton::Left:
  349. event.button = PointerEventButton::Left;
  350. break;
  351. case OSMouseButton::Middle:
  352. event.button = PointerEventButton::Middle;
  353. break;
  354. case OSMouseButton::Right:
  355. event.button = PointerEventButton::Right;
  356. break;
  357. default:
  358. break;
  359. }
  360. event.screenPos = cursorPos;
  361. event.type = PointerEventType::ButtonReleased;
  362. mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerUp, (UINT32)mPointerReleasedEvents[0].size()));
  363. mPointerReleasedEvents[0].push_back(event);
  364. }
  365. void Input::cursorDoubleClick(const Vector2I& cursorPos, const OSPointerButtonStates& btnStates)
  366. {
  367. Lock lock(mMutex);
  368. PointerEvent event;
  369. event.alt = false;
  370. event.shift = btnStates.shift;
  371. event.control = btnStates.ctrl;
  372. event.buttonStates[0] = btnStates.mouseButtons[0];
  373. event.buttonStates[1] = btnStates.mouseButtons[1];
  374. event.buttonStates[2] = btnStates.mouseButtons[2];
  375. event.button = PointerEventButton::Left;
  376. event.screenPos = cursorPos;
  377. event.type = PointerEventType::DoubleClick;
  378. mQueuedEvents[0].push_back(QueuedEvent(EventType::PointerDoubleClick, (UINT32)mPointerDoubleClickEvents[0].size()));
  379. mPointerDoubleClickEvents[0].push_back(event);
  380. }
  381. void Input::inputCommandEntered(InputCommandType commandType)
  382. {
  383. Lock lock(mMutex);
  384. mQueuedEvents[0].push_back(QueuedEvent(EventType::Command, (UINT32)mCommandEvents[0].size()));
  385. mCommandEvents[0].push_back(commandType);
  386. }
  387. void Input::mouseWheelScrolled(float scrollPos)
  388. {
  389. Lock lock(mMutex);
  390. mMouseScroll = scrollPos;
  391. }
  392. void Input::charInput(UINT32 chr)
  393. {
  394. Lock lock(mMutex);
  395. TextInputEvent textInputEvent;
  396. textInputEvent.textChar = chr;
  397. mQueuedEvents[0].push_back(QueuedEvent(EventType::TextInput, (UINT32)mTextInputEvents[0].size()));
  398. mTextInputEvents[0].push_back(textInputEvent);
  399. }
  400. float Input::getAxisValue(UINT32 type, UINT32 deviceIdx) const
  401. {
  402. if (deviceIdx >= (UINT32)mDevices.size())
  403. return 0.0f;
  404. const Vector<float>& axes = mDevices[deviceIdx].axes;
  405. if (type >= (UINT32)axes.size())
  406. return 0.0f;
  407. return axes[type];
  408. }
  409. bool Input::isButtonHeld(ButtonCode button, UINT32 deviceIdx) const
  410. {
  411. if (deviceIdx >= (UINT32)mDevices.size())
  412. return false;
  413. return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::On ||
  414. mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn ||
  415. mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
  416. }
  417. bool Input::isButtonUp(ButtonCode button, UINT32 deviceIdx) const
  418. {
  419. if (deviceIdx >= (UINT32)mDevices.size())
  420. return false;
  421. return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOff ||
  422. mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
  423. }
  424. bool Input::isButtonDown(ButtonCode button, UINT32 deviceIdx) const
  425. {
  426. if (deviceIdx >= (UINT32)mDevices.size())
  427. return false;
  428. return mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOn ||
  429. mDevices[deviceIdx].keyStates[button & 0x0000FFFF] == ButtonState::ToggledOnOff;
  430. }
  431. bool Input::isPointerButtonHeld(PointerEventButton pointerButton) const
  432. {
  433. return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::On ||
  434. mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn ||
  435. mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
  436. }
  437. bool Input::isPointerButtonUp(PointerEventButton pointerButton) const
  438. {
  439. return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOff ||
  440. mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
  441. }
  442. bool Input::isPointerButtonDown(PointerEventButton pointerButton) const
  443. {
  444. return mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOn ||
  445. mPointerButtonStates[(UINT32)pointerButton] == ButtonState::ToggledOnOff;
  446. }
  447. bool Input::isPointerDoubleClicked() const
  448. {
  449. return mPointerDoubleClicked;
  450. }
  451. Vector2I Input::getPointerPosition() const
  452. {
  453. return mPointerPosition;
  454. }
  455. String Input::getDeviceName(InputDevice type, UINT32 idx)
  456. {
  457. switch(type)
  458. {
  459. case InputDevice::Keyboard:
  460. if (mKeyboard != nullptr && idx == 0)
  461. return mKeyboard->getName();
  462. return StringUtil::BLANK;
  463. case InputDevice::Mouse:
  464. if (mMouse != nullptr && idx == 0)
  465. return mMouse->getName();
  466. return StringUtil::BLANK;
  467. case InputDevice::Gamepad:
  468. if (idx < (UINT32)mGamepads.size())
  469. return mGamepads[idx]->getName();
  470. return StringUtil::BLANK;
  471. default:
  472. return StringUtil::BLANK;
  473. }
  474. }
  475. void Input::setMouseSmoothing(bool enable)
  476. {
  477. mMouseSmoothingEnabled = enable;
  478. }
  479. float Input::smoothMouse(float value, UINT32 idx)
  480. {
  481. UINT32 sampleCount = 1;
  482. float deltaTime = gTime().getFrameDelta();
  483. if (deltaTime < 0.25f)
  484. {
  485. float secondsPerSample = mTotalMouseSamplingTime[idx] / mTotalMouseNumSamples[idx];
  486. if (value == 0.0f)
  487. {
  488. mMouseZeroTime[idx] += deltaTime;
  489. if (mMouseZeroTime[idx] < secondsPerSample)
  490. value = mMouseSmoothedAxis[idx] * deltaTime / secondsPerSample;
  491. else
  492. mMouseSmoothedAxis[idx] = 0;
  493. }
  494. else
  495. {
  496. mMouseZeroTime[idx] = 0;
  497. if (mMouseSmoothedAxis[idx] != 0)
  498. {
  499. if (deltaTime < secondsPerSample * (sampleCount + 1))
  500. value = value * deltaTime / (secondsPerSample * sampleCount);
  501. else
  502. sampleCount = Math::roundToInt(deltaTime / secondsPerSample);
  503. }
  504. mMouseSmoothedAxis[idx] = value / sampleCount;
  505. }
  506. }
  507. else
  508. {
  509. mMouseSmoothedAxis[idx] = 0.0f;
  510. mMouseZeroTime[idx] = 0.0f;
  511. }
  512. return value;
  513. }
  514. Input& gInput()
  515. {
  516. return Input::instance();
  517. }
  518. }