BsInput.cpp 18 KB

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