Input.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. //
  2. // Copyright (c) 2008-2014 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "CoreEvents.h"
  25. #include "FileSystem.h"
  26. #include "Graphics.h"
  27. #include "GraphicsEvents.h"
  28. #include "GraphicsImpl.h"
  29. #include "Input.h"
  30. #include "Log.h"
  31. #include "Mutex.h"
  32. #include "ProcessUtils.h"
  33. #include "Profiler.h"
  34. #include "StringUtils.h"
  35. #include <cstring>
  36. #include <SDL.h>
  37. #include "DebugNew.h"
  38. // Require a click inside window before re-hiding mouse cursor on OSX, otherwise dragging the window
  39. // can be incorrectly interpreted as mouse movement inside the window
  40. #if defined(__APPLE__) && !defined(IOS)
  41. #define REQUIRE_CLICK_TO_FOCUS
  42. #endif
  43. namespace Urho3D
  44. {
  45. /// Convert SDL keycode if necessary
  46. int ConvertSDLKeyCode(int keySym, int scanCode)
  47. {
  48. if (scanCode == SCANCODE_AC_BACK)
  49. return KEY_ESC;
  50. else
  51. return SDL_toupper(keySym);
  52. }
  53. Input::Input(Context* context) :
  54. Object(context),
  55. mouseButtonDown_(0),
  56. mouseButtonPress_(0),
  57. mouseMoveWheel_(0),
  58. windowID_(0),
  59. toggleFullscreen_(true),
  60. mouseVisible_(false),
  61. inputFocus_(false),
  62. minimized_(false),
  63. focusedThisFrame_(false),
  64. suppressNextMouseMove_(false),
  65. initialized_(false)
  66. {
  67. SubscribeToEvent(E_SCREENMODE, HANDLER(Input, HandleScreenMode));
  68. // Try to initialize right now, but skip if screen mode is not yet set
  69. Initialize();
  70. }
  71. Input::~Input()
  72. {
  73. }
  74. void Input::Update()
  75. {
  76. assert(initialized_);
  77. PROFILE(UpdateInput);
  78. // Reset input accumulation for this frame
  79. keyPress_.Clear();
  80. scancodePress_.Clear();
  81. mouseButtonPress_ = 0;
  82. mouseMove_ = IntVector2::ZERO;
  83. mouseMoveWheel_ = 0;
  84. for (Vector<JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  85. {
  86. for (unsigned j = 0; j < i->buttonPress_.Size(); ++j)
  87. i->buttonPress_[j] = false;
  88. }
  89. // Reset touch delta movement
  90. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  91. {
  92. TouchState& state = i->second_;
  93. state.lastPosition_ = state.position_;
  94. state.delta_ = IntVector2::ZERO;
  95. }
  96. // Check and handle SDL events
  97. SDL_PumpEvents();
  98. SDL_Event evt;
  99. while (SDL_PeepEvents(&evt, 1, SDL_GETEVENT, SDL_FIRSTEVENT, SDL_LASTEVENT) > 0)
  100. HandleSDLEvent(&evt);
  101. // Check for activation and inactivation from SDL window flags. Must nullcheck the window pointer because it may have
  102. // been closed due to input events
  103. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  104. unsigned flags = window ? SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS) : 0;
  105. if (window)
  106. {
  107. #ifdef REQUIRE_CLICK_TO_FOCUS
  108. if (!inputFocus_ && (graphics_->GetFullscreen() || mouseVisible_) && flags == (SDL_WINDOW_INPUT_FOCUS |
  109. SDL_WINDOW_MOUSE_FOCUS))
  110. #else
  111. if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
  112. #endif
  113. focusedThisFrame_ = true;
  114. if (focusedThisFrame_)
  115. GainFocus();
  116. if (inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS) == 0)
  117. LoseFocus();
  118. }
  119. else
  120. return;
  121. // Check for relative mode mouse move
  122. if (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS)))
  123. {
  124. IntVector2 mousePosition = GetMousePosition();
  125. mouseMove_ = mousePosition - lastMousePosition_;
  126. if (graphics_->GetExternalWindow())
  127. lastMousePosition_ = mousePosition;
  128. else
  129. {
  130. // Recenter the mouse cursor manually
  131. IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  132. if (mousePosition != center)
  133. {
  134. SetMousePosition(center);
  135. lastMousePosition_ = center;
  136. }
  137. }
  138. // Send mouse move event if necessary
  139. if (mouseMove_ != IntVector2::ZERO)
  140. {
  141. if (suppressNextMouseMove_)
  142. {
  143. mouseMove_ = IntVector2::ZERO;
  144. suppressNextMouseMove_ = false;
  145. }
  146. else
  147. {
  148. using namespace MouseMove;
  149. VariantMap& eventData = GetEventDataMap();
  150. if (mouseVisible_)
  151. {
  152. eventData[P_X] = mousePosition.x_;
  153. eventData[P_Y] = mousePosition.y_;
  154. }
  155. eventData[P_DX] = mouseMove_.x_;
  156. eventData[P_DY] = mouseMove_.y_;
  157. eventData[P_BUTTONS] = mouseButtonDown_;
  158. eventData[P_QUALIFIERS] = GetQualifiers();
  159. SendEvent(E_MOUSEMOVE, eventData);
  160. }
  161. }
  162. }
  163. }
  164. void Input::SetMouseVisible(bool enable)
  165. {
  166. // SDL Raspberry Pi "video driver" does not have proper OS mouse support yet, so no-op for now
  167. #ifndef RASPI
  168. if (enable != mouseVisible_)
  169. {
  170. mouseVisible_ = enable;
  171. if (initialized_)
  172. {
  173. // External windows can only support visible mouse cursor
  174. if (graphics_->GetExternalWindow())
  175. {
  176. mouseVisible_ = true;
  177. return;
  178. }
  179. if (!mouseVisible_ && inputFocus_)
  180. SDL_ShowCursor(SDL_FALSE);
  181. else
  182. SDL_ShowCursor(SDL_TRUE);
  183. }
  184. using namespace MouseVisibleChanged;
  185. VariantMap& eventData = GetEventDataMap();
  186. eventData[P_VISIBLE] = mouseVisible_;
  187. SendEvent(E_MOUSEVISIBLECHANGED, eventData);
  188. }
  189. #endif
  190. }
  191. void Input::SetToggleFullscreen(bool enable)
  192. {
  193. toggleFullscreen_ = enable;
  194. }
  195. bool Input::DetectJoysticks()
  196. {
  197. SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
  198. SDL_InitSubSystem(SDL_INIT_JOYSTICK);
  199. ResetJoysticks();
  200. return true;
  201. }
  202. void Input::SetScreenKeyboardVisible(bool enable)
  203. {
  204. if (!graphics_)
  205. return;
  206. if (enable != IsScreenKeyboardVisible())
  207. {
  208. if (enable)
  209. SDL_StartTextInput();
  210. else
  211. SDL_StopTextInput();
  212. }
  213. }
  214. bool Input::OpenJoystick(unsigned index)
  215. {
  216. if (index >= joysticks_.Size())
  217. return false;
  218. // Check if already opened
  219. if (joysticks_[index].joystick_)
  220. return true;
  221. SDL_Joystick* joystick = SDL_JoystickOpen(index);
  222. if (joystick)
  223. {
  224. // Map SDL joystick index to internal index (which starts at 0)
  225. int sdl_joy_instance_id = SDL_JoystickInstanceID(joystick);
  226. joystickIDMap_[sdl_joy_instance_id] = index;
  227. JoystickState& state = joysticks_[index];
  228. state.joystick_ = joystick;
  229. if (SDL_IsGameController(index))
  230. state.controller_ = SDL_GameControllerOpen(index);
  231. state.buttons_.Resize(SDL_JoystickNumButtons(joystick));
  232. state.buttonPress_.Resize(state.buttons_.Size());
  233. state.axes_.Resize(SDL_JoystickNumAxes(joystick));
  234. state.hats_.Resize(SDL_JoystickNumHats(joystick));
  235. for (unsigned i = 0; i < state.buttons_.Size(); ++i)
  236. {
  237. state.buttons_[i] = false;
  238. state.buttonPress_[i] = false;
  239. }
  240. for (unsigned i = 0; i < state.axes_.Size(); ++i)
  241. state.axes_[i] = 0.0f;
  242. for (unsigned i = 0; i < state.hats_.Size(); ++i)
  243. state.hats_[i] = HAT_CENTER;
  244. return true;
  245. }
  246. else
  247. return false;
  248. }
  249. void Input::CloseJoystick(unsigned index)
  250. {
  251. if (index < joysticks_.Size() && joysticks_[index].joystick_)
  252. {
  253. JoystickState& state = joysticks_[index];
  254. SDL_JoystickClose(state.joystick_);
  255. state.joystick_ = 0;
  256. state.buttons_.Clear();
  257. state.axes_.Clear();
  258. state.hats_.Clear();
  259. }
  260. }
  261. int Input::GetKeyFromName(const String& name) const
  262. {
  263. return SDL_GetKeyFromName(name.CString());
  264. }
  265. int Input::GetKeyFromScancode(int scancode) const
  266. {
  267. return SDL_GetKeyFromScancode((SDL_Scancode)scancode);
  268. }
  269. String Input::GetKeyName(int key) const
  270. {
  271. return String(SDL_GetKeyName(key));
  272. }
  273. int Input::GetScancodeFromKey(int key) const
  274. {
  275. return SDL_GetScancodeFromKey(key);
  276. }
  277. int Input::GetScancodeFromName(const String& name) const
  278. {
  279. return SDL_GetScancodeFromName(name.CString());
  280. }
  281. String Input::GetScancodeName(int scancode) const
  282. {
  283. return SDL_GetScancodeName((SDL_Scancode)scancode);
  284. }
  285. bool Input::GetKeyDown(int key) const
  286. {
  287. return keyDown_.Contains(key);
  288. }
  289. bool Input::GetKeyPress(int key) const
  290. {
  291. return keyPress_.Contains(key);
  292. }
  293. bool Input::GetScancodeDown(int scancode) const
  294. {
  295. return scancodeDown_.Contains(scancode);
  296. }
  297. bool Input::GetScancodePress(int scancode) const
  298. {
  299. return scancodePress_.Contains(scancode);
  300. }
  301. bool Input::GetMouseButtonDown(int button) const
  302. {
  303. return (mouseButtonDown_ & button) != 0;
  304. }
  305. bool Input::GetMouseButtonPress(int button) const
  306. {
  307. return (mouseButtonPress_ & button) != 0;
  308. }
  309. bool Input::GetQualifierDown(int qualifier) const
  310. {
  311. if (qualifier == QUAL_SHIFT)
  312. return GetKeyDown(KEY_LSHIFT) || GetKeyDown(KEY_RSHIFT);
  313. if (qualifier == QUAL_CTRL)
  314. return GetKeyDown(KEY_LCTRL) || GetKeyDown(KEY_RCTRL);
  315. if (qualifier == QUAL_ALT)
  316. return GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT);
  317. return false;
  318. }
  319. bool Input::GetQualifierPress(int qualifier) const
  320. {
  321. if (qualifier == QUAL_SHIFT)
  322. return GetKeyPress(KEY_LSHIFT) || GetKeyPress(KEY_RSHIFT);
  323. if (qualifier == QUAL_CTRL)
  324. return GetKeyPress(KEY_LCTRL) || GetKeyPress(KEY_RCTRL);
  325. if (qualifier == QUAL_ALT)
  326. return GetKeyPress(KEY_LALT) || GetKeyPress(KEY_RALT);
  327. return false;
  328. }
  329. int Input::GetQualifiers() const
  330. {
  331. int ret = 0;
  332. if (GetQualifierDown(QUAL_SHIFT))
  333. ret |= QUAL_SHIFT;
  334. if (GetQualifierDown(QUAL_CTRL))
  335. ret |= QUAL_CTRL;
  336. if (GetQualifierDown(QUAL_ALT))
  337. ret |= QUAL_ALT;
  338. return ret;
  339. }
  340. IntVector2 Input::GetMousePosition() const
  341. {
  342. IntVector2 ret = IntVector2::ZERO;
  343. if (!initialized_)
  344. return ret;
  345. SDL_GetMouseState(&ret.x_, &ret.y_);
  346. return ret;
  347. }
  348. TouchState* Input::GetTouch(unsigned index) const
  349. {
  350. if (index >= touches_.Size())
  351. return 0;
  352. HashMap<int, TouchState>::ConstIterator i = touches_.Begin();
  353. while (index--)
  354. ++i;
  355. return const_cast<TouchState*>(&i->second_);
  356. }
  357. const String& Input::GetJoystickName(unsigned index) const
  358. {
  359. if (index < joysticks_.Size())
  360. return joysticks_[index].name_;
  361. else
  362. return String::EMPTY;
  363. }
  364. JoystickState* Input::GetJoystick(unsigned index)
  365. {
  366. if (index < joysticks_.Size())
  367. {
  368. // If necessary, automatically open the joystick first
  369. if (!joysticks_[index].joystick_)
  370. OpenJoystick(index);
  371. return const_cast<JoystickState*>(&joysticks_[index]);
  372. }
  373. else
  374. return 0;
  375. }
  376. bool Input::GetScreenKeyboardSupport() const
  377. {
  378. return graphics_ ? SDL_HasScreenKeyboardSupport() : false;
  379. }
  380. bool Input::IsScreenKeyboardVisible() const
  381. {
  382. if (graphics_)
  383. {
  384. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  385. return SDL_IsScreenKeyboardShown(window);
  386. }
  387. else
  388. return false;
  389. }
  390. bool Input::IsMinimized() const
  391. {
  392. // Return minimized state also when unfocused in fullscreen
  393. if (!inputFocus_ && graphics_ && graphics_->GetFullscreen())
  394. return true;
  395. else
  396. return minimized_;
  397. }
  398. void Input::Initialize()
  399. {
  400. Graphics* graphics = GetSubsystem<Graphics>();
  401. if (!graphics || !graphics->IsInitialized())
  402. return;
  403. graphics_ = graphics;
  404. // In external window mode only visible mouse is supported
  405. if (graphics_->GetExternalWindow())
  406. mouseVisible_ = true;
  407. // Set the initial activation
  408. focusedThisFrame_ = true;
  409. initialized_ = true;
  410. ResetJoysticks();
  411. ResetState();
  412. SubscribeToEvent(E_BEGINFRAME, HANDLER(Input, HandleBeginFrame));
  413. LOGINFO("Initialized input");
  414. }
  415. void Input::ResetJoysticks()
  416. {
  417. joysticks_.Clear();
  418. joysticks_.Resize(SDL_NumJoysticks());
  419. for (unsigned i = 0; i < joysticks_.Size(); ++i)
  420. joysticks_[i].name_ = SDL_JoystickNameForIndex(i);
  421. }
  422. void Input::GainFocus()
  423. {
  424. ResetState();
  425. inputFocus_ = true;
  426. focusedThisFrame_ = false;
  427. // Re-establish mouse cursor hiding as necessary
  428. if (!mouseVisible_)
  429. {
  430. SDL_ShowCursor(SDL_FALSE);
  431. suppressNextMouseMove_ = true;
  432. }
  433. else
  434. lastMousePosition_ = GetMousePosition();
  435. SendInputFocusEvent();
  436. }
  437. void Input::LoseFocus()
  438. {
  439. ResetState();
  440. inputFocus_ = false;
  441. focusedThisFrame_ = false;
  442. // Show the mouse cursor when inactive
  443. SDL_ShowCursor(SDL_TRUE);
  444. SendInputFocusEvent();
  445. }
  446. void Input::ResetState()
  447. {
  448. keyDown_.Clear();
  449. keyPress_.Clear();
  450. scancodeDown_.Clear();
  451. scancodePress_.Clear();
  452. /// \todo Check if this is necessary
  453. for (Vector<JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  454. {
  455. for (unsigned j = 0; j < i->buttons_.Size(); ++j)
  456. i->buttons_[j] = false;
  457. for (unsigned j = 0; j < i->hats_.Size(); ++j)
  458. i->hats_[j] = HAT_CENTER;
  459. }
  460. // When clearing touch states, send the corresponding touch end events
  461. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  462. {
  463. TouchState& state = i->second_;
  464. using namespace TouchEnd;
  465. VariantMap& eventData = GetEventDataMap();
  466. eventData[P_TOUCHID] = state.touchID_;
  467. eventData[P_X] = state.position_.x_;
  468. eventData[P_Y] = state.position_.y_;
  469. SendEvent(E_TOUCHEND, eventData);
  470. }
  471. // Use SetMouseButton() to reset the state so that mouse events will be sent properly
  472. SetMouseButton(MOUSEB_LEFT, false);
  473. SetMouseButton(MOUSEB_RIGHT, false);
  474. SetMouseButton(MOUSEB_MIDDLE, false);
  475. mouseMove_ = IntVector2::ZERO;
  476. mouseMoveWheel_ = 0;
  477. mouseButtonPress_ = 0;
  478. }
  479. void Input::SendInputFocusEvent()
  480. {
  481. using namespace InputFocus;
  482. VariantMap& eventData = GetEventDataMap();
  483. eventData[P_FOCUS] = HasFocus();
  484. eventData[P_MINIMIZED] = IsMinimized();
  485. SendEvent(E_INPUTFOCUS, eventData);
  486. }
  487. void Input::SetMouseButton(int button, bool newState)
  488. {
  489. #ifdef REQUIRE_CLICK_TO_FOCUS
  490. if (!mouseVisible_ && !graphics_->GetFullscreen())
  491. {
  492. if (!inputFocus_ && newState && button == MOUSEB_LEFT)
  493. focusedThisFrame_ = true;
  494. }
  495. #endif
  496. // If we do not have focus yet, do not react to the mouse button down
  497. if (!graphics_->GetExternalWindow() && newState && !inputFocus_)
  498. return;
  499. if (newState)
  500. {
  501. if (!(mouseButtonDown_ & button))
  502. mouseButtonPress_ |= button;
  503. mouseButtonDown_ |= button;
  504. }
  505. else
  506. {
  507. if (!(mouseButtonDown_ & button))
  508. return;
  509. mouseButtonDown_ &= ~button;
  510. }
  511. using namespace MouseButtonDown;
  512. VariantMap& eventData = GetEventDataMap();
  513. eventData[P_BUTTON] = button;
  514. eventData[P_BUTTONS] = mouseButtonDown_;
  515. eventData[P_QUALIFIERS] = GetQualifiers();
  516. SendEvent(newState ? E_MOUSEBUTTONDOWN : E_MOUSEBUTTONUP, eventData);
  517. }
  518. void Input::SetKey(int key, int scancode, unsigned raw, bool newState)
  519. {
  520. // If we do not have focus yet, do not react to the key down
  521. if (!graphics_->GetExternalWindow() && newState && !inputFocus_)
  522. return;
  523. bool repeat = false;
  524. if (newState)
  525. {
  526. scancodeDown_.Insert(scancode);
  527. scancodePress_.Insert(scancode);
  528. if (!keyDown_.Contains(key))
  529. {
  530. keyDown_.Insert(key);
  531. keyPress_.Insert(key);
  532. }
  533. else
  534. repeat = true;
  535. }
  536. else
  537. {
  538. scancodeDown_.Erase(scancode);
  539. if (!keyDown_.Erase(key))
  540. return;
  541. }
  542. using namespace KeyDown;
  543. VariantMap& eventData = GetEventDataMap();
  544. eventData[P_KEY] = key;
  545. eventData[P_SCANCODE] = scancode;
  546. eventData[P_RAW] = raw;
  547. eventData[P_BUTTONS] = mouseButtonDown_;
  548. eventData[P_QUALIFIERS] = GetQualifiers();
  549. if (newState)
  550. eventData[P_REPEAT] = repeat;
  551. SendEvent(newState ? E_KEYDOWN : E_KEYUP, eventData);
  552. if ((key == KEY_RETURN || key == KEY_RETURN2 || key == KEY_KP_ENTER) && newState && !repeat && toggleFullscreen_ &&
  553. (GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT)))
  554. graphics_->ToggleFullscreen();
  555. }
  556. void Input::SetMouseWheel(int delta)
  557. {
  558. // If we do not have focus yet, do not react to the wheel
  559. if (!graphics_->GetExternalWindow() && !inputFocus_)
  560. return;
  561. if (delta)
  562. {
  563. mouseMoveWheel_ += delta;
  564. using namespace MouseWheel;
  565. VariantMap& eventData = GetEventDataMap();
  566. eventData[P_WHEEL] = delta;
  567. eventData[P_BUTTONS] = mouseButtonDown_;
  568. eventData[P_QUALIFIERS] = GetQualifiers();
  569. SendEvent(E_MOUSEWHEEL, eventData);
  570. }
  571. }
  572. void Input::SetMousePosition(const IntVector2& position)
  573. {
  574. if (!graphics_)
  575. return;
  576. SDL_WarpMouseInWindow(graphics_->GetImpl()->GetWindow(), position.x_, position.y_);
  577. }
  578. void Input::HandleSDLEvent(void* sdlEvent)
  579. {
  580. SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
  581. switch (evt.type)
  582. {
  583. case SDL_KEYDOWN:
  584. // Convert to uppercase to match Win32 virtual key codes
  585. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, true);
  586. break;
  587. case SDL_KEYUP:
  588. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, false);
  589. break;
  590. case SDL_TEXTINPUT:
  591. {
  592. textInput_ = &evt.text.text[0];
  593. unsigned unicode = textInput_.AtUTF8(0);
  594. if (unicode)
  595. {
  596. using namespace Char;
  597. VariantMap keyEventData;
  598. keyEventData[P_CHAR] = unicode;
  599. keyEventData[P_BUTTONS] = mouseButtonDown_;
  600. keyEventData[P_QUALIFIERS] = GetQualifiers();
  601. SendEvent(E_CHAR, keyEventData);
  602. }
  603. }
  604. break;
  605. case SDL_MOUSEBUTTONDOWN:
  606. SetMouseButton(1 << (evt.button.button - 1), true);
  607. break;
  608. case SDL_MOUSEBUTTONUP:
  609. SetMouseButton(1 << (evt.button.button - 1), false);
  610. break;
  611. case SDL_MOUSEMOTION:
  612. if (mouseVisible_)
  613. {
  614. mouseMove_.x_ += evt.motion.xrel;
  615. mouseMove_.y_ += evt.motion.yrel;
  616. using namespace MouseMove;
  617. VariantMap& eventData = GetEventDataMap();
  618. if (mouseVisible_)
  619. {
  620. eventData[P_X] = evt.motion.x;
  621. eventData[P_Y] = evt.motion.y;
  622. }
  623. eventData[P_DX] = evt.motion.xrel;
  624. eventData[P_DY] = evt.motion.yrel;
  625. eventData[P_BUTTONS] = mouseButtonDown_;
  626. eventData[P_QUALIFIERS] = GetQualifiers();
  627. SendEvent(E_MOUSEMOVE, eventData);
  628. }
  629. break;
  630. case SDL_MOUSEWHEEL:
  631. SetMouseWheel(evt.wheel.y);
  632. break;
  633. case SDL_FINGERDOWN:
  634. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  635. {
  636. int touchID = evt.tfinger.fingerId & 0x7ffffff;
  637. TouchState& state = touches_[touchID];
  638. state.touchID_ = touchID;
  639. state.lastPosition_ = state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  640. (int)(evt.tfinger.y * graphics_->GetHeight()));
  641. state.delta_ = IntVector2::ZERO;
  642. state.pressure_ = evt.tfinger.pressure;
  643. using namespace TouchBegin;
  644. VariantMap& eventData = GetEventDataMap();
  645. eventData[P_TOUCHID] = touchID;
  646. eventData[P_X] = state.position_.x_;
  647. eventData[P_Y] = state.position_.y_;
  648. eventData[P_PRESSURE] = state.pressure_;
  649. SendEvent(E_TOUCHBEGIN, eventData);
  650. }
  651. break;
  652. case SDL_FINGERUP:
  653. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  654. {
  655. int touchID = evt.tfinger.fingerId & 0x7ffffff;
  656. TouchState& state = touches_[touchID];
  657. using namespace TouchEnd;
  658. VariantMap& eventData = GetEventDataMap();
  659. // Do not trust the position in the finger up event. Instead use the last position stored in the
  660. // touch structure
  661. eventData[P_TOUCHID] = touchID;
  662. eventData[P_X] = state.position_.x_;
  663. eventData[P_Y] = state.position_.y_;
  664. touches_.Erase(touchID);
  665. SendEvent(E_TOUCHEND, eventData);
  666. }
  667. break;
  668. case SDL_FINGERMOTION:
  669. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  670. {
  671. int touchID = evt.tfinger.fingerId & 0x7ffffff;
  672. TouchState& state = touches_[touchID];
  673. state.touchID_ = touchID;
  674. state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  675. (int)(evt.tfinger.y * graphics_->GetHeight()));
  676. state.delta_ = state.position_ - state.lastPosition_;
  677. state.pressure_ = evt.tfinger.pressure;
  678. using namespace TouchMove;
  679. VariantMap& eventData = GetEventDataMap();
  680. eventData[P_TOUCHID] = touchID;
  681. eventData[P_X] = state.position_.x_;
  682. eventData[P_Y] = state.position_.y_;
  683. eventData[P_DX] = (int)(evt.tfinger.dx * graphics_->GetWidth());
  684. eventData[P_DY] = (int)(evt.tfinger.dy * graphics_->GetHeight());
  685. eventData[P_PRESSURE] = state.pressure_;
  686. SendEvent(E_TOUCHMOVE, eventData);
  687. }
  688. break;
  689. case SDL_JOYBUTTONDOWN:
  690. {
  691. using namespace JoystickButtonDown;
  692. unsigned button = evt.jbutton.button;
  693. unsigned joystickIndex = joystickIDMap_[evt.jbutton.which];
  694. VariantMap& eventData = GetEventDataMap();
  695. eventData[P_JOYSTICK] = joystickIndex;
  696. eventData[P_BUTTON] = button;
  697. if (joystickIndex < joysticks_.Size() && button < joysticks_[joystickIndex].buttons_.Size()) {
  698. joysticks_[joystickIndex].buttons_[button] = true;
  699. joysticks_[joystickIndex].buttonPress_[button] = true;
  700. SendEvent(E_JOYSTICKBUTTONDOWN, eventData);
  701. }
  702. }
  703. break;
  704. case SDL_JOYBUTTONUP:
  705. {
  706. using namespace JoystickButtonUp;
  707. unsigned button = evt.jbutton.button;
  708. unsigned joystickIndex = joystickIDMap_[evt.jbutton.which];
  709. VariantMap& eventData = GetEventDataMap();
  710. eventData[P_JOYSTICK] = joystickIndex;
  711. eventData[P_BUTTON] = button;
  712. if (joystickIndex < joysticks_.Size() && button < joysticks_[joystickIndex].buttons_.Size()) {
  713. joysticks_[joystickIndex].buttons_[button] = false;
  714. SendEvent(E_JOYSTICKBUTTONUP, eventData);
  715. }
  716. }
  717. break;
  718. case SDL_JOYAXISMOTION:
  719. {
  720. using namespace JoystickAxisMove;
  721. unsigned joystickIndex = joystickIDMap_[evt.jaxis.which];
  722. VariantMap& eventData = GetEventDataMap();
  723. eventData[P_JOYSTICK] = joystickIndex;
  724. eventData[P_AXIS] = evt.jaxis.axis;
  725. eventData[P_POSITION] = Clamp((float)evt.jaxis.value / 32767.0f, -1.0f, 1.0f);
  726. if (joystickIndex < joysticks_.Size() && evt.jaxis.axis <
  727. joysticks_[joystickIndex].axes_.Size())
  728. {
  729. joysticks_[joystickIndex].axes_[evt.jaxis.axis] = eventData[P_POSITION].GetFloat();
  730. SendEvent(E_JOYSTICKAXISMOVE, eventData);
  731. }
  732. }
  733. break;
  734. case SDL_JOYHATMOTION:
  735. {
  736. using namespace JoystickHatMove;
  737. unsigned joystickIndex = joystickIDMap_[evt.jaxis.which];
  738. VariantMap& eventData = GetEventDataMap();
  739. eventData[P_JOYSTICK] = joystickIndex;
  740. eventData[P_HAT] = evt.jhat.hat;
  741. eventData[P_POSITION] = evt.jhat.value;
  742. if (joystickIndex < joysticks_.Size() && evt.jhat.hat <
  743. joysticks_[joystickIndex].hats_.Size())
  744. {
  745. joysticks_[joystickIndex].hats_[evt.jhat.hat] = evt.jhat.value;
  746. SendEvent(E_JOYSTICKHATMOVE, eventData);
  747. }
  748. }
  749. break;
  750. case SDL_CONTROLLERBUTTONDOWN:
  751. {
  752. using namespace ControllerButtonDown;
  753. unsigned button = evt.cbutton.button;
  754. unsigned joystickIndex = joystickIDMap_[evt.cbutton.which];
  755. VariantMap& eventData = GetEventDataMap();
  756. eventData[P_JOYSTICK] = joystickIndex;
  757. eventData[P_BUTTON] = button;
  758. if (joystickIndex < joysticks_.Size() && button < joysticks_[joystickIndex].buttons_.Size()) {
  759. joysticks_[joystickIndex].buttons_[button] = true;
  760. joysticks_[joystickIndex].buttonPress_[button] = true;
  761. SendEvent(E_CONTROLLERBUTTONDOWN, eventData);
  762. }
  763. }
  764. break;
  765. case SDL_CONTROLLERBUTTONUP:
  766. {
  767. using namespace ControllerButtonUp;
  768. unsigned button = evt.cbutton.button;
  769. unsigned joystickIndex = joystickIDMap_[evt.cbutton.which];
  770. VariantMap& eventData = GetEventDataMap();
  771. eventData[P_JOYSTICK] = joystickIndex;
  772. eventData[P_BUTTON] = button;
  773. if (joystickIndex < joysticks_.Size() && button < joysticks_[joystickIndex].buttons_.Size()) {
  774. joysticks_[joystickIndex].buttons_[button] = false;
  775. SendEvent(E_CONTROLLERBUTTONUP, eventData);
  776. }
  777. }
  778. break;
  779. case SDL_CONTROLLERAXISMOTION:
  780. {
  781. using namespace ControllerAxisMove;
  782. unsigned joystickIndex = joystickIDMap_[evt.caxis.which];
  783. VariantMap& eventData = GetEventDataMap();
  784. eventData[P_JOYSTICK] = joystickIndex;
  785. eventData[P_AXIS] = evt.caxis.axis;
  786. eventData[P_POSITION] = Clamp((float)evt.caxis.value / 32767.0f, -1.0f, 1.0f);
  787. if (joystickIndex < joysticks_.Size() && evt.caxis.axis <
  788. joysticks_[joystickIndex].axes_.Size())
  789. {
  790. joysticks_[joystickIndex].axes_[evt.caxis.axis] = eventData[P_POSITION].GetFloat();
  791. SendEvent(E_CONTROLLERAXISMOVE, eventData);
  792. }
  793. }
  794. break;
  795. case SDL_WINDOWEVENT:
  796. {
  797. switch (evt.window.event)
  798. {
  799. case SDL_WINDOWEVENT_MINIMIZED:
  800. minimized_ = true;
  801. SendInputFocusEvent();
  802. break;
  803. case SDL_WINDOWEVENT_MAXIMIZED:
  804. case SDL_WINDOWEVENT_RESTORED:
  805. minimized_ = false;
  806. SendInputFocusEvent();
  807. #ifdef IOS
  808. // On iOS we never lose the GL context, but may have done GPU object changes that could not be applied yet.
  809. // Apply them now
  810. graphics_->Restore();
  811. #endif
  812. break;
  813. #ifdef ANDROID
  814. case SDL_WINDOWEVENT_FOCUS_GAINED:
  815. // Restore GPU objects to the new GL context
  816. graphics_->Restore();
  817. break;
  818. #endif
  819. case SDL_WINDOWEVENT_RESIZED:
  820. graphics_->WindowResized();
  821. break;
  822. }
  823. }
  824. break;
  825. case SDL_DROPFILE:
  826. {
  827. using namespace DropFile;
  828. VariantMap& eventData = GetEventDataMap();
  829. eventData[P_FILENAME] = GetInternalPath(String(evt.drop.file));
  830. SDL_free(evt.drop.file);
  831. SendEvent(E_DROPFILE, eventData);
  832. }
  833. break;
  834. case SDL_QUIT:
  835. SendEvent(E_EXITREQUESTED);
  836. break;
  837. }
  838. }
  839. void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  840. {
  841. // Reset input state on subsequent initializations
  842. if (!initialized_)
  843. Initialize();
  844. else
  845. ResetState();
  846. // Re-enable cursor clipping, and re-center the cursor (if needed) to the new screen size, so that there is no erroneous
  847. // mouse move event. Also get new window ID if it changed
  848. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  849. windowID_ = SDL_GetWindowID(window);
  850. if (!mouseVisible_)
  851. {
  852. IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  853. SetMousePosition(center);
  854. lastMousePosition_ = center;
  855. }
  856. focusedThisFrame_ = true;
  857. // After setting a new screen mode we should not be minimized
  858. minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;
  859. }
  860. void Input::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  861. {
  862. // Update input right at the beginning of the frame
  863. Update();
  864. }
  865. }