Input.cpp 68 KB

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