Input.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015
  1. //
  2. // Copyright (c) 2008-2015 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 "../Core/Context.h"
  23. #include "../Core/CoreEvents.h"
  24. #include "../IO/FileSystem.h"
  25. #include "../Graphics/Graphics.h"
  26. #include "../Graphics/GraphicsEvents.h"
  27. #include "../Graphics/GraphicsImpl.h"
  28. #include "../Input/Input.h"
  29. #include "../IO/Log.h"
  30. #include "../Core/Mutex.h"
  31. #include "../Core/ProcessUtils.h"
  32. #include "../Core/Profiler.h"
  33. #include "../Resource/ResourceCache.h"
  34. #include "../IO/RWOpsWrapper.h"
  35. #include "../Core/StringUtils.h"
  36. #include <cstring>
  37. #include <SDL/include/SDL.h>
  38. #ifdef EMSCRIPTEN
  39. #include <emscripten/html5.h>
  40. #endif
  41. #include "../DebugNew.h"
  42. extern "C" int SDL_AddTouch(SDL_TouchID touchID, const char *name);
  43. // Use a "click inside window to focus" mechanism on desktop platforms when the mouse cursor is hidden
  44. #if defined(WIN32) || (defined(__APPLE__) && !defined(IOS)) || (defined(__linux__) && !defined(ANDROID) && !defined(RPI))
  45. #define REQUIRE_CLICK_TO_FOCUS
  46. #endif
  47. namespace Atomic
  48. {
  49. const int SCREEN_JOYSTICK_START_ID = 0x40000000;
  50. const StringHash VAR_BUTTON_KEY_BINDING("VAR_BUTTON_KEY_BINDING");
  51. const StringHash VAR_BUTTON_MOUSE_BUTTON_BINDING("VAR_BUTTON_MOUSE_BUTTON_BINDING");
  52. const StringHash VAR_LAST_KEYSYM("VAR_LAST_KEYSYM");
  53. const StringHash VAR_SCREEN_JOYSTICK_ID("VAR_SCREEN_JOYSTICK_ID");
  54. const unsigned TOUCHID_MAX = 32;
  55. /// Convert SDL keycode if necessary.
  56. int ConvertSDLKeyCode(int keySym, int scanCode)
  57. {
  58. if (scanCode == SCANCODE_AC_BACK)
  59. return KEY_ESC;
  60. else
  61. return SDL_toupper(keySym);
  62. }
  63. UIElement* TouchState::GetTouchedElement()
  64. {
  65. return touchedElement_.Get();
  66. }
  67. #ifdef EMSCRIPTEN
  68. #define EM_TRUE 1
  69. /// Glue between Urho Input and Emscripten HTML5
  70. /** HTML5 (Emscripten) is limited in the way it handles input. The EmscriptenInput class attempts to provide the glue between Urho3D Input behavior and HTML5, where SDL currently fails to do so.
  71. *
  72. * Mouse Input:
  73. * - The OS mouse cursor position can't be set.
  74. * - The mouse can be trapped within play area via 'PointerLock API', which requires a request and interaction between the user and browser.
  75. * - To request mouse lock, call SetMouseMode(MM_RELATIVE). The E_MOUSEMODECHANGED event will be sent if/when the user confirms the request.
  76. * NOTE: The request must be initiated by the user (eg: on mouse button down/up, key down/up).
  77. * - The user can press 'escape' key and browser will force user out of pointer lock. Urho will send the E_MOUSEMODECHANGED event.
  78. * - SetMouseMode(MM_ABSOLUTE) will leave pointer lock.
  79. * - MM_WRAP is unsupported.
  80. */
  81. /// % Emscripten Input glue. Intended to be used by the Input subsystem only.
  82. class EmscriptenInput
  83. {
  84. public:
  85. /// Constructor, expecting pointer to constructing Input instance.
  86. EmscriptenInput(Input* inputInst);
  87. /// Static callback method for Pointer Lock API. Handles change in Pointer Lock state and sends events for mouse mode change.
  88. static EM_BOOL HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData);
  89. /// Static callback method for tracking focus change events.
  90. static EM_BOOL HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData);
  91. /// Send request to user to gain pointer lock. This requires a user-browser interaction on the first call.
  92. void RequestPointerLock();
  93. /// Send request to exit pointer lock. This has the benefit of not requiring the user-browser interaction on the next pointer lock request.
  94. void ExitPointerLock();
  95. /// Returns whether the page is visible.
  96. bool IsVisible();
  97. private:
  98. /// Instance of Input subsystem that constructed this instance.
  99. Input* inputInst_;
  100. };
  101. EmscriptenInput::EmscriptenInput(Input* inputInst)
  102. {
  103. inputInst_ = inputInst;
  104. void* vInputInst = (void*)inputInst;
  105. emscripten_set_pointerlockchange_callback(NULL, vInputInst, false, EmscriptenInput::HandlePointerLockChange);
  106. // Handle focus changes:
  107. emscripten_set_blur_callback(NULL, vInputInst, false, EmscriptenInput::HandleFocusChange);
  108. emscripten_set_focus_callback(NULL, vInputInst, false, EmscriptenInput::HandleFocusChange);
  109. }
  110. void EmscriptenInput::RequestPointerLock()
  111. {
  112. emscripten_request_pointerlock(NULL, true);
  113. }
  114. void EmscriptenInput::ExitPointerLock()
  115. {
  116. inputInst_->emscriptenExitingPointerLock_ = true;
  117. emscripten_exit_pointerlock();
  118. }
  119. bool EmscriptenInput::IsVisible()
  120. {
  121. EmscriptenVisibilityChangeEvent visibilityStatus;
  122. if (emscripten_get_visibility_status(&visibilityStatus) >= EMSCRIPTEN_RESULT_SUCCESS)
  123. return visibilityStatus.hidden >= EM_TRUE ? false : true;
  124. // Assume visible
  125. LOGWARNING("Could not determine visibility status.");
  126. return true;
  127. }
  128. EM_BOOL EmscriptenInput::HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData)
  129. {
  130. Input* inputInst = (Input*)userData;
  131. if (keyEvent->isActive >= EM_TRUE)
  132. {
  133. // Pointer Lock is now active
  134. inputInst->emscriptenEnteredPointerLock_ = true;
  135. inputInst->SetMouseModeEmscripten(MM_RELATIVE);
  136. }
  137. else
  138. {
  139. // Pointer Lock is now inactive
  140. inputInst->SetMouseModeEmscripten(MM_ABSOLUTE);
  141. }
  142. return EM_TRUE;
  143. }
  144. EM_BOOL EmscriptenInput::HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData)
  145. {
  146. Input* inputInst = (Input*)userData;
  147. if (eventType == EMSCRIPTEN_EVENT_BLUR)
  148. inputInst->LoseFocus();
  149. else if (eventType == EMSCRIPTEN_EVENT_FOCUS)
  150. inputInst->GainFocus();
  151. return EM_TRUE;
  152. }
  153. #endif
  154. void JoystickState::Initialize(unsigned numButtons, unsigned numAxes, unsigned numHats)
  155. {
  156. buttons_.Resize(numButtons);
  157. buttonPress_.Resize(numButtons);
  158. axes_.Resize(numAxes);
  159. hats_.Resize(numHats);
  160. Reset();
  161. }
  162. void JoystickState::Reset()
  163. {
  164. for (unsigned i = 0; i < buttons_.Size(); ++i)
  165. {
  166. buttons_[i] = false;
  167. buttonPress_[i] = false;
  168. }
  169. for (unsigned i = 0; i < axes_.Size(); ++i)
  170. axes_[i] = 0.0f;
  171. for (unsigned i = 0; i < hats_.Size(); ++i)
  172. hats_[i] = HAT_CENTER;
  173. }
  174. Input::Input(Context* context) :
  175. Object(context),
  176. mouseButtonDown_(0),
  177. mouseButtonPress_(0),
  178. lastVisibleMousePosition_(MOUSE_POSITION_OFFSCREEN),
  179. mouseMoveWheel_(0),
  180. windowID_(0),
  181. toggleFullscreen_(true),
  182. mouseVisible_(false),
  183. lastMouseVisible_(false),
  184. mouseGrabbed_(false),
  185. mouseMode_(MM_ABSOLUTE),
  186. #ifdef EMSCRIPTEN
  187. emscriptenExitingPointerLock_(false),
  188. emscriptenEnteredPointerLock_(false),
  189. #endif
  190. touchEmulation_(false),
  191. inputFocus_(false),
  192. minimized_(false),
  193. focusedThisFrame_(false),
  194. suppressNextMouseMove_(false),
  195. inResize_(false),
  196. screenModeChanged_(false),
  197. initialized_(false)
  198. {
  199. for (int i = 0; i < TOUCHID_MAX; i++)
  200. availableTouchIDs_.Push(i);
  201. SubscribeToEvent(E_SCREENMODE, HANDLER(Input, HandleScreenMode));
  202. #ifdef EMSCRIPTEN
  203. emscriptenInput_ = new EmscriptenInput(this);
  204. #endif
  205. // Try to initialize right now, but skip if screen mode is not yet set
  206. Initialize();
  207. }
  208. Input::~Input()
  209. {
  210. #ifdef EMSCRIPTEN
  211. delete emscriptenInput_;
  212. emscriptenInput_ = 0;
  213. #endif
  214. }
  215. void Input::Update()
  216. {
  217. assert(initialized_);
  218. PROFILE(UpdateInput);
  219. // Reset input accumulation for this frame
  220. keyPress_.Clear();
  221. scancodePress_.Clear();
  222. mouseButtonPress_ = 0;
  223. mouseMove_ = IntVector2::ZERO;
  224. mouseMoveWheel_ = 0;
  225. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  226. {
  227. for (unsigned j = 0; j < i->second_.buttonPress_.Size(); ++j)
  228. i->second_.buttonPress_[j] = false;
  229. }
  230. // Reset touch delta movement
  231. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  232. {
  233. TouchState& state = i->second_;
  234. state.lastPosition_ = state.position_;
  235. state.delta_ = IntVector2::ZERO;
  236. }
  237. SDL_Event evt;
  238. while (SDL_PollEvent(&evt))
  239. HandleSDLEvent(&evt);
  240. // Check for focus change this frame
  241. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  242. unsigned flags = window ? SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS) : 0;
  243. #ifndef EMSCRIPTEN
  244. if (window)
  245. {
  246. #ifdef REQUIRE_CLICK_TO_FOCUS
  247. // When using the "click to focus" mechanism, only focus automatically in fullscreen or non-hidden mouse mode
  248. if (!inputFocus_ && (mouseVisible_ || graphics_->GetFullscreen() || screenModeChanged_) && (flags & SDL_WINDOW_INPUT_FOCUS))
  249. #else
  250. if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
  251. #endif
  252. {
  253. screenModeChanged_ = false;
  254. focusedThisFrame_ = true;
  255. }
  256. if (focusedThisFrame_)
  257. GainFocus();
  258. if (inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS) == 0)
  259. LoseFocus();
  260. }
  261. else
  262. return;
  263. // Handle mouse mode MM_WRAP
  264. if (mouseVisible_ && mouseMode_ == MM_WRAP)
  265. {
  266. IntVector2 mpos;
  267. SDL_GetMouseState(&mpos.x_, &mpos.y_);
  268. const int buffer = 5;
  269. int width = graphics_->GetWidth() - buffer * 2;
  270. int height = graphics_->GetHeight() - buffer * 2;
  271. bool warp = false;
  272. if (mpos.x_ < buffer)
  273. {
  274. warp = true;
  275. mpos.x_ += width;
  276. }
  277. if (mpos.x_ > buffer + width)
  278. {
  279. warp = true;
  280. mpos.x_ -= width;
  281. }
  282. if (mpos.y_ < buffer)
  283. {
  284. warp = true;
  285. mpos.y_ += height;
  286. }
  287. if (mpos.y_ > buffer + height)
  288. {
  289. warp = true;
  290. mpos.y_ -= height;
  291. }
  292. if (warp)
  293. {
  294. SetMousePosition(mpos);
  295. SDL_FlushEvent(SDL_MOUSEMOTION);
  296. }
  297. }
  298. #else
  299. if (!window)
  300. return;
  301. if (emscriptenExitingPointerLock_)
  302. {
  303. // Suppress mouse jump when exiting Pointer Lock
  304. IntVector2 mousePosition = GetMousePosition();
  305. mouseMove_ = IntVector2::ZERO;
  306. lastMousePosition_ = lastVisibleMousePosition_;
  307. emscriptenExitingPointerLock_ = false;
  308. return;
  309. }
  310. #endif
  311. // Check for relative mode mouse move
  312. // Note that Emscripten will use SDL mouse move events for relative mode instead
  313. #ifndef EMSCRIPTEN
  314. if (!touchEmulation_ && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
  315. #else
  316. if (!touchEmulation_ && mouseMode_ != MM_RELATIVE && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
  317. #endif
  318. {
  319. IntVector2 mousePosition = GetMousePosition();
  320. mouseMove_ = mousePosition - lastMousePosition_;
  321. #ifndef EMSCRIPTEN
  322. if (graphics_->GetExternalWindow())
  323. lastMousePosition_ = mousePosition;
  324. else
  325. {
  326. // Recenter the mouse cursor manually after move
  327. IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  328. if (mousePosition != center)
  329. {
  330. SetMousePosition(center);
  331. lastMousePosition_ = center;
  332. }
  333. }
  334. #else
  335. if (mouseMode_ == MM_ABSOLUTE)
  336. lastMousePosition_ = mousePosition;
  337. #endif
  338. // Send mouse move event if necessary
  339. if (mouseMove_ != IntVector2::ZERO)
  340. {
  341. if (suppressNextMouseMove_)
  342. {
  343. mouseMove_ = IntVector2::ZERO;
  344. suppressNextMouseMove_ = false;
  345. }
  346. else
  347. {
  348. using namespace MouseMove;
  349. VariantMap& eventData = GetEventDataMap();
  350. if (mouseVisible_)
  351. {
  352. eventData[P_X] = mousePosition.x_;
  353. eventData[P_Y] = mousePosition.y_;
  354. }
  355. eventData[P_DX] = mouseMove_.x_;
  356. eventData[P_DY] = mouseMove_.y_;
  357. eventData[P_BUTTONS] = mouseButtonDown_;
  358. eventData[P_QUALIFIERS] = GetQualifiers();
  359. SendEvent(E_MOUSEMOVE, eventData);
  360. }
  361. }
  362. }
  363. }
  364. void Input::SetMouseVisible(bool enable, bool suppressEvent)
  365. {
  366. // In touch emulation mode only enabled mouse is allowed
  367. if (touchEmulation_)
  368. enable = true;
  369. // In mouse mode relative, the mouse should be invisible
  370. if (mouseMode_ == MM_RELATIVE)
  371. enable = false;
  372. // SDL Raspberry Pi "video driver" does not have proper OS mouse support yet, so no-op for now
  373. #ifndef RPI
  374. if (enable != mouseVisible_)
  375. {
  376. mouseVisible_ = enable;
  377. if (initialized_)
  378. {
  379. // External windows can only support visible mouse cursor
  380. if (graphics_->GetExternalWindow())
  381. {
  382. mouseVisible_ = true;
  383. if (!suppressEvent)
  384. lastMouseVisible_ = true;
  385. return;
  386. }
  387. if (!mouseVisible_ && inputFocus_)
  388. {
  389. SDL_ShowCursor(SDL_FALSE);
  390. #ifndef EMSCRIPTEN
  391. // Recenter the mouse cursor manually when hiding it to avoid erratic mouse move for one frame
  392. lastVisibleMousePosition_ = GetMousePosition();
  393. IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  394. SetMousePosition(center);
  395. lastMousePosition_ = center;
  396. #else
  397. lastVisibleMousePosition_ = GetMousePosition();
  398. lastMousePosition_ = lastVisibleMousePosition_;
  399. #endif
  400. }
  401. else
  402. {
  403. SDL_ShowCursor(SDL_TRUE);
  404. #ifndef EMSCRIPTEN
  405. if (lastVisibleMousePosition_.x_ != MOUSE_POSITION_OFFSCREEN.x_ && lastVisibleMousePosition_.y_ != MOUSE_POSITION_OFFSCREEN.y_)
  406. SetMousePosition(lastVisibleMousePosition_);
  407. lastMousePosition_ = lastVisibleMousePosition_;
  408. #endif
  409. }
  410. }
  411. if (!suppressEvent)
  412. {
  413. using namespace MouseVisibleChanged;
  414. VariantMap& eventData = GetEventDataMap();
  415. eventData[P_VISIBLE] = mouseVisible_;
  416. SendEvent(E_MOUSEVISIBLECHANGED, eventData);
  417. }
  418. }
  419. // Make sure last mouse visible is valid:
  420. if (!suppressEvent)
  421. lastMouseVisible_ = mouseVisible_;
  422. #endif
  423. }
  424. void Input::ResetMouseVisible()
  425. {
  426. #ifndef EMSCRIPTEN
  427. SetMouseVisible(lastMouseVisible_, true);
  428. #else
  429. SetMouseVisibleEmscripten(lastMouseVisible_);
  430. #endif
  431. }
  432. #ifdef EMSCRIPTEN
  433. void Input::SetMouseVisibleEmscripten(bool enable)
  434. {
  435. if (enable != mouseVisible_)
  436. {
  437. mouseVisible_ = enable;
  438. SDL_ShowCursor(enable ? SDL_TRUE : SDL_FALSE);
  439. if (!mouseVisible_)
  440. lastVisibleMousePosition_ = GetMousePosition();
  441. lastMousePosition_ = lastVisibleMousePosition_;
  442. }
  443. }
  444. void Input::SetMouseModeEmscripten(MouseMode mode)
  445. {
  446. mouseMode_ = mode;
  447. if (mode == MM_RELATIVE)
  448. {
  449. SetMouseVisibleEmscripten(false);
  450. }
  451. else
  452. {
  453. ResetMouseVisible();
  454. }
  455. suppressNextMouseMove_ = true;
  456. VariantMap& eventData = GetEventDataMap();
  457. eventData[MouseModeChanged::P_MODE] = mode;
  458. SendEvent(E_MOUSEMODECHANGED, eventData);
  459. }
  460. #endif
  461. void Input::SetMouseGrabbed(bool grab)
  462. {
  463. mouseGrabbed_ = grab;
  464. }
  465. void Input::SetMouseMode(MouseMode mode)
  466. {
  467. if (mode != mouseMode_)
  468. {
  469. MouseMode previousMode = mouseMode_;
  470. mouseMode_ = mode;
  471. suppressNextMouseMove_ = true;
  472. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  473. // Handle changing away from previous mode
  474. if (previousMode == MM_RELATIVE)
  475. {
  476. #ifndef EMSCRIPTEN
  477. /// \todo Use SDL_SetRelativeMouseMode() for MM_RELATIVE mode
  478. ResetMouseVisible();
  479. #else
  480. emscriptenInput_->ExitPointerLock();
  481. #endif
  482. SDL_SetWindowGrab(window, SDL_FALSE);
  483. }
  484. #ifndef EMSCRIPTEN
  485. else if (previousMode == MM_WRAP)
  486. SDL_SetWindowGrab(window, SDL_FALSE);
  487. #endif
  488. // Handle changing to new mode
  489. if (mode == MM_ABSOLUTE)
  490. {
  491. #ifndef EMSCRIPTEN
  492. SetMouseGrabbed(false);
  493. VariantMap& eventData = GetEventDataMap();
  494. eventData[MouseModeChanged::P_MODE] = mode;
  495. SendEvent(E_MOUSEMODECHANGED, eventData);
  496. #else
  497. // Deferred mouse mode change to PointerLock callback
  498. #endif
  499. }
  500. else
  501. {
  502. SetMouseGrabbed(true);
  503. if (mode == MM_RELATIVE)
  504. {
  505. SDL_SetWindowGrab(window, SDL_TRUE);
  506. #ifndef EMSCRIPTEN
  507. SetMouseVisible(false, true);
  508. VariantMap& eventData = GetEventDataMap();
  509. eventData[MouseModeChanged::P_MODE] = mode;
  510. SendEvent(E_MOUSEMODECHANGED, eventData);
  511. #else
  512. // Defer mouse mode change to PointerLock callback
  513. mouseMode_ = previousMode;
  514. emscriptenInput_->RequestPointerLock();
  515. #endif
  516. }
  517. #ifndef EMSCRIPTEN
  518. else if (mode == MM_WRAP)
  519. {
  520. /// \todo When SDL 2.0.4 is integrated, use SDL_CaptureMouse() and global mouse functions for MM_WRAP mode.
  521. SDL_SetWindowGrab(window, SDL_TRUE);
  522. VariantMap& eventData = GetEventDataMap();
  523. eventData[MouseModeChanged::P_MODE] = mode;
  524. SendEvent(E_MOUSEMODECHANGED, eventData);
  525. }
  526. #endif
  527. }
  528. }
  529. }
  530. void Input::SetToggleFullscreen(bool enable)
  531. {
  532. toggleFullscreen_ = enable;
  533. }
  534. static void PopulateKeyBindingMap(HashMap<String, int>& keyBindingMap)
  535. {
  536. if (keyBindingMap.Empty())
  537. {
  538. keyBindingMap.Insert(MakePair<String, int>("SPACE", KEY_SPACE));
  539. keyBindingMap.Insert(MakePair<String, int>("LCTRL", KEY_LCTRL));
  540. keyBindingMap.Insert(MakePair<String, int>("RCTRL", KEY_RCTRL));
  541. keyBindingMap.Insert(MakePair<String, int>("LSHIFT", KEY_LSHIFT));
  542. keyBindingMap.Insert(MakePair<String, int>("RSHIFT", KEY_RSHIFT));
  543. keyBindingMap.Insert(MakePair<String, int>("LALT", KEY_LALT));
  544. keyBindingMap.Insert(MakePair<String, int>("RALT", KEY_RALT));
  545. keyBindingMap.Insert(MakePair<String, int>("LGUI", KEY_LGUI));
  546. keyBindingMap.Insert(MakePair<String, int>("RGUI", KEY_RGUI));
  547. keyBindingMap.Insert(MakePair<String, int>("TAB", KEY_TAB));
  548. keyBindingMap.Insert(MakePair<String, int>("RETURN", KEY_RETURN));
  549. keyBindingMap.Insert(MakePair<String, int>("RETURN2", KEY_RETURN2));
  550. keyBindingMap.Insert(MakePair<String, int>("ENTER", KEY_KP_ENTER));
  551. keyBindingMap.Insert(MakePair<String, int>("SELECT", KEY_SELECT));
  552. keyBindingMap.Insert(MakePair<String, int>("LEFT", KEY_LEFT));
  553. keyBindingMap.Insert(MakePair<String, int>("RIGHT", KEY_RIGHT));
  554. keyBindingMap.Insert(MakePair<String, int>("UP", KEY_UP));
  555. keyBindingMap.Insert(MakePair<String, int>("DOWN", KEY_DOWN));
  556. keyBindingMap.Insert(MakePair<String, int>("PAGEUP", KEY_PAGEUP));
  557. keyBindingMap.Insert(MakePair<String, int>("PAGEDOWN", KEY_PAGEDOWN));
  558. keyBindingMap.Insert(MakePair<String, int>("F1", KEY_F1));
  559. keyBindingMap.Insert(MakePair<String, int>("F2", KEY_F2));
  560. keyBindingMap.Insert(MakePair<String, int>("F3", KEY_F3));
  561. keyBindingMap.Insert(MakePair<String, int>("F4", KEY_F4));
  562. keyBindingMap.Insert(MakePair<String, int>("F5", KEY_F5));
  563. keyBindingMap.Insert(MakePair<String, int>("F6", KEY_F6));
  564. keyBindingMap.Insert(MakePair<String, int>("F7", KEY_F7));
  565. keyBindingMap.Insert(MakePair<String, int>("F8", KEY_F8));
  566. keyBindingMap.Insert(MakePair<String, int>("F9", KEY_F9));
  567. keyBindingMap.Insert(MakePair<String, int>("F10", KEY_F10));
  568. keyBindingMap.Insert(MakePair<String, int>("F11", KEY_F11));
  569. keyBindingMap.Insert(MakePair<String, int>("F12", KEY_F12));
  570. }
  571. }
  572. static void PopulateMouseButtonBindingMap(HashMap<String, int>& mouseButtonBindingMap)
  573. {
  574. if (mouseButtonBindingMap.Empty())
  575. {
  576. mouseButtonBindingMap.Insert(MakePair<String, int>("LEFT", SDL_BUTTON_LEFT));
  577. mouseButtonBindingMap.Insert(MakePair<String, int>("MIDDLE", SDL_BUTTON_MIDDLE));
  578. mouseButtonBindingMap.Insert(MakePair<String, int>("RIGHT", SDL_BUTTON_RIGHT));
  579. mouseButtonBindingMap.Insert(MakePair<String, int>("X1", SDL_BUTTON_X1));
  580. mouseButtonBindingMap.Insert(MakePair<String, int>("X2", SDL_BUTTON_X2));
  581. }
  582. }
  583. int Input::AddScreenJoystick(XMLFile* layoutFile, XMLFile* styleFile)
  584. {
  585. return -1;
  586. /*
  587. static HashMap<String, int> keyBindingMap;
  588. static HashMap<String, int> mouseButtonBindingMap;
  589. if (!graphics_)
  590. {
  591. LOGWARNING("Cannot add screen joystick in headless mode");
  592. return -1;
  593. }
  594. // If layout file is not given, use the default screen joystick layout
  595. if (!layoutFile)
  596. {
  597. ResourceCache* cache = GetSubsystem<ResourceCache>();
  598. layoutFile = cache->GetResource<XMLFile>("UI/ScreenJoystick.xml");
  599. if (!layoutFile) // Error is already logged
  600. return -1;
  601. }
  602. UI* ui = GetSubsystem<UI>();
  603. SharedPtr<UIElement> screenJoystick = ui->LoadLayout(layoutFile, styleFile);
  604. if (!screenJoystick) // Error is already logged
  605. return -1;
  606. screenJoystick->SetSize(ui->GetRoot()->GetSize());
  607. ui->GetRoot()->AddChild(screenJoystick);
  608. // Get an unused ID for the screen joystick
  609. /// \todo After a real joystick has been plugged in 1073741824 times, the ranges will overlap
  610. SDL_JoystickID joystickID = SCREEN_JOYSTICK_START_ID;
  611. while (joysticks_.Contains(joystickID))
  612. ++joystickID;
  613. JoystickState& state = joysticks_[joystickID];
  614. state.joystickID_ = joystickID;
  615. state.name_ = screenJoystick->GetName();
  616. state.screenJoystick_ = screenJoystick;
  617. unsigned numButtons = 0;
  618. unsigned numAxes = 0;
  619. unsigned numHats = 0;
  620. const Vector<SharedPtr<UIElement> >& children = state.screenJoystick_->GetChildren();
  621. for (Vector<SharedPtr<UIElement> >::ConstIterator iter = children.Begin(); iter != children.End(); ++iter)
  622. {
  623. UIElement* element = iter->Get();
  624. String name = element->GetName();
  625. if (name.StartsWith("Button"))
  626. {
  627. ++numButtons;
  628. // Check whether the button has key binding
  629. Text* text = dynamic_cast<Text*>(element->GetChild("KeyBinding", false));
  630. if (text)
  631. {
  632. text->SetVisible(false);
  633. const String& key = text->GetText();
  634. int keyBinding;
  635. if (key.Length() == 1)
  636. keyBinding = key[0];
  637. else
  638. {
  639. PopulateKeyBindingMap(keyBindingMap);
  640. HashMap<String, int>::Iterator i = keyBindingMap.Find(key);
  641. if (i != keyBindingMap.End())
  642. keyBinding = i->second_;
  643. else
  644. {
  645. LOGERRORF("Unsupported key binding: %s", key.CString());
  646. keyBinding = M_MAX_INT;
  647. }
  648. }
  649. if (keyBinding != M_MAX_INT)
  650. element->SetVar(VAR_BUTTON_KEY_BINDING, keyBinding);
  651. }
  652. // Check whether the button has mouse button binding
  653. text = dynamic_cast<Text*>(element->GetChild("MouseButtonBinding", false));
  654. if (text)
  655. {
  656. text->SetVisible(false);
  657. const String& mouseButton = text->GetText();
  658. PopulateMouseButtonBindingMap(mouseButtonBindingMap);
  659. HashMap<String, int>::Iterator i = mouseButtonBindingMap.Find(mouseButton);
  660. if (i != mouseButtonBindingMap.End())
  661. element->SetVar(VAR_BUTTON_MOUSE_BUTTON_BINDING, i->second_);
  662. else
  663. LOGERRORF("Unsupported mouse button binding: %s", mouseButton.CString());
  664. }
  665. }
  666. else if (name.StartsWith("Axis"))
  667. {
  668. ++numAxes;
  669. ///\todo Axis emulation for screen joystick is not fully supported yet.
  670. LOGWARNING("Axis emulation for screen joystick is not fully supported yet");
  671. }
  672. else if (name.StartsWith("Hat"))
  673. {
  674. ++numHats;
  675. Text* text = dynamic_cast<Text*>(element->GetChild("KeyBinding", false));
  676. if (text)
  677. {
  678. text->SetVisible(false);
  679. String keyBinding = text->GetText();
  680. if (keyBinding.Contains(' ')) // e.g.: "UP DOWN LEFT RIGHT"
  681. {
  682. // Attempt to split the text using ' ' as separator
  683. Vector<String>keyBindings(keyBinding.Split(' '));
  684. String mappedKeyBinding;
  685. if (keyBindings.Size() == 4)
  686. {
  687. PopulateKeyBindingMap(keyBindingMap);
  688. for (unsigned j = 0; j < 4; ++j)
  689. {
  690. if (keyBindings[j].Length() == 1)
  691. mappedKeyBinding.Append(keyBindings[j][0]);
  692. else
  693. {
  694. HashMap<String, int>::Iterator i = keyBindingMap.Find(keyBindings[j]);
  695. if (i != keyBindingMap.End())
  696. mappedKeyBinding.Append(i->second_);
  697. else
  698. break;
  699. }
  700. }
  701. }
  702. if (mappedKeyBinding.Length() != 4)
  703. {
  704. LOGERRORF("%s has invalid key binding %s, fallback to WSAD", name.CString(), keyBinding.CString());
  705. keyBinding = "WSAD";
  706. }
  707. else
  708. keyBinding = mappedKeyBinding;
  709. }
  710. else if (keyBinding.Length() != 4)
  711. {
  712. LOGERRORF("%s has invalid key binding %s, fallback to WSAD", name.CString(), keyBinding.CString());
  713. keyBinding = "WSAD";
  714. }
  715. element->SetVar(VAR_BUTTON_KEY_BINDING, keyBinding);
  716. }
  717. }
  718. element->SetVar(VAR_SCREEN_JOYSTICK_ID, joystickID);
  719. }
  720. // Make sure all the children are non-focusable so they do not mistakenly to be considered as active UI input controls by application
  721. PODVector<UIElement*> allChildren;
  722. state.screenJoystick_->GetChildren(allChildren, true);
  723. for (PODVector<UIElement*>::Iterator iter = allChildren.Begin(); iter != allChildren.End(); ++iter)
  724. (*iter)->SetFocusMode(FM_NOTFOCUSABLE);
  725. state.Initialize(numButtons, numAxes, numHats);
  726. // There could be potentially more than one screen joystick, however they all will be handled by a same handler method
  727. // So there is no harm to replace the old handler with the new handler in each call to SubscribeToEvent()
  728. SubscribeToEvent(E_TOUCHBEGIN, HANDLER(Input, HandleScreenJoystickTouch));
  729. SubscribeToEvent(E_TOUCHMOVE, HANDLER(Input, HandleScreenJoystickTouch));
  730. SubscribeToEvent(E_TOUCHEND, HANDLER(Input, HandleScreenJoystickTouch));
  731. return joystickID;
  732. */
  733. }
  734. bool Input::RemoveScreenJoystick(SDL_JoystickID id)
  735. {
  736. return true;
  737. }
  738. void Input::SetScreenJoystickVisible(SDL_JoystickID id, bool enable)
  739. {
  740. }
  741. void Input::SetScreenKeyboardVisible(bool enable)
  742. {
  743. if (!graphics_)
  744. return;
  745. if (enable != IsScreenKeyboardVisible())
  746. {
  747. if (enable)
  748. SDL_StartTextInput();
  749. else
  750. SDL_StopTextInput();
  751. }
  752. }
  753. void Input::SetTouchEmulation(bool enable)
  754. {
  755. #if !defined(ANDROID) && !defined(IOS)
  756. if (enable != touchEmulation_)
  757. {
  758. if (enable)
  759. {
  760. // Touch emulation needs the mouse visible
  761. if (!mouseVisible_)
  762. SetMouseVisible(true);
  763. // Add a virtual touch device the first time we are enabling emulated touch
  764. if (!SDL_GetNumTouchDevices())
  765. SDL_AddTouch(0, "Emulated Touch");
  766. }
  767. else
  768. ResetTouches();
  769. touchEmulation_ = enable;
  770. }
  771. #endif
  772. }
  773. bool Input::RecordGesture()
  774. {
  775. // If have no touch devices, fail
  776. if (!SDL_GetNumTouchDevices())
  777. {
  778. LOGERROR("Can not record gesture: no touch devices");
  779. return false;
  780. }
  781. return SDL_RecordGesture(-1) != 0;
  782. }
  783. bool Input::SaveGestures(Serializer& dest)
  784. {
  785. RWOpsWrapper<Serializer> wrapper(dest);
  786. return SDL_SaveAllDollarTemplates(wrapper.GetRWOps()) != 0;
  787. }
  788. bool Input::SaveGesture(Serializer& dest, unsigned gestureID)
  789. {
  790. RWOpsWrapper<Serializer> wrapper(dest);
  791. return SDL_SaveDollarTemplate(gestureID, wrapper.GetRWOps()) != 0;
  792. }
  793. unsigned Input::LoadGestures(Deserializer& source)
  794. {
  795. // If have no touch devices, fail
  796. if (!SDL_GetNumTouchDevices())
  797. {
  798. LOGERROR("Can not load gestures: no touch devices");
  799. return 0;
  800. }
  801. RWOpsWrapper<Deserializer> wrapper(source);
  802. return SDL_LoadDollarTemplates(-1, wrapper.GetRWOps());
  803. }
  804. bool Input::RemoveGesture(unsigned gestureID)
  805. {
  806. #ifdef EMSCRIPTEN
  807. return false;
  808. #else
  809. return SDL_RemoveDollarTemplate(gestureID) != 0;
  810. #endif
  811. }
  812. void Input::RemoveAllGestures()
  813. {
  814. #ifndef EMSCRIPTEN
  815. SDL_RemoveAllDollarTemplates();
  816. #endif
  817. }
  818. SDL_JoystickID Input::OpenJoystick(unsigned index)
  819. {
  820. SDL_Joystick* joystick = SDL_JoystickOpen(index);
  821. if (!joystick)
  822. {
  823. LOGERRORF("Cannot open joystick #%d", index);
  824. return -1;
  825. }
  826. // Create joystick state for the new joystick
  827. int joystickID = SDL_JoystickInstanceID(joystick);
  828. JoystickState& state = joysticks_[joystickID];
  829. state.joystick_ = joystick;
  830. state.joystickID_ = joystickID;
  831. state.name_ = SDL_JoystickName(joystick);
  832. if (SDL_IsGameController(index))
  833. state.controller_ = SDL_GameControllerOpen(index);
  834. unsigned numButtons = SDL_JoystickNumButtons(joystick);
  835. unsigned numAxes = SDL_JoystickNumAxes(joystick);
  836. unsigned numHats = SDL_JoystickNumHats(joystick);
  837. // When the joystick is a controller, make sure there's enough axes & buttons for the standard controller mappings
  838. if (state.controller_)
  839. {
  840. if (numButtons < SDL_CONTROLLER_BUTTON_MAX)
  841. numButtons = SDL_CONTROLLER_BUTTON_MAX;
  842. if (numAxes < SDL_CONTROLLER_AXIS_MAX)
  843. numAxes = SDL_CONTROLLER_AXIS_MAX;
  844. }
  845. state.Initialize(numButtons, numAxes, numHats);
  846. return joystickID;
  847. }
  848. int Input::GetKeyFromName(const String& name) const
  849. {
  850. return SDL_GetKeyFromName(name.CString());
  851. }
  852. int Input::GetKeyFromScancode(int scancode) const
  853. {
  854. return SDL_GetKeyFromScancode((SDL_Scancode)scancode);
  855. }
  856. String Input::GetKeyName(int key) const
  857. {
  858. return String(SDL_GetKeyName(key));
  859. }
  860. int Input::GetScancodeFromKey(int key) const
  861. {
  862. return SDL_GetScancodeFromKey(key);
  863. }
  864. int Input::GetScancodeFromName(const String& name) const
  865. {
  866. return SDL_GetScancodeFromName(name.CString());
  867. }
  868. String Input::GetScancodeName(int scancode) const
  869. {
  870. return SDL_GetScancodeName((SDL_Scancode)scancode);
  871. }
  872. bool Input::GetKeyDown(int key) const
  873. {
  874. return keyDown_.Contains(SDL_toupper(key));
  875. }
  876. bool Input::GetKeyPress(int key) const
  877. {
  878. return keyPress_.Contains(SDL_toupper(key));
  879. }
  880. bool Input::GetScancodeDown(int scancode) const
  881. {
  882. return scancodeDown_.Contains(scancode);
  883. }
  884. bool Input::GetScancodePress(int scancode) const
  885. {
  886. return scancodePress_.Contains(scancode);
  887. }
  888. bool Input::GetMouseButtonDown(int button) const
  889. {
  890. return (mouseButtonDown_ & button) != 0;
  891. }
  892. bool Input::GetMouseButtonPress(int button) const
  893. {
  894. return (mouseButtonPress_ & button) != 0;
  895. }
  896. bool Input::GetQualifierDown(int qualifier) const
  897. {
  898. if (qualifier == QUAL_SHIFT)
  899. return GetKeyDown(KEY_LSHIFT) || GetKeyDown(KEY_RSHIFT);
  900. if (qualifier == QUAL_CTRL)
  901. return GetKeyDown(KEY_LCTRL) || GetKeyDown(KEY_RCTRL);
  902. if (qualifier == QUAL_ALT)
  903. return GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT);
  904. return false;
  905. }
  906. bool Input::GetQualifierPress(int qualifier) const
  907. {
  908. if (qualifier == QUAL_SHIFT)
  909. return GetKeyPress(KEY_LSHIFT) || GetKeyPress(KEY_RSHIFT);
  910. if (qualifier == QUAL_CTRL)
  911. return GetKeyPress(KEY_LCTRL) || GetKeyPress(KEY_RCTRL);
  912. if (qualifier == QUAL_ALT)
  913. return GetKeyPress(KEY_LALT) || GetKeyPress(KEY_RALT);
  914. return false;
  915. }
  916. int Input::GetQualifiers() const
  917. {
  918. int ret = 0;
  919. if (GetQualifierDown(QUAL_SHIFT))
  920. ret |= QUAL_SHIFT;
  921. if (GetQualifierDown(QUAL_CTRL))
  922. ret |= QUAL_CTRL;
  923. if (GetQualifierDown(QUAL_ALT))
  924. ret |= QUAL_ALT;
  925. return ret;
  926. }
  927. IntVector2 Input::GetMousePosition() const
  928. {
  929. IntVector2 ret = IntVector2::ZERO;
  930. if (!initialized_)
  931. return ret;
  932. SDL_GetMouseState(&ret.x_, &ret.y_);
  933. return ret;
  934. }
  935. TouchState* Input::GetTouch(unsigned index) const
  936. {
  937. if (index >= touches_.Size())
  938. return 0;
  939. HashMap<int, TouchState>::ConstIterator i = touches_.Begin();
  940. while (index--)
  941. ++i;
  942. return const_cast<TouchState*>(&i->second_);
  943. }
  944. JoystickState* Input::GetJoystickByIndex(unsigned index)
  945. {
  946. unsigned compare = 0;
  947. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  948. {
  949. if (compare++ == index)
  950. return &(i->second_);
  951. }
  952. return 0;
  953. }
  954. JoystickState* Input::GetJoystick(SDL_JoystickID id)
  955. {
  956. HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Find(id);
  957. return i != joysticks_.End() ? &(i->second_) : 0;
  958. }
  959. bool Input::IsScreenJoystickVisible(SDL_JoystickID id) const
  960. {
  961. return false;
  962. }
  963. bool Input::GetScreenKeyboardSupport() const
  964. {
  965. return graphics_ ? SDL_HasScreenKeyboardSupport() != 0 : false;
  966. }
  967. bool Input::IsScreenKeyboardVisible() const
  968. {
  969. if (graphics_)
  970. {
  971. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  972. return SDL_IsScreenKeyboardShown(window) != SDL_FALSE;
  973. }
  974. else
  975. return false;
  976. }
  977. bool Input::IsMinimized() const
  978. {
  979. // Return minimized state also when unfocused in fullscreen
  980. if (!inputFocus_ && graphics_ && graphics_->GetFullscreen())
  981. return true;
  982. else
  983. return minimized_;
  984. }
  985. void Input::Initialize()
  986. {
  987. Graphics* graphics = GetSubsystem<Graphics>();
  988. if (!graphics || !graphics->IsInitialized())
  989. return;
  990. graphics_ = graphics;
  991. // In external window mode only visible mouse is supported
  992. if (graphics_->GetExternalWindow())
  993. mouseVisible_ = true;
  994. // Set the initial activation
  995. initialized_ = true;
  996. #ifndef EMSCRIPTEN
  997. focusedThisFrame_ = true;
  998. #else
  999. // Note: Page visibility and focus are slightly different, however we can't query last focus with Emscripten (1.29.0)
  1000. if (emscriptenInput_->IsVisible())
  1001. GainFocus();
  1002. else
  1003. LoseFocus();
  1004. #endif
  1005. ResetJoysticks();
  1006. ResetState();
  1007. SubscribeToEvent(E_BEGINFRAME, HANDLER(Input, HandleBeginFrame));
  1008. LOGINFO("Initialized input");
  1009. }
  1010. void Input::ResetJoysticks()
  1011. {
  1012. joysticks_.Clear();
  1013. // Open each detected joystick automatically on startup
  1014. int size = SDL_NumJoysticks();
  1015. for (int i = 0; i < size; ++i)
  1016. OpenJoystick(i);
  1017. }
  1018. void Input::GainFocus()
  1019. {
  1020. ResetState();
  1021. inputFocus_ = true;
  1022. focusedThisFrame_ = false;
  1023. // Restore mouse mode
  1024. MouseMode mm = mouseMode_;
  1025. mouseMode_ = MM_ABSOLUTE;
  1026. SetMouseMode(mm);
  1027. // Re-establish mouse cursor hiding as necessary
  1028. if (!mouseVisible_)
  1029. {
  1030. SDL_ShowCursor(SDL_FALSE);
  1031. suppressNextMouseMove_ = true;
  1032. }
  1033. else
  1034. lastMousePosition_ = GetMousePosition();
  1035. SendInputFocusEvent();
  1036. }
  1037. void Input::LoseFocus()
  1038. {
  1039. ResetState();
  1040. inputFocus_ = false;
  1041. focusedThisFrame_ = false;
  1042. MouseMode mm = mouseMode_;
  1043. // Show the mouse cursor when inactive
  1044. SDL_ShowCursor(SDL_TRUE);
  1045. // Change mouse mode -- removing any cursor grabs, etc.
  1046. SetMouseMode(MM_ABSOLUTE);
  1047. // Restore flags to reflect correct mouse state.
  1048. mouseMode_ = mm;
  1049. SendInputFocusEvent();
  1050. }
  1051. void Input::ResetState()
  1052. {
  1053. keyDown_.Clear();
  1054. keyPress_.Clear();
  1055. scancodeDown_.Clear();
  1056. scancodePress_.Clear();
  1057. /// \todo Check if resetting joystick state on input focus loss is even necessary
  1058. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  1059. i->second_.Reset();
  1060. ResetTouches();
  1061. // Use SetMouseButton() to reset the state so that mouse events will be sent properly
  1062. SetMouseButton(MOUSEB_LEFT, false);
  1063. SetMouseButton(MOUSEB_RIGHT, false);
  1064. SetMouseButton(MOUSEB_MIDDLE, false);
  1065. mouseMove_ = IntVector2::ZERO;
  1066. mouseMoveWheel_ = 0;
  1067. mouseButtonPress_ = 0;
  1068. }
  1069. void Input::ResetTouches()
  1070. {
  1071. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  1072. {
  1073. TouchState& state = i->second_;
  1074. using namespace TouchEnd;
  1075. VariantMap& eventData = GetEventDataMap();
  1076. eventData[P_TOUCHID] = state.touchID_;
  1077. eventData[P_X] = state.position_.x_;
  1078. eventData[P_Y] = state.position_.y_;
  1079. SendEvent(E_TOUCHEND, eventData);
  1080. }
  1081. touches_.Clear();
  1082. touchIDMap_.Clear();
  1083. availableTouchIDs_.Clear();
  1084. for (int i = 0; i < TOUCHID_MAX; i++)
  1085. availableTouchIDs_.Push(i);
  1086. }
  1087. unsigned Input::GetTouchIndexFromID(int touchID)
  1088. {
  1089. HashMap<int, int>::ConstIterator i = touchIDMap_.Find(touchID);
  1090. if (i != touchIDMap_.End())
  1091. {
  1092. return i->second_;
  1093. }
  1094. int index = PopTouchIndex();
  1095. touchIDMap_[touchID] = index;
  1096. return index;
  1097. }
  1098. unsigned Input::PopTouchIndex()
  1099. {
  1100. if (availableTouchIDs_.Empty())
  1101. return 0;
  1102. unsigned index = availableTouchIDs_.Front();
  1103. availableTouchIDs_.PopFront();
  1104. return index;
  1105. }
  1106. void Input::PushTouchIndex(int touchID)
  1107. {
  1108. HashMap<int, int>::ConstIterator ci = touchIDMap_.Find(touchID);
  1109. if (ci == touchIDMap_.End())
  1110. return;
  1111. int index = touchIDMap_[touchID];
  1112. touchIDMap_.Erase(touchID);
  1113. // Sorted insertion
  1114. bool inserted = false;
  1115. for (List<int>::Iterator i = availableTouchIDs_.Begin(); i != availableTouchIDs_.End(); ++i)
  1116. {
  1117. if (*i == index)
  1118. {
  1119. // This condition can occur when TOUCHID_MAX is reached.
  1120. inserted = true;
  1121. break;
  1122. }
  1123. if (*i > index)
  1124. {
  1125. availableTouchIDs_.Insert(i, index);
  1126. inserted = true;
  1127. break;
  1128. }
  1129. }
  1130. // If empty, or the lowest value then insert at end.
  1131. if (!inserted)
  1132. availableTouchIDs_.Push(index);
  1133. }
  1134. void Input::SendInputFocusEvent()
  1135. {
  1136. using namespace InputFocus;
  1137. VariantMap& eventData = GetEventDataMap();
  1138. eventData[P_FOCUS] = HasFocus();
  1139. eventData[P_MINIMIZED] = IsMinimized();
  1140. SendEvent(E_INPUTFOCUS, eventData);
  1141. }
  1142. void Input::SetMouseButton(int button, bool newState)
  1143. {
  1144. #ifdef EMSCRIPTEN
  1145. if (emscriptenEnteredPointerLock_)
  1146. {
  1147. // Suppress mouse jump on initial Pointer Lock
  1148. IntVector2 mousePosition = GetMousePosition();
  1149. lastMousePosition_ = mousePosition;
  1150. mouseMove_ = IntVector2::ZERO;
  1151. suppressNextMouseMove_ = true;
  1152. emscriptenEnteredPointerLock_ = false;
  1153. }
  1154. #endif
  1155. if (newState)
  1156. {
  1157. if (!(mouseButtonDown_ & button))
  1158. mouseButtonPress_ |= button;
  1159. mouseButtonDown_ |= button;
  1160. }
  1161. else
  1162. {
  1163. if (!(mouseButtonDown_ & button))
  1164. return;
  1165. mouseButtonDown_ &= ~button;
  1166. }
  1167. using namespace MouseButtonDown;
  1168. VariantMap& eventData = GetEventDataMap();
  1169. eventData[P_BUTTON] = button;
  1170. eventData[P_BUTTONS] = mouseButtonDown_;
  1171. eventData[P_QUALIFIERS] = GetQualifiers();
  1172. SendEvent(newState ? E_MOUSEBUTTONDOWN : E_MOUSEBUTTONUP, eventData);
  1173. }
  1174. void Input::SetKey(int key, int scancode, unsigned raw, bool newState)
  1175. {
  1176. bool repeat = false;
  1177. if (newState)
  1178. {
  1179. scancodeDown_.Insert(scancode);
  1180. scancodePress_.Insert(scancode);
  1181. if (!keyDown_.Contains(key))
  1182. {
  1183. keyDown_.Insert(key);
  1184. keyPress_.Insert(key);
  1185. }
  1186. else
  1187. repeat = true;
  1188. }
  1189. else
  1190. {
  1191. scancodeDown_.Erase(scancode);
  1192. if (!keyDown_.Erase(key))
  1193. return;
  1194. }
  1195. using namespace KeyDown;
  1196. VariantMap& eventData = GetEventDataMap();
  1197. eventData[P_KEY] = key;
  1198. eventData[P_SCANCODE] = scancode;
  1199. eventData[P_RAW] = raw;
  1200. eventData[P_BUTTONS] = mouseButtonDown_;
  1201. eventData[P_QUALIFIERS] = GetQualifiers();
  1202. if (newState)
  1203. eventData[P_REPEAT] = repeat;
  1204. SendEvent(newState ? E_KEYDOWN : E_KEYUP, eventData);
  1205. if ((key == KEY_RETURN || key == KEY_RETURN2 || key == KEY_KP_ENTER) && newState && !repeat && toggleFullscreen_ &&
  1206. (GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT)))
  1207. graphics_->ToggleFullscreen();
  1208. }
  1209. void Input::SetMouseWheel(int delta)
  1210. {
  1211. if (delta)
  1212. {
  1213. mouseMoveWheel_ += delta;
  1214. using namespace MouseWheel;
  1215. VariantMap& eventData = GetEventDataMap();
  1216. eventData[P_WHEEL] = delta;
  1217. eventData[P_BUTTONS] = mouseButtonDown_;
  1218. eventData[P_QUALIFIERS] = GetQualifiers();
  1219. SendEvent(E_MOUSEWHEEL, eventData);
  1220. }
  1221. }
  1222. void Input::SetMousePosition(const IntVector2& position)
  1223. {
  1224. if (!graphics_)
  1225. return;
  1226. SDL_WarpMouseInWindow(graphics_->GetImpl()->GetWindow(), position.x_, position.y_);
  1227. }
  1228. void Input::HandleSDLEvent(void* sdlEvent)
  1229. {
  1230. SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
  1231. // While not having input focus, skip key/mouse/touch/joystick events, except for the "click to focus" mechanism
  1232. if (!inputFocus_ && evt.type >= SDL_KEYDOWN && evt.type <= SDL_MULTIGESTURE)
  1233. {
  1234. #ifdef REQUIRE_CLICK_TO_FOCUS
  1235. // Require the click to be at least 1 pixel inside the window to disregard clicks in the title bar
  1236. if (evt.type == SDL_MOUSEBUTTONDOWN && evt.button.x > 0 && evt.button.y > 0 && evt.button.x < graphics_->GetWidth() - 1 &&
  1237. evt.button.y < graphics_->GetHeight() - 1)
  1238. {
  1239. focusedThisFrame_ = true;
  1240. // Do not cause the click to actually go throughfin
  1241. return;
  1242. }
  1243. else if (evt.type == SDL_FINGERDOWN)
  1244. {
  1245. // When focusing by touch, call GainFocus() immediately as it resets the state; a touch has sustained state
  1246. // which should be kept
  1247. GainFocus();
  1248. }
  1249. else
  1250. #endif
  1251. return;
  1252. }
  1253. switch (evt.type)
  1254. {
  1255. case SDL_KEYDOWN:
  1256. // Convert to uppercase to match Win32 virtual key codes
  1257. #ifdef EMSCRIPTEN
  1258. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, 0, true);
  1259. #else
  1260. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, true);
  1261. #endif
  1262. break;
  1263. case SDL_KEYUP:
  1264. #ifdef EMSCRIPTEN
  1265. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, 0, false);
  1266. #else
  1267. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), evt.key.keysym.scancode, evt.key.keysym.raw, false);
  1268. #endif
  1269. break;
  1270. case SDL_TEXTINPUT:
  1271. {
  1272. textInput_ = &evt.text.text[0];
  1273. unsigned unicode = textInput_.AtUTF8(0);
  1274. if (unicode)
  1275. {
  1276. using namespace TextInput;
  1277. VariantMap textInputEventData;
  1278. textInputEventData[P_TEXT] = textInput_;
  1279. textInputEventData[P_BUTTONS] = mouseButtonDown_;
  1280. textInputEventData[P_QUALIFIERS] = GetQualifiers();
  1281. SendEvent(E_TEXTINPUT, textInputEventData);
  1282. }
  1283. }
  1284. break;
  1285. case SDL_MOUSEBUTTONDOWN:
  1286. if (!touchEmulation_)
  1287. SetMouseButton(1 << (evt.button.button - 1), true);
  1288. else
  1289. {
  1290. int x, y;
  1291. SDL_GetMouseState(&x, &y);
  1292. SDL_Event event;
  1293. event.type = SDL_FINGERDOWN;
  1294. event.tfinger.touchId = 0;
  1295. event.tfinger.fingerId = evt.button.button - 1;
  1296. event.tfinger.pressure = 1.0f;
  1297. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1298. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1299. event.tfinger.dx = 0;
  1300. event.tfinger.dy = 0;
  1301. SDL_PushEvent(&event);
  1302. }
  1303. break;
  1304. case SDL_MOUSEBUTTONUP:
  1305. if (!touchEmulation_)
  1306. SetMouseButton(1 << (evt.button.button - 1), false);
  1307. else
  1308. {
  1309. int x, y;
  1310. SDL_GetMouseState(&x, &y);
  1311. SDL_Event event;
  1312. event.type = SDL_FINGERUP;
  1313. event.tfinger.touchId = 0;
  1314. event.tfinger.fingerId = evt.button.button - 1;
  1315. event.tfinger.pressure = 0.0f;
  1316. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1317. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1318. event.tfinger.dx = 0;
  1319. event.tfinger.dy = 0;
  1320. SDL_PushEvent(&event);
  1321. }
  1322. break;
  1323. case SDL_MOUSEMOTION:
  1324. // Emscripten will use SDL mouse move events for relative mode, as repositioning the mouse and
  1325. // measuring distance from window center is not supported
  1326. #ifndef EMSCRIPTEN
  1327. if (mouseVisible_ && !touchEmulation_)
  1328. #else
  1329. if ((mouseVisible_ || mouseMode_ == MM_RELATIVE) && !touchEmulation_)
  1330. #endif
  1331. {
  1332. mouseMove_.x_ += evt.motion.xrel;
  1333. mouseMove_.y_ += evt.motion.yrel;
  1334. using namespace MouseMove;
  1335. VariantMap& eventData = GetEventDataMap();
  1336. if (mouseVisible_)
  1337. {
  1338. eventData[P_X] = evt.motion.x;
  1339. eventData[P_Y] = evt.motion.y;
  1340. }
  1341. eventData[P_DX] = evt.motion.xrel;
  1342. eventData[P_DY] = evt.motion.yrel;
  1343. eventData[P_BUTTONS] = mouseButtonDown_;
  1344. eventData[P_QUALIFIERS] = GetQualifiers();
  1345. SendEvent(E_MOUSEMOVE, eventData);
  1346. }
  1347. // Only the left mouse button "finger" moves along with the mouse movement
  1348. else if (touchEmulation_ && touches_.Contains(0))
  1349. {
  1350. int x, y;
  1351. SDL_GetMouseState(&x, &y);
  1352. SDL_Event event;
  1353. event.type = SDL_FINGERMOTION;
  1354. event.tfinger.touchId = 0;
  1355. event.tfinger.fingerId = 0;
  1356. event.tfinger.pressure = 1.0f;
  1357. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1358. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1359. event.tfinger.dx = (float)evt.motion.xrel / (float)graphics_->GetWidth();
  1360. event.tfinger.dy = (float)evt.motion.yrel / (float)graphics_->GetHeight();
  1361. SDL_PushEvent(&event);
  1362. }
  1363. break;
  1364. case SDL_MOUSEWHEEL:
  1365. if (!touchEmulation_)
  1366. SetMouseWheel(evt.wheel.y);
  1367. break;
  1368. case SDL_FINGERDOWN:
  1369. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1370. {
  1371. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
  1372. TouchState& state = touches_[touchID];
  1373. state.touchID_ = touchID;
  1374. #ifndef EMSCRIPTEN
  1375. state.lastPosition_ = state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  1376. (int)(evt.tfinger.y * graphics_->GetHeight()));
  1377. #else
  1378. state.position_ = IntVector2((int)(evt.tfinger.x), (int)(evt.tfinger.y));
  1379. #endif
  1380. state.delta_ = IntVector2::ZERO;
  1381. state.pressure_ = evt.tfinger.pressure;
  1382. using namespace TouchBegin;
  1383. VariantMap& eventData = GetEventDataMap();
  1384. eventData[P_TOUCHID] = touchID;
  1385. eventData[P_X] = state.position_.x_;
  1386. eventData[P_Y] = state.position_.y_;
  1387. eventData[P_PRESSURE] = state.pressure_;
  1388. SendEvent(E_TOUCHBEGIN, eventData);
  1389. // Finger touch may move the mouse cursor. Suppress next mouse move when cursor hidden to prevent jumps
  1390. if (!mouseVisible_)
  1391. suppressNextMouseMove_ = true;
  1392. }
  1393. break;
  1394. case SDL_FINGERUP:
  1395. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1396. {
  1397. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
  1398. TouchState& state = touches_[touchID];
  1399. using namespace TouchEnd;
  1400. VariantMap& eventData = GetEventDataMap();
  1401. // Do not trust the position in the finger up event. Instead use the last position stored in the
  1402. // touch structure
  1403. eventData[P_TOUCHID] = touchID;
  1404. eventData[P_X] = state.position_.x_;
  1405. eventData[P_Y] = state.position_.y_;
  1406. SendEvent(E_TOUCHEND, eventData);
  1407. // Add touch index back to list of available touch Ids
  1408. PushTouchIndex(evt.tfinger.fingerId & 0x7ffffff);
  1409. touches_.Erase(touchID);
  1410. }
  1411. break;
  1412. case SDL_FINGERMOTION:
  1413. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1414. {
  1415. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffff);
  1416. // We don't want this event to create a new touches_ event if it doesn't exist (touchEmulation)
  1417. if (touchEmulation_ && !touches_.Contains(touchID))
  1418. break;
  1419. TouchState& state = touches_[touchID];
  1420. state.touchID_ = touchID;
  1421. #ifndef EMSCRIPTEN
  1422. state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  1423. (int)(evt.tfinger.y * graphics_->GetHeight()));
  1424. #else
  1425. state.position_ = IntVector2((int)(evt.tfinger.x), (int)(evt.tfinger.y));
  1426. #endif
  1427. state.delta_ = state.position_ - state.lastPosition_;
  1428. state.pressure_ = evt.tfinger.pressure;
  1429. using namespace TouchMove;
  1430. VariantMap& eventData = GetEventDataMap();
  1431. eventData[P_TOUCHID] = touchID;
  1432. eventData[P_X] = state.position_.x_;
  1433. eventData[P_Y] = state.position_.y_;
  1434. #ifndef EMSCRIPTEN
  1435. eventData[P_DX] = (int)(evt.tfinger.dx * graphics_->GetWidth());
  1436. eventData[P_DY] = (int)(evt.tfinger.dy * graphics_->GetHeight());
  1437. #else
  1438. eventData[P_DX] = (int)(evt.tfinger.dx);
  1439. eventData[P_DY] = (int)(evt.tfinger.dy);
  1440. #endif
  1441. eventData[P_PRESSURE] = state.pressure_;
  1442. SendEvent(E_TOUCHMOVE, eventData);
  1443. // Finger touch may move the mouse cursor. Suppress next mouse move when cursor hidden to prevent jumps
  1444. if (!mouseVisible_)
  1445. suppressNextMouseMove_ = true;
  1446. }
  1447. break;
  1448. case SDL_DOLLARRECORD:
  1449. {
  1450. using namespace GestureRecorded;
  1451. VariantMap& eventData = GetEventDataMap();
  1452. eventData[P_GESTUREID] = (int)evt.dgesture.gestureId;
  1453. SendEvent(E_GESTURERECORDED, eventData);
  1454. }
  1455. break;
  1456. case SDL_DOLLARGESTURE:
  1457. {
  1458. using namespace GestureInput;
  1459. VariantMap& eventData = GetEventDataMap();
  1460. eventData[P_GESTUREID] = (int)evt.dgesture.gestureId;
  1461. eventData[P_CENTERX] = (int)(evt.dgesture.x * graphics_->GetWidth());
  1462. eventData[P_CENTERY] = (int)(evt.dgesture.y * graphics_->GetHeight());
  1463. eventData[P_NUMFINGERS] = (int)evt.dgesture.numFingers;
  1464. eventData[P_ERROR] = evt.dgesture.error;
  1465. SendEvent(E_GESTUREINPUT, eventData);
  1466. }
  1467. break;
  1468. case SDL_MULTIGESTURE:
  1469. {
  1470. using namespace MultiGesture;
  1471. VariantMap& eventData = GetEventDataMap();
  1472. eventData[P_CENTERX] = (int)(evt.mgesture.x * graphics_->GetWidth());
  1473. eventData[P_CENTERY] = (int)(evt.mgesture.y * graphics_->GetHeight());
  1474. eventData[P_NUMFINGERS] = (int)evt.mgesture.numFingers;
  1475. eventData[P_DTHETA] = M_RADTODEG * evt.mgesture.dTheta;
  1476. eventData[P_DDIST] = evt.mgesture.dDist;
  1477. SendEvent(E_MULTIGESTURE, eventData);
  1478. }
  1479. break;
  1480. case SDL_JOYDEVICEADDED:
  1481. {
  1482. using namespace JoystickConnected;
  1483. SDL_JoystickID joystickID = OpenJoystick(evt.jdevice.which);
  1484. VariantMap& eventData = GetEventDataMap();
  1485. eventData[P_JOYSTICKID] = joystickID;
  1486. SendEvent(E_JOYSTICKCONNECTED, eventData);
  1487. }
  1488. break;
  1489. case SDL_JOYDEVICEREMOVED:
  1490. {
  1491. using namespace JoystickDisconnected;
  1492. joysticks_.Erase(evt.jdevice.which);
  1493. VariantMap& eventData = GetEventDataMap();
  1494. eventData[P_JOYSTICKID] = evt.jdevice.which;
  1495. SendEvent(E_JOYSTICKDISCONNECTED, eventData);
  1496. }
  1497. break;
  1498. case SDL_JOYBUTTONDOWN:
  1499. {
  1500. using namespace JoystickButtonDown;
  1501. unsigned button = evt.jbutton.button;
  1502. SDL_JoystickID joystickID = evt.jbutton.which;
  1503. JoystickState& state = joysticks_[joystickID];
  1504. // Skip ordinary joystick event for a controller
  1505. if (!state.controller_)
  1506. {
  1507. VariantMap& eventData = GetEventDataMap();
  1508. eventData[P_JOYSTICKID] = joystickID;
  1509. eventData[P_BUTTON] = button;
  1510. if (button < state.buttons_.Size())
  1511. {
  1512. state.buttons_[button] = true;
  1513. state.buttonPress_[button] = true;
  1514. SendEvent(E_JOYSTICKBUTTONDOWN, eventData);
  1515. }
  1516. }
  1517. }
  1518. break;
  1519. case SDL_JOYBUTTONUP:
  1520. {
  1521. using namespace JoystickButtonUp;
  1522. unsigned button = evt.jbutton.button;
  1523. SDL_JoystickID joystickID = evt.jbutton.which;
  1524. JoystickState& state = joysticks_[joystickID];
  1525. if (!state.controller_)
  1526. {
  1527. VariantMap& eventData = GetEventDataMap();
  1528. eventData[P_JOYSTICKID] = joystickID;
  1529. eventData[P_BUTTON] = button;
  1530. if (button < state.buttons_.Size())
  1531. {
  1532. if (!state.controller_)
  1533. state.buttons_[button] = false;
  1534. SendEvent(E_JOYSTICKBUTTONUP, eventData);
  1535. }
  1536. }
  1537. }
  1538. break;
  1539. case SDL_JOYAXISMOTION:
  1540. {
  1541. using namespace JoystickAxisMove;
  1542. SDL_JoystickID joystickID = evt.jaxis.which;
  1543. JoystickState& state = joysticks_[joystickID];
  1544. if (!state.controller_)
  1545. {
  1546. VariantMap& eventData = GetEventDataMap();
  1547. eventData[P_JOYSTICKID] = joystickID;
  1548. eventData[P_AXIS] = evt.jaxis.axis;
  1549. eventData[P_POSITION] = Clamp((float)evt.jaxis.value / 32767.0f, -1.0f, 1.0f);
  1550. if (evt.jaxis.axis < state.axes_.Size())
  1551. {
  1552. // If the joystick is a controller, only use the controller axis mappings
  1553. // (we'll also get the controller event)
  1554. if (!state.controller_)
  1555. state.axes_[evt.jaxis.axis] = eventData[P_POSITION].GetFloat();
  1556. SendEvent(E_JOYSTICKAXISMOVE, eventData);
  1557. }
  1558. }
  1559. }
  1560. break;
  1561. case SDL_JOYHATMOTION:
  1562. {
  1563. using namespace JoystickHatMove;
  1564. SDL_JoystickID joystickID = evt.jaxis.which;
  1565. JoystickState& state = joysticks_[joystickID];
  1566. VariantMap& eventData = GetEventDataMap();
  1567. eventData[P_JOYSTICKID] = joystickID;
  1568. eventData[P_HAT] = evt.jhat.hat;
  1569. eventData[P_POSITION] = evt.jhat.value;
  1570. if (evt.jhat.hat < state.hats_.Size())
  1571. {
  1572. state.hats_[evt.jhat.hat] = evt.jhat.value;
  1573. SendEvent(E_JOYSTICKHATMOVE, eventData);
  1574. }
  1575. }
  1576. break;
  1577. case SDL_CONTROLLERBUTTONDOWN:
  1578. {
  1579. using namespace JoystickButtonDown;
  1580. unsigned button = evt.cbutton.button;
  1581. SDL_JoystickID joystickID = evt.cbutton.which;
  1582. JoystickState& state = joysticks_[joystickID];
  1583. VariantMap& eventData = GetEventDataMap();
  1584. eventData[P_JOYSTICKID] = joystickID;
  1585. eventData[P_BUTTON] = button;
  1586. if (button < state.buttons_.Size())
  1587. {
  1588. state.buttons_[button] = true;
  1589. state.buttonPress_[button] = true;
  1590. SendEvent(E_JOYSTICKBUTTONDOWN, eventData);
  1591. }
  1592. }
  1593. break;
  1594. case SDL_CONTROLLERBUTTONUP:
  1595. {
  1596. using namespace JoystickButtonUp;
  1597. unsigned button = evt.cbutton.button;
  1598. SDL_JoystickID joystickID = evt.cbutton.which;
  1599. JoystickState& state = joysticks_[joystickID];
  1600. VariantMap& eventData = GetEventDataMap();
  1601. eventData[P_JOYSTICKID] = joystickID;
  1602. eventData[P_BUTTON] = button;
  1603. if (button < state.buttons_.Size())
  1604. {
  1605. state.buttons_[button] = false;
  1606. SendEvent(E_JOYSTICKBUTTONUP, eventData);
  1607. }
  1608. }
  1609. break;
  1610. case SDL_CONTROLLERAXISMOTION:
  1611. {
  1612. using namespace JoystickAxisMove;
  1613. SDL_JoystickID joystickID = evt.caxis.which;
  1614. JoystickState& state = joysticks_[joystickID];
  1615. VariantMap& eventData = GetEventDataMap();
  1616. eventData[P_JOYSTICKID] = joystickID;
  1617. eventData[P_AXIS] = evt.caxis.axis;
  1618. eventData[P_POSITION] = Clamp((float)evt.caxis.value / 32767.0f, -1.0f, 1.0f);
  1619. if (evt.caxis.axis < state.axes_.Size())
  1620. {
  1621. state.axes_[evt.caxis.axis] = eventData[P_POSITION].GetFloat();
  1622. SendEvent(E_JOYSTICKAXISMOVE, eventData);
  1623. }
  1624. }
  1625. break;
  1626. case SDL_WINDOWEVENT:
  1627. {
  1628. switch (evt.window.event)
  1629. {
  1630. case SDL_WINDOWEVENT_MINIMIZED:
  1631. minimized_ = true;
  1632. SendInputFocusEvent();
  1633. break;
  1634. case SDL_WINDOWEVENT_MAXIMIZED:
  1635. case SDL_WINDOWEVENT_RESTORED:
  1636. minimized_ = false;
  1637. SendInputFocusEvent();
  1638. #ifdef IOS
  1639. // On iOS we never lose the GL context, but may have done GPU object changes that could not be applied yet.
  1640. // Apply them now
  1641. graphics_->Restore();
  1642. #endif
  1643. break;
  1644. #ifdef ANDROID
  1645. case SDL_WINDOWEVENT_FOCUS_GAINED:
  1646. // Restore GPU objects to the new GL context
  1647. graphics_->Restore();
  1648. break;
  1649. #endif
  1650. case SDL_WINDOWEVENT_RESIZED:
  1651. inResize_ = true;
  1652. graphics_->WindowResized();
  1653. inResize_ = false;
  1654. break;
  1655. case SDL_WINDOWEVENT_MOVED:
  1656. graphics_->WindowMoved();
  1657. break;
  1658. }
  1659. }
  1660. break;
  1661. case SDL_DROPFILE:
  1662. {
  1663. using namespace DropFile;
  1664. VariantMap& eventData = GetEventDataMap();
  1665. eventData[P_FILENAME] = GetInternalPath(String(evt.drop.file));
  1666. SDL_free(evt.drop.file);
  1667. SendEvent(E_DROPFILE, eventData);
  1668. }
  1669. break;
  1670. case SDL_QUIT:
  1671. SendEvent(E_EXITREQUESTED);
  1672. break;
  1673. }
  1674. }
  1675. void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  1676. {
  1677. // Reset input state on subsequent initializations
  1678. if (!initialized_)
  1679. Initialize();
  1680. else
  1681. ResetState();
  1682. // Re-enable cursor clipping, and re-center the cursor (if needed) to the new screen size, so that there is no erroneous
  1683. // mouse move event. Also get new window ID if it changed
  1684. SDL_Window* window = graphics_->GetImpl()->GetWindow();
  1685. windowID_ = SDL_GetWindowID(window);
  1686. // If screen mode happens due to mouse drag resize, do not recenter the mouse as that would lead to erratic window sizes
  1687. if (!mouseVisible_ && !inResize_)
  1688. {
  1689. IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  1690. SetMousePosition(center);
  1691. lastMousePosition_ = center;
  1692. focusedThisFrame_ = true;
  1693. }
  1694. else
  1695. lastMousePosition_ = GetMousePosition();
  1696. }
  1697. if (graphics_->GetFullscreen())
  1698. focusedThisFrame_ = true;
  1699. // After setting a new screen mode we should not be minimized
  1700. minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;
  1701. // Remember that screen mode changed in case we lose focus (needed on Linux)
  1702. if (!inResize_)
  1703. screenModeChanged_ = true;
  1704. }
  1705. void Input::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  1706. {
  1707. // Update input right at the beginning of the frame
  1708. Update();
  1709. }
  1710. void Input::HandleScreenJoystickTouch(StringHash eventType, VariantMap& eventData)
  1711. {
  1712. }
  1713. }