BsInputHandlerOIS.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. //__________________________ Banshee Project - A modern game development toolkit _________________________________//
  2. //_____________________________________ www.banshee-project.com __________________________________________________//
  3. //________________________ Copyright (c) 2014 Marko Pintera. All rights reserved. ________________________________//
  4. #include "BsInputHandlerOIS.h"
  5. #include "BsVector2I.h"
  6. #include "OIS/OISException.h"
  7. #include "BsRenderWindow.h"
  8. #include "BsTime.h"
  9. #include "BsMath.h"
  10. #include "BsDebug.h"
  11. namespace BansheeEngine
  12. {
  13. const UINT32 InputHandlerOIS::MOUSE_DPI = 800;
  14. const float InputHandlerOIS::MOUSE_MAX = 0.05f;
  15. const float InputHandlerOIS::MOUSE_MAX_TIME = 0.020f; // 20 ms
  16. const float InputHandlerOIS::MOUSE_MAX_SAMPLING_RATE = 0.006f; // 6ms
  17. GamepadEventListener::GamepadEventListener(InputHandlerOIS* parentHandler, UINT32 joystickIdx)
  18. :mParentHandler(parentHandler), mGamepadIdx(joystickIdx)
  19. { }
  20. bool GamepadEventListener::buttonPressed(const OIS::JoyStickEvent& arg, int button)
  21. {
  22. ButtonCode bc = InputHandlerOIS::gamepadButtonToButtonCode(button);
  23. // Note: No timestamps for gamepad buttons, but they shouldn't be used for anything anyway
  24. mParentHandler->onButtonDown(mGamepadIdx, bc, 0);
  25. return true;
  26. }
  27. bool GamepadEventListener::buttonReleased(const OIS::JoyStickEvent& arg, int button)
  28. {
  29. ButtonCode bc = InputHandlerOIS::gamepadButtonToButtonCode(button);
  30. // Note: No timestamps for gamepad buttons, but they shouldn't be used for anything anyway
  31. mParentHandler->onButtonUp(mGamepadIdx, bc, 0);
  32. return true;
  33. }
  34. bool GamepadEventListener::axisMoved(const OIS::JoyStickEvent& arg, int axis)
  35. {
  36. // Move axis values into [-1.0f, 1.0f] range
  37. float axisRange = Math::abs((float)OIS::JoyStick::MAX_AXIS) + Math::abs((float)OIS::JoyStick::MIN_AXIS);
  38. INT32 axisRel = arg.state.mAxes[axis].rel;
  39. INT32 axisAbs = arg.state.mAxes[axis].abs;
  40. RawAxisState axisState;
  41. axisState.rel = ((axisRel + Math::abs((float)OIS::JoyStick::MIN_AXIS)) / axisRange) * 2.0f - 1.0f;
  42. axisState.abs = ((axisAbs + Math::abs((float)OIS::JoyStick::MIN_AXIS)) / axisRange) * 2.0f - 1.0f;
  43. mParentHandler->onAxisMoved(mGamepadIdx, axisState, (UINT32)axis);
  44. return true;
  45. }
  46. InputHandlerOIS::InputHandlerOIS(unsigned int hWnd)
  47. :mInputManager(nullptr), mKeyboard(nullptr), mMouse(nullptr), mTimestampClockOffset(0),
  48. mLastMouseUpdateFrame(0), mMouseSampleCounter(0.0f)
  49. {
  50. mMouseSampleAccumulator[0] = 0;
  51. mMouseSampleAccumulator[1] = 0;
  52. mTotalMouseSamplingTime[0] = 1.0f / 125.0f; // Use 125Hz as initial pooling rate for mice
  53. mTotalMouseSamplingTime[1] = 1.0f / 125.0f;
  54. mTotalMouseNumSamples[0] = 1;
  55. mTotalMouseNumSamples[1] = 1;
  56. mMouseSmoothedAxis[0] = 0.0f;
  57. mMouseSmoothedAxis[1] = 0.0f;
  58. mMouseZeroTime[0] = 0.0f;
  59. mMouseZeroTime[1] = 0.0f;
  60. OIS::ParamList pl;
  61. std::ostringstream windowHndStr;
  62. windowHndStr << hWnd;
  63. pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
  64. #if defined BS_PLATFORM == BS_PLATFORM_WIN32
  65. pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_FOREGROUND" )));
  66. pl.insert(std::make_pair(std::string("w32_mouse"), std::string("DISCL_NONEXCLUSIVE")));
  67. pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_FOREGROUND")));
  68. pl.insert(std::make_pair(std::string("w32_keyboard"), std::string("DISCL_NONEXCLUSIVE")));
  69. #elif defined BS_PLATFORM == BS_PLATFORM_LINUX || BS_PLATFORM == BS_PLATFORM_APPLE
  70. pl.insert(std::make_pair(std::string("x11_mouse_grab"), std::string("false")));
  71. pl.insert(std::make_pair(std::string("x11_mouse_hide"), std::string("false")));
  72. pl.insert(std::make_pair(std::string("x11_keyboard_grab"), std::string("false")));
  73. pl.insert(std::make_pair(std::string("XAutoRepeatOn"), std::string("true")));
  74. #endif
  75. try
  76. {
  77. mInputManager = OIS::InputManager::createInputSystem(pl);
  78. }
  79. catch(OIS::Exception &e)
  80. {
  81. std::cout << e.eText << std::endl;
  82. }
  83. if (mInputManager->getNumberOfDevices(OIS::OISKeyboard) > 0)
  84. {
  85. mKeyboard = static_cast<OIS::Keyboard*>(mInputManager->createInputObject(OIS::OISKeyboard, true));
  86. mKeyboard->setEventCallback(this);
  87. }
  88. if (mInputManager->getNumberOfDevices(OIS::OISMouse) > 0)
  89. {
  90. mMouse = static_cast<OIS::Mouse*>(mInputManager->createInputObject(OIS::OISMouse, true));
  91. mMouse->setEventCallback(this);
  92. }
  93. UINT32 numGamepads = mInputManager->getNumberOfDevices(OIS::OISJoyStick);
  94. for (UINT32 i = 0; i < numGamepads; i++)
  95. {
  96. mGamepads.push_back(GamepadData());
  97. GamepadData& gamepadData = mGamepads.back();
  98. gamepadData.gamepad = static_cast<OIS::JoyStick*>(mInputManager->createInputObject(OIS::OISJoyStick, true));
  99. gamepadData.listener = bs_new<GamepadEventListener>(this, i);
  100. gamepadData.gamepad->setEventCallback(gamepadData.listener);
  101. }
  102. // OIS reports times since system start but we use time since program start
  103. mTimestampClockOffset = gTime().getStartTimeMs();
  104. }
  105. InputHandlerOIS::~InputHandlerOIS()
  106. {
  107. if(mInputManager)
  108. {
  109. if(mMouse != nullptr)
  110. mInputManager->destroyInputObject(mMouse);
  111. if(mKeyboard != nullptr)
  112. mInputManager->destroyInputObject(mKeyboard);
  113. for (auto& gamepadData : mGamepads)
  114. {
  115. mInputManager->destroyInputObject(gamepadData.gamepad);
  116. bs_delete(gamepadData.listener);
  117. }
  118. OIS::InputManager::destroyInputSystem(mInputManager);
  119. mInputManager = nullptr;
  120. }
  121. }
  122. float InputHandlerOIS::smoothMouse(float value, UINT32 idx)
  123. {
  124. UINT32 sampleCount = 1;
  125. float deltaTime = gTime().getFrameDelta();
  126. if (deltaTime < 0.25f)
  127. {
  128. float secondsPerSample = mTotalMouseSamplingTime[idx] / mTotalMouseNumSamples[idx];
  129. if (value == 0.0f)
  130. {
  131. mMouseZeroTime[idx] += deltaTime;
  132. if (mMouseZeroTime[idx] < secondsPerSample)
  133. value = mMouseSmoothedAxis[idx] * deltaTime / secondsPerSample;
  134. else
  135. mMouseSmoothedAxis[idx] = 0;
  136. }
  137. else
  138. {
  139. mMouseZeroTime[idx] = 0;
  140. if (mMouseSmoothedAxis[idx] != 0)
  141. {
  142. if (deltaTime < secondsPerSample * (sampleCount + 1))
  143. value = value * deltaTime / (secondsPerSample * sampleCount);
  144. else
  145. sampleCount = Math::roundToInt(deltaTime / secondsPerSample);
  146. }
  147. mMouseSmoothedAxis[idx] = value / sampleCount;
  148. }
  149. }
  150. else
  151. {
  152. mMouseSmoothedAxis[idx] = 0.0f;
  153. mMouseZeroTime[idx] = 0.0f;
  154. }
  155. return value;
  156. }
  157. void InputHandlerOIS::_update()
  158. {
  159. if (mMouse != nullptr)
  160. mMouse->capture();
  161. if (mKeyboard != nullptr)
  162. mKeyboard->capture();
  163. for (auto& gamepadData : mGamepads)
  164. {
  165. gamepadData.gamepad->capture();
  166. }
  167. // Limit mouse sampling to a certain rate to avoid jitter at extremely high frame rates.
  168. // (As the application might request samples faster than they are produced)
  169. mMouseSampleCounter += gTime().getFrameDelta();
  170. if (mMouseSampleCounter < MOUSE_MAX_SAMPLING_RATE)
  171. return;
  172. float rawXValue = 0.0f;
  173. float rawYValue = 0.0f;
  174. // Smooth mouse axes if needed
  175. if (mMouseSmoothingEnabled)
  176. {
  177. rawXValue = smoothMouse((float)mMouseSampleAccumulator[0], 0);
  178. rawYValue = smoothMouse((float)mMouseSampleAccumulator[1], 1);
  179. }
  180. else
  181. {
  182. rawXValue = (float)mMouseSampleAccumulator[0];
  183. rawYValue = (float)mMouseSampleAccumulator[1];
  184. }
  185. mMouseSampleAccumulator[0] = 0;
  186. mMouseSampleAccumulator[1] = 0;
  187. // Scale by time so that we are framerate independant: rawXValue = rawXValue * (MOUSE_MAX_TIME / gTime().getFrameDelta());
  188. // Scale to valid [-1.0, 1.0] range: rawXValue / (MOUSE_DPI * MOUSE_MAX)
  189. // This is just the combination of the two:
  190. float axisScale = ((MOUSE_DPI * MOUSE_MAX) / MOUSE_MAX_TIME) * mMouseSampleCounter;
  191. RawAxisState xState;
  192. xState.rel = -Math::clamp(rawXValue / axisScale, -1.0f, 1.0f);
  193. xState.abs = xState.rel; // Abs value irrelevant for mouse
  194. onAxisMoved(0, xState, (UINT32)InputAxis::MouseX);
  195. RawAxisState yState;
  196. yState.rel = -Math::clamp(rawYValue / axisScale, -1.0f, 1.0f);
  197. yState.abs = yState.rel; // Abs value irrelevant for mouse
  198. onAxisMoved(0, yState, (UINT32)InputAxis::MouseY);
  199. mMouseSampleCounter = 0.0f;
  200. }
  201. void InputHandlerOIS::_inputWindowChanged(const RenderWindow& win)
  202. {
  203. unsigned long long hWnd;
  204. win.getCustomAttribute("WINDOW", &hWnd);
  205. std::string normalString = toString((UINT64)hWnd).c_str();
  206. mKeyboard->setCaptureContext(normalString);
  207. mMouse->setCaptureContext(normalString);
  208. }
  209. bool InputHandlerOIS::keyPressed(const OIS::KeyEvent &arg)
  210. {
  211. onButtonDown(0, keyCodeToButtonCode(arg.key), arg.timestamp - mTimestampClockOffset);
  212. return true;
  213. }
  214. bool InputHandlerOIS::keyReleased(const OIS::KeyEvent& arg)
  215. {
  216. onButtonUp(0, keyCodeToButtonCode(arg.key), arg.timestamp - mTimestampClockOffset);
  217. return true;
  218. }
  219. bool InputHandlerOIS::mouseMoved(const OIS::MouseEvent& arg)
  220. {
  221. mMouseSampleAccumulator[0] += arg.state.X.rel;
  222. mMouseSampleAccumulator[1] += arg.state.Y.rel;
  223. mTotalMouseNumSamples[0] += Math::roundToInt(Math::abs((float)arg.state.X.rel));
  224. mTotalMouseNumSamples[1] += Math::roundToInt(Math::abs((float)arg.state.Y.rel));
  225. // Update sample times used for determining sampling rate. But only if something was
  226. // actually sampled, and only if this isn't the first non-zero sample.
  227. if (mLastMouseUpdateFrame != gTime().getCurrentFrameNumber())
  228. {
  229. if (arg.state.X.rel != 0 && !Math::approxEquals(mMouseSmoothedAxis[0], 0.0f))
  230. mTotalMouseSamplingTime[0] += gTime().getFrameDelta();
  231. if (arg.state.Y.rel != 0 && !Math::approxEquals(mMouseSmoothedAxis[1], 0.0f))
  232. mTotalMouseSamplingTime[1] += gTime().getFrameDelta();
  233. mLastMouseUpdateFrame = gTime().getCurrentFrameNumber();
  234. }
  235. RawAxisState zState;
  236. zState.abs = (float)arg.state.Z.abs;
  237. zState.rel = (float)arg.state.Z.rel;
  238. onAxisMoved(0, zState, (UINT32)InputAxis::MouseZ);
  239. return true;
  240. }
  241. bool InputHandlerOIS::mousePressed(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
  242. {
  243. onButtonDown(0, mouseButtonToButtonCode(id), arg.timestamp - mTimestampClockOffset);
  244. return true;
  245. }
  246. bool InputHandlerOIS::mouseReleased(const OIS::MouseEvent& arg, OIS::MouseButtonID id)
  247. {
  248. onButtonUp(0, mouseButtonToButtonCode(id), arg.timestamp - mTimestampClockOffset);
  249. return true;
  250. }
  251. ButtonCode InputHandlerOIS::keyCodeToButtonCode(OIS::KeyCode keyCode)
  252. {
  253. return (ButtonCode)keyCode;
  254. }
  255. ButtonCode InputHandlerOIS::mouseButtonToButtonCode(OIS::MouseButtonID mouseBtn)
  256. {
  257. return (ButtonCode)(((int)mouseBtn + BC_NumKeys) | 0x80000000);
  258. }
  259. ButtonCode InputHandlerOIS::gamepadButtonToButtonCode(INT32 joystickCode)
  260. {
  261. switch (joystickCode)
  262. {
  263. case 0:
  264. return BC_GAMEPAD_DPAD_UP;
  265. case 1:
  266. return BC_GAMEPAD_DPAD_DOWN;
  267. case 2:
  268. return BC_GAMEPAD_DPAD_LEFT;
  269. case 3:
  270. return BC_GAMEPAD_DPAD_RIGHT;
  271. case 4:
  272. return BC_GAMEPAD_START;
  273. case 5:
  274. return BC_GAMEPAD_BACK;
  275. case 6:
  276. return BC_GAMEPAD_LS;
  277. case 7:
  278. return BC_GAMEPAD_RS;
  279. case 8:
  280. return BC_GAMEPAD_LB;
  281. case 9:
  282. return BC_GAMEPAD_RB;
  283. case 10:
  284. return BC_GAMEPAD_BTN1;
  285. case 11:
  286. return BC_GAMEPAD_LS;
  287. case 12:
  288. return BC_GAMEPAD_A;
  289. case 13:
  290. return BC_GAMEPAD_B;
  291. case 14:
  292. return BC_GAMEPAD_X;
  293. case 15:
  294. return BC_GAMEPAD_Y;
  295. }
  296. return (ButtonCode)(BC_GAMEPAD_BTN1 + (joystickCode - 15));
  297. }
  298. }