Input.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577
  1. // Copyright (c) 2008-2022 the Urho3D project
  2. // License: MIT
  3. #include "../Precompiled.h"
  4. #include "../Core/Context.h"
  5. #include "../Core/CoreEvents.h"
  6. #include "../Core/Mutex.h"
  7. #include "../Core/ProcessUtils.h"
  8. #include "../Core/Profiler.h"
  9. #include "../Core/StringUtils.h"
  10. #include "../Graphics/Graphics.h"
  11. #include "../Graphics/GraphicsEvents.h"
  12. #include "../Input/Input.h"
  13. #include "../IO/FileSystem.h"
  14. #include "../IO/Log.h"
  15. #include "../IO/RWOpsWrapper.h"
  16. #include "../Resource/ResourceCache.h"
  17. #include "../UI/Text.h"
  18. #include "../UI/UI.h"
  19. #ifdef _WIN32
  20. #include "../Engine/Engine.h"
  21. #endif
  22. #include <SDL/SDL.h>
  23. #ifdef __EMSCRIPTEN__
  24. #include <emscripten/html5.h>
  25. #endif
  26. #include "../DebugNew.h"
  27. using namespace std;
  28. extern "C" int SDL_AddTouch(SDL_TouchID touchID, SDL_TouchDeviceType type, const char* name);
  29. // Use a "click inside window to focus" mechanism on desktop platforms when the mouse cursor is hidden
  30. #if defined(_WIN32) || (defined(__APPLE__) && !defined(IOS) && !defined(TVOS)) || (defined(__linux__) && !defined(__ANDROID__))
  31. #define REQUIRE_CLICK_TO_FOCUS
  32. #endif
  33. namespace Urho3D
  34. {
  35. const int SCREEN_JOYSTICK_START_ID = 0x40000000;
  36. const StringHash VAR_BUTTON_KEY_BINDING("VAR_BUTTON_KEY_BINDING");
  37. const StringHash VAR_BUTTON_MOUSE_BUTTON_BINDING("VAR_BUTTON_MOUSE_BUTTON_BINDING");
  38. const StringHash VAR_LAST_KEYSYM("VAR_LAST_KEYSYM");
  39. const StringHash VAR_SCREEN_JOYSTICK_ID("VAR_SCREEN_JOYSTICK_ID");
  40. const unsigned TOUCHID_MAX = 32;
  41. /// Convert SDL keycode if necessary.
  42. Key ConvertSDLKeyCode(int keySym, int scanCode)
  43. {
  44. if (scanCode == SCANCODE_AC_BACK)
  45. return KEY_ESCAPE;
  46. else
  47. return (Key)SDL_tolower(keySym);
  48. }
  49. UIElement* TouchState::GetTouchedElement()
  50. {
  51. return touchedElement_.Get();
  52. }
  53. #ifdef __EMSCRIPTEN__
  54. #define EM_TRUE 1
  55. #define EM_FALSE 0
  56. /// Glue between Urho Input and Emscripten HTML5
  57. /** 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.
  58. *
  59. * Mouse Input:
  60. * - The OS mouse cursor position can't be set.
  61. * - The mouse can be trapped within play area via 'PointerLock API', which requires a request and interaction between the user and browser.
  62. * - To request mouse lock, call SetMouseMode(MM_RELATIVE). The E_MOUSEMODECHANGED event will be sent if/when the user confirms the request.
  63. * NOTE: The request must be initiated by the user (eg: on mouse button down/up, key down/up).
  64. * - The user can press 'escape' key and browser will force user out of pointer lock. Urho will send the E_MOUSEMODECHANGED event.
  65. * - SetMouseMode(MM_ABSOLUTE) will leave pointer lock.
  66. * - MM_WRAP is unsupported.
  67. */
  68. /// % Emscripten Input glue. Intended to be used by the Input subsystem only.
  69. class EmscriptenInput
  70. {
  71. friend class Input;
  72. public:
  73. /// Constructor, expecting pointer to constructing Input instance.
  74. EmscriptenInput(Input* inputInst);
  75. /// Static callback method for Pointer Lock API. Handles change in Pointer Lock state and sends events for mouse mode change.
  76. static EM_BOOL HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData);
  77. /// Static callback method for tracking focus change events.
  78. static EM_BOOL HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData);
  79. /// Static callback method for suppressing mouse jump.
  80. static EM_BOOL HandleMouseJump(int eventType, const EmscriptenMouseEvent * mouseEvent, void* userData);
  81. /// Static callback method to handle SDL events.
  82. static int HandleSDLEvents(void* userData, SDL_Event* event);
  83. /// Send request to user to gain pointer lock. This requires a user-browser interaction on the first call.
  84. void RequestPointerLock(MouseMode mode, bool suppressEvent = false);
  85. /// Send request to exit pointer lock. This has the benefit of not requiring the user-browser interaction on the next pointer lock request.
  86. void ExitPointerLock(bool suppressEvent = false);
  87. /// Returns whether the page is visible.
  88. bool IsVisible();
  89. private:
  90. /// Instance of Input subsystem that constructed this instance.
  91. Input* inputInst_;
  92. /// The mouse mode being requested for pointer-lock.
  93. static MouseMode requestedMouseMode_;
  94. /// Flag indicating whether to suppress the next mouse mode change event.
  95. static bool suppressMouseModeEvent_;
  96. /// The mouse mode of the previous request for pointer-lock.
  97. static MouseMode invalidatedRequestedMouseMode_;
  98. /// Flag indicating the previous request to suppress the next mouse mode change event.
  99. static bool invalidatedSuppressMouseModeEvent_;
  100. };
  101. bool EmscriptenInput::suppressMouseModeEvent_ = false;
  102. MouseMode EmscriptenInput::requestedMouseMode_ = MM_INVALID;
  103. bool EmscriptenInput::invalidatedSuppressMouseModeEvent_ = false;
  104. MouseMode EmscriptenInput::invalidatedRequestedMouseMode_ = MM_INVALID;
  105. EmscriptenInput::EmscriptenInput(Input* inputInst) :
  106. inputInst_(inputInst)
  107. {
  108. auto* vInputInst = (void*)inputInst;
  109. // Handle pointer lock
  110. emscripten_set_pointerlockchange_callback(NULL, vInputInst, false, EmscriptenInput::HandlePointerLockChange);
  111. // Handle mouse events to prevent mouse jumps
  112. emscripten_set_mousedown_callback(NULL, vInputInst, true, EmscriptenInput::HandleMouseJump);
  113. emscripten_set_mousemove_callback(NULL, vInputInst, true, EmscriptenInput::HandleMouseJump);
  114. // Handle focus changes
  115. emscripten_set_focusout_callback(NULL, vInputInst, false, EmscriptenInput::HandleFocusChange);
  116. emscripten_set_focus_callback(NULL, vInputInst, false, EmscriptenInput::HandleFocusChange);
  117. // Handle SDL events
  118. SDL_AddEventWatch(EmscriptenInput::HandleSDLEvents, vInputInst);
  119. }
  120. void EmscriptenInput::RequestPointerLock(MouseMode mode, bool suppressEvent)
  121. {
  122. requestedMouseMode_ = mode;
  123. suppressMouseModeEvent_ = suppressEvent;
  124. emscripten_request_pointerlock(NULL, true);
  125. }
  126. void EmscriptenInput::ExitPointerLock(bool suppressEvent)
  127. {
  128. if (requestedMouseMode_ != MM_INVALID)
  129. {
  130. invalidatedRequestedMouseMode_ = requestedMouseMode_;
  131. invalidatedSuppressMouseModeEvent_ = suppressMouseModeEvent_;
  132. }
  133. requestedMouseMode_ = MM_INVALID;
  134. suppressMouseModeEvent_ = suppressEvent;
  135. if (inputInst_->IsMouseLocked())
  136. {
  137. inputInst_->emscriptenExitingPointerLock_ = true;
  138. emscripten_exit_pointerlock();
  139. }
  140. }
  141. bool EmscriptenInput::IsVisible()
  142. {
  143. EmscriptenVisibilityChangeEvent visibilityStatus;
  144. if (emscripten_get_visibility_status(&visibilityStatus) >= EMSCRIPTEN_RESULT_SUCCESS)
  145. return visibilityStatus.hidden >= EM_TRUE ? false : true;
  146. // Assume visible
  147. URHO3D_LOGWARNING("Could not determine visibility status.");
  148. return true;
  149. }
  150. EM_BOOL EmscriptenInput::HandlePointerLockChange(int eventType, const EmscriptenPointerlockChangeEvent* keyEvent, void* userData)
  151. {
  152. auto* const inputInst = (Input*)userData;
  153. bool invalid = false;
  154. const bool suppress = suppressMouseModeEvent_;
  155. if (requestedMouseMode_ == MM_INVALID && invalidatedRequestedMouseMode_ != MM_INVALID)
  156. {
  157. invalid = true;
  158. requestedMouseMode_ = invalidatedRequestedMouseMode_;
  159. suppressMouseModeEvent_ = invalidatedSuppressMouseModeEvent_;
  160. invalidatedRequestedMouseMode_ = MM_INVALID;
  161. invalidatedSuppressMouseModeEvent_ = false;
  162. }
  163. if (keyEvent->isActive >= EM_TRUE)
  164. {
  165. // Pointer Lock is now active
  166. inputInst->emscriptenPointerLock_ = true;
  167. inputInst->emscriptenEnteredPointerLock_ = true;
  168. inputInst->SetMouseModeEmscriptenFinal(requestedMouseMode_, suppressMouseModeEvent_);
  169. }
  170. else
  171. {
  172. // Pointer Lock is now inactive
  173. inputInst->emscriptenPointerLock_ = false;
  174. if (inputInst->mouseMode_ == MM_RELATIVE)
  175. inputInst->SetMouseModeEmscriptenFinal(MM_FREE, suppressMouseModeEvent_);
  176. else if (inputInst->mouseMode_ == MM_ABSOLUTE)
  177. inputInst->SetMouseModeEmscriptenFinal(MM_ABSOLUTE, suppressMouseModeEvent_);
  178. inputInst->emscriptenExitingPointerLock_ = false;
  179. }
  180. if (invalid)
  181. {
  182. if (keyEvent->isActive >= EM_TRUE)
  183. {
  184. // ExitPointerLock was called before the pointer-lock request was accepted.
  185. // Exit from pointer-lock to avoid unexpected behavior.
  186. invalidatedRequestedMouseMode_ = MM_INVALID;
  187. inputInst->emscriptenInput_->ExitPointerLock(suppress);
  188. return EM_TRUE;
  189. }
  190. }
  191. requestedMouseMode_ = MM_INVALID;
  192. suppressMouseModeEvent_ = false;
  193. invalidatedRequestedMouseMode_ = MM_INVALID;
  194. invalidatedSuppressMouseModeEvent_ = false;
  195. return EM_TRUE;
  196. }
  197. EM_BOOL EmscriptenInput::HandleFocusChange(int eventType, const EmscriptenFocusEvent* keyEvent, void* userData)
  198. {
  199. auto* const inputInst = (Input*)userData;
  200. inputInst->SuppressNextMouseMove();
  201. if (eventType == EMSCRIPTEN_EVENT_FOCUSOUT)
  202. inputInst->LoseFocus();
  203. else if (eventType == EMSCRIPTEN_EVENT_FOCUS)
  204. inputInst->GainFocus();
  205. return EM_TRUE;
  206. }
  207. EM_BOOL EmscriptenInput::HandleMouseJump(int eventType, const EmscriptenMouseEvent * mouseEvent, void* userData)
  208. {
  209. // Suppress mouse jump on pointer-lock change
  210. auto* const inputInst = (Input*)userData;
  211. bool suppress = false;
  212. if (eventType == EMSCRIPTEN_EVENT_MOUSEDOWN && inputInst->emscriptenEnteredPointerLock_)
  213. {
  214. suppress = true;
  215. inputInst->emscriptenEnteredPointerLock_ = false;
  216. }
  217. else if (eventType == EMSCRIPTEN_EVENT_MOUSEMOVE && inputInst->emscriptenExitingPointerLock_)
  218. {
  219. suppress = true;
  220. }
  221. if (suppress)
  222. inputInst->SuppressNextMouseMove();
  223. return EM_FALSE;
  224. }
  225. int EmscriptenInput::HandleSDLEvents(void* userData, SDL_Event* event)
  226. {
  227. auto* const inputInst = (Input*)userData;
  228. inputInst->HandleSDLEvent(event);
  229. return 0;
  230. }
  231. #endif
  232. #ifdef _WIN32
  233. // On Windows repaint while the window is actively being resized.
  234. int Win32_ResizingEventWatcher(void* data, SDL_Event* event)
  235. {
  236. if (event->type == SDL_WINDOWEVENT && event->window.event == SDL_WINDOWEVENT_RESIZED)
  237. {
  238. SDL_Window* win = SDL_GetWindowFromID(event->window.windowID);
  239. if (win == (SDL_Window*)data)
  240. {
  241. if (auto* ctx = (Context*)SDL_GetWindowData(win, "URHO3D_CONTEXT"))
  242. {
  243. if (auto* graphics = ctx->GetSubsystem<Graphics>())
  244. {
  245. if (graphics->IsInitialized())
  246. {
  247. graphics->OnWindowResized();
  248. ctx->GetSubsystem<Engine>()->RunFrame();
  249. }
  250. }
  251. }
  252. }
  253. }
  254. return 0;
  255. }
  256. #endif
  257. void JoystickState::Initialize(unsigned numButtons, unsigned numAxes, unsigned numHats)
  258. {
  259. buttons_.Resize(numButtons);
  260. buttonPress_.Resize(numButtons);
  261. axes_.Resize(numAxes);
  262. hats_.Resize(numHats);
  263. Reset();
  264. }
  265. void JoystickState::Reset()
  266. {
  267. for (unsigned i = 0; i < buttons_.Size(); ++i)
  268. {
  269. buttons_[i] = false;
  270. buttonPress_[i] = false;
  271. }
  272. for (unsigned i = 0; i < axes_.Size(); ++i)
  273. axes_[i] = 0.0f;
  274. for (unsigned i = 0; i < hats_.Size(); ++i)
  275. hats_[i] = HAT_CENTER;
  276. }
  277. Input::Input(Context* context) :
  278. Object(context),
  279. mouseButtonDown_(0),
  280. mouseButtonPress_(0),
  281. lastVisibleMousePosition_(MOUSE_POSITION_OFFSCREEN),
  282. mouseMoveWheel_(0),
  283. inputScale_(Vector2::ONE),
  284. windowID_(0),
  285. toggleFullscreen_(true),
  286. mouseVisible_(false),
  287. lastMouseVisible_(false),
  288. mouseGrabbed_(false),
  289. lastMouseGrabbed_(false),
  290. mouseMode_(MM_ABSOLUTE),
  291. lastMouseMode_(MM_ABSOLUTE),
  292. #ifndef __EMSCRIPTEN__
  293. sdlMouseRelative_(false),
  294. #else
  295. emscriptenPointerLock_(false),
  296. emscriptenEnteredPointerLock_(false),
  297. emscriptenExitingPointerLock_(false),
  298. #endif
  299. touchEmulation_(false),
  300. inputFocus_(false),
  301. minimized_(false),
  302. focusedThisFrame_(false),
  303. suppressNextMouseMove_(false),
  304. mouseMoveScaled_(false),
  305. initialized_(false)
  306. {
  307. context_->RequireSDL(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER);
  308. for (int i = 0; i < TOUCHID_MAX; i++)
  309. availableTouchIDs_.Push(i);
  310. SubscribeToEvent(E_SCREENMODE, URHO3D_HANDLER(Input, HandleScreenMode));
  311. #if defined(__ANDROID__)
  312. // Prevent mouse events from being registered as synthetic touch events and vice versa
  313. SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
  314. SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
  315. #elif defined(__EMSCRIPTEN__)
  316. emscriptenInput_ = make_unique<EmscriptenInput>(this);
  317. #endif
  318. // Try to initialize right now, but skip if screen mode is not yet set
  319. Initialize();
  320. }
  321. Input::~Input()
  322. {
  323. context_->ReleaseSDL();
  324. }
  325. void Input::Update()
  326. {
  327. assert(initialized_);
  328. URHO3D_PROFILE(UpdateInput);
  329. #ifndef __EMSCRIPTEN__
  330. bool mouseMoved = false;
  331. if (mouseMove_ != IntVector2::ZERO)
  332. mouseMoved = true;
  333. ResetInputAccumulation();
  334. SDL_Event evt;
  335. while (SDL_PollEvent(&evt))
  336. HandleSDLEvent(&evt);
  337. if (suppressNextMouseMove_ && (mouseMove_ != IntVector2::ZERO || mouseMoved))
  338. UnsuppressMouseMove();
  339. #endif
  340. // Check for focus change this frame
  341. SDL_Window* window = graphics_->GetWindow();
  342. unsigned flags = window ? SDL_GetWindowFlags(window) & (SDL_WINDOW_INPUT_FOCUS | SDL_WINDOW_MOUSE_FOCUS) : 0;
  343. #ifndef __EMSCRIPTEN__
  344. if (window)
  345. {
  346. #ifdef REQUIRE_CLICK_TO_FOCUS
  347. // When using the "click to focus" mechanism, only focus automatically in fullscreen or non-hidden mouse mode
  348. if (!inputFocus_ && ((mouseVisible_ || mouseMode_ == MM_FREE) || graphics_->GetFullscreen()) && (flags & SDL_WINDOW_INPUT_FOCUS))
  349. #else
  350. if (!inputFocus_ && (flags & SDL_WINDOW_INPUT_FOCUS))
  351. #endif
  352. focusedThisFrame_ = true;
  353. if (focusedThisFrame_)
  354. GainFocus();
  355. // Check for losing focus. The window flags are not reliable when using an external window, so prevent losing focus in that case
  356. if (inputFocus_ && !graphics_->GetExternalWindow() && (flags & SDL_WINDOW_INPUT_FOCUS) == 0)
  357. LoseFocus();
  358. }
  359. else
  360. return;
  361. // Handle mouse mode MM_WRAP
  362. if (mouseVisible_ && mouseMode_ == MM_WRAP)
  363. {
  364. IntVector2 windowPos = graphics_->GetWindowPosition();
  365. IntVector2 mpos;
  366. SDL_GetGlobalMouseState(&mpos.x_, &mpos.y_);
  367. mpos -= windowPos;
  368. const int buffer = 5;
  369. const int width = graphics_->GetWidth() - buffer * 2;
  370. const int height = graphics_->GetHeight() - buffer * 2;
  371. // SetMousePosition utilizes backbuffer coordinate system, scale now from window coordinates
  372. mpos.x_ = (int)(mpos.x_ * inputScale_.x_);
  373. mpos.y_ = (int)(mpos.y_ * inputScale_.y_);
  374. bool warp = false;
  375. if (mpos.x_ < buffer)
  376. {
  377. warp = true;
  378. mpos.x_ += width;
  379. }
  380. if (mpos.x_ > buffer + width)
  381. {
  382. warp = true;
  383. mpos.x_ -= width;
  384. }
  385. if (mpos.y_ < buffer)
  386. {
  387. warp = true;
  388. mpos.y_ += height;
  389. }
  390. if (mpos.y_ > buffer + height)
  391. {
  392. warp = true;
  393. mpos.y_ -= height;
  394. }
  395. if (warp)
  396. {
  397. SetMousePosition(mpos);
  398. SuppressNextMouseMove();
  399. }
  400. }
  401. #else
  402. if (!window)
  403. return;
  404. #endif
  405. #ifndef __EMSCRIPTEN__
  406. if (!touchEmulation_ && (graphics_->GetExternalWindow() || ((!sdlMouseRelative_ && !mouseVisible_ && mouseMode_ != MM_FREE) && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
  407. #else
  408. if (!touchEmulation_ && !emscriptenPointerLock_ && (graphics_->GetExternalWindow() || (!mouseVisible_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))))
  409. #endif
  410. {
  411. const IntVector2 mousePosition = GetMousePosition();
  412. mouseMove_ = mousePosition - lastMousePosition_;
  413. mouseMoveScaled_ = true; // Already in backbuffer scale, since GetMousePosition() operates in that
  414. #ifndef __EMSCRIPTEN__
  415. if (graphics_->GetExternalWindow())
  416. lastMousePosition_ = mousePosition;
  417. else
  418. {
  419. // Recenter the mouse cursor manually after move
  420. CenterMousePosition();
  421. }
  422. #else
  423. if (mouseMode_ == MM_ABSOLUTE || mouseMode_ == MM_FREE)
  424. lastMousePosition_ = mousePosition;
  425. if (emscriptenExitingPointerLock_)
  426. SuppressNextMouseMove();
  427. #endif
  428. // Send mouse move event if necessary
  429. if (mouseMove_ != IntVector2::ZERO)
  430. {
  431. if (!suppressNextMouseMove_)
  432. {
  433. using namespace MouseMove;
  434. VariantMap& eventData = GetEventDataMap();
  435. eventData[P_X] = mousePosition.x_;
  436. eventData[P_Y] = mousePosition.y_;
  437. eventData[P_DX] = mouseMove_.x_;
  438. eventData[P_DY] = mouseMove_.y_;
  439. eventData[P_BUTTONS] = (unsigned)mouseButtonDown_;
  440. eventData[P_QUALIFIERS] = (unsigned)GetQualifiers();
  441. SendEvent(E_MOUSEMOVE, eventData);
  442. }
  443. }
  444. }
  445. #ifndef __EMSCRIPTEN__
  446. else if (!touchEmulation_ && !mouseVisible_ && sdlMouseRelative_ && inputFocus_ && (flags & SDL_WINDOW_MOUSE_FOCUS))
  447. {
  448. // Keep the cursor trapped in window.
  449. CenterMousePosition();
  450. }
  451. #endif
  452. }
  453. void Input::SetMouseVisible(bool enable, bool suppressEvent)
  454. {
  455. const bool startMouseVisible = mouseVisible_;
  456. // In touch emulation mode only enabled mouse is allowed
  457. if (touchEmulation_)
  458. enable = true;
  459. // In mouse mode relative, the mouse should be invisible
  460. if (mouseMode_ == MM_RELATIVE)
  461. {
  462. if (!suppressEvent)
  463. lastMouseVisible_ = enable;
  464. enable = false;
  465. }
  466. // SDL Raspberry Pi "video driver" does not have proper OS mouse support yet, so no-op for now
  467. #ifndef RPI
  468. if (enable != mouseVisible_)
  469. {
  470. if (initialized_)
  471. {
  472. // External windows can only support visible mouse cursor
  473. if (graphics_->GetExternalWindow())
  474. {
  475. mouseVisible_ = true;
  476. if (!suppressEvent)
  477. lastMouseVisible_ = true;
  478. return;
  479. }
  480. if (!enable && inputFocus_)
  481. {
  482. #ifndef __EMSCRIPTEN__
  483. if (mouseVisible_)
  484. lastVisibleMousePosition_ = GetMousePosition();
  485. if (mouseMode_ == MM_ABSOLUTE)
  486. SetMouseModeAbsolute(SDL_TRUE);
  487. #else
  488. if (mouseMode_ == MM_ABSOLUTE && !emscriptenPointerLock_)
  489. emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent);
  490. #endif
  491. SDL_ShowCursor(SDL_FALSE);
  492. mouseVisible_ = false;
  493. }
  494. else if (mouseMode_ != MM_RELATIVE)
  495. {
  496. SetMouseGrabbed(false, suppressEvent);
  497. SDL_ShowCursor(SDL_TRUE);
  498. mouseVisible_ = true;
  499. #ifndef __EMSCRIPTEN__
  500. if (mouseMode_ == MM_ABSOLUTE)
  501. SetMouseModeAbsolute(SDL_FALSE);
  502. // Update cursor position
  503. auto* ui = GetSubsystem<UI>();
  504. Cursor* cursor = ui->GetCursor();
  505. // If the UI Cursor was visible, use that position instead of last visible OS cursor position
  506. if (cursor && cursor->IsVisible())
  507. {
  508. IntVector2 pos = cursor->GetScreenPosition();
  509. if (pos != MOUSE_POSITION_OFFSCREEN)
  510. {
  511. SetMousePosition(pos);
  512. lastMousePosition_ = pos;
  513. }
  514. }
  515. else
  516. {
  517. if (lastVisibleMousePosition_ != MOUSE_POSITION_OFFSCREEN)
  518. {
  519. SetMousePosition(lastVisibleMousePosition_);
  520. lastMousePosition_ = lastVisibleMousePosition_;
  521. }
  522. }
  523. #else
  524. if (mouseMode_ == MM_ABSOLUTE && emscriptenPointerLock_)
  525. emscriptenInput_->ExitPointerLock(suppressEvent);
  526. #endif
  527. }
  528. }
  529. else
  530. {
  531. // Allow to set desired mouse visibility before initialization
  532. mouseVisible_ = enable;
  533. }
  534. if (mouseVisible_ != startMouseVisible)
  535. {
  536. SuppressNextMouseMove();
  537. if (!suppressEvent)
  538. {
  539. lastMouseVisible_ = mouseVisible_;
  540. using namespace MouseVisibleChanged;
  541. VariantMap& eventData = GetEventDataMap();
  542. eventData[P_VISIBLE] = mouseVisible_;
  543. SendEvent(E_MOUSEVISIBLECHANGED, eventData);
  544. }
  545. }
  546. }
  547. #endif
  548. }
  549. void Input::ResetMouseVisible()
  550. {
  551. #ifndef __EMSCRIPTEN__
  552. SetMouseVisible(lastMouseVisible_, false);
  553. #else
  554. SetMouseVisibleEmscripten(lastMouseVisible_, false);
  555. #endif
  556. }
  557. #ifdef __EMSCRIPTEN__
  558. void Input::SetMouseVisibleEmscripten(bool enable, bool suppressEvent)
  559. {
  560. if (enable != mouseVisible_)
  561. {
  562. if (mouseMode_ == MM_ABSOLUTE)
  563. {
  564. if (enable)
  565. {
  566. mouseVisible_ = true;
  567. SDL_ShowCursor(SDL_TRUE);
  568. emscriptenInput_->ExitPointerLock(suppressEvent);
  569. }
  570. else
  571. {
  572. if (emscriptenPointerLock_)
  573. {
  574. mouseVisible_ = false;
  575. SDL_ShowCursor(SDL_FALSE);
  576. }
  577. else
  578. emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent);
  579. }
  580. }
  581. else
  582. {
  583. mouseVisible_ = enable;
  584. SDL_ShowCursor(enable ? SDL_TRUE : SDL_FALSE);
  585. }
  586. }
  587. if (!suppressEvent)
  588. lastMouseVisible_ = mouseVisible_;
  589. }
  590. void Input::SetMouseModeEmscriptenFinal(MouseMode mode, bool suppressEvent)
  591. {
  592. if (!suppressEvent)
  593. lastMouseMode_ = mode;
  594. mouseMode_ = mode;
  595. if (mode == MM_ABSOLUTE)
  596. {
  597. if (emscriptenPointerLock_)
  598. {
  599. SetMouseVisibleEmscripten(false, suppressEvent);
  600. }
  601. else
  602. {
  603. SetMouseVisibleEmscripten(true, suppressEvent);
  604. }
  605. UI* const ui = GetSubsystem<UI>();
  606. Cursor* const cursor = ui->GetCursor();
  607. SetMouseGrabbed(!(mouseVisible_ || (cursor && cursor->IsVisible())), suppressEvent);
  608. }
  609. else if (mode == MM_RELATIVE && emscriptenPointerLock_)
  610. {
  611. SetMouseGrabbed(true, suppressEvent);
  612. SetMouseVisibleEmscripten(false, suppressEvent);
  613. }
  614. else
  615. {
  616. SetMouseGrabbed(false, suppressEvent);
  617. }
  618. SuppressNextMouseMove();
  619. if (!suppressEvent)
  620. {
  621. VariantMap& eventData = GetEventDataMap();
  622. eventData[MouseModeChanged::P_MODE] = mode;
  623. eventData[MouseModeChanged::P_MOUSELOCKED] = IsMouseLocked();
  624. SendEvent(E_MOUSEMODECHANGED, eventData);
  625. }
  626. }
  627. void Input::SetMouseModeEmscripten(MouseMode mode, bool suppressEvent)
  628. {
  629. if (mode != mouseMode_)
  630. SuppressNextMouseMove();
  631. const MouseMode previousMode = mouseMode_;
  632. mouseMode_ = mode;
  633. UI* const ui = GetSubsystem<UI>();
  634. Cursor* const cursor = ui->GetCursor();
  635. // Handle changing from previous mode
  636. if (previousMode == MM_RELATIVE)
  637. ResetMouseVisible();
  638. // Handle changing to new mode
  639. if (mode == MM_FREE)
  640. {
  641. // Attempt to cancel pending pointer-lock requests
  642. emscriptenInput_->ExitPointerLock(suppressEvent);
  643. SetMouseGrabbed(!(mouseVisible_ || (cursor && cursor->IsVisible())), suppressEvent);
  644. }
  645. else if (mode == MM_ABSOLUTE)
  646. {
  647. if (!mouseVisible_)
  648. {
  649. if (emscriptenPointerLock_)
  650. {
  651. SetMouseVisibleEmscripten(false, suppressEvent);
  652. }
  653. else
  654. {
  655. if (!cursor)
  656. SetMouseVisible(true, suppressEvent);
  657. // Deferred mouse mode change to pointer-lock callback
  658. mouseMode_ = previousMode;
  659. emscriptenInput_->RequestPointerLock(MM_ABSOLUTE, suppressEvent);
  660. }
  661. SetMouseGrabbed(!(mouseVisible_ || (cursor && cursor->IsVisible())), suppressEvent);
  662. }
  663. }
  664. else if (mode == MM_RELATIVE)
  665. {
  666. if (emscriptenPointerLock_)
  667. {
  668. SetMouseVisibleEmscripten(false, true);
  669. SetMouseGrabbed(!(cursor && cursor->IsVisible()), suppressEvent);
  670. }
  671. else
  672. {
  673. // Defer mouse mode change to pointer-lock callback
  674. SetMouseGrabbed(false, true);
  675. mouseMode_ = previousMode;
  676. emscriptenInput_->RequestPointerLock(MM_RELATIVE, suppressEvent);
  677. }
  678. }
  679. }
  680. #endif
  681. void Input::SetMouseGrabbed(bool grab, bool suppressEvent)
  682. {
  683. // To not interfere with touch UI operation, never report the mouse as grabbed on Android / iOS
  684. #if !defined(__ANDROID__) && !defined(IOS)
  685. mouseGrabbed_ = grab;
  686. if (!suppressEvent)
  687. lastMouseGrabbed_ = grab;
  688. #endif
  689. }
  690. void Input::ResetMouseGrabbed()
  691. {
  692. SetMouseGrabbed(lastMouseGrabbed_, true);
  693. }
  694. #ifndef __EMSCRIPTEN__
  695. void Input::SetMouseModeAbsolute(SDL_bool enable)
  696. {
  697. SDL_Window* const window = graphics_->GetWindow();
  698. SDL_SetWindowGrab(window, enable);
  699. }
  700. void Input::SetMouseModeRelative(SDL_bool enable)
  701. {
  702. SDL_Window* const window = graphics_->GetWindow();
  703. int result = SDL_SetRelativeMouseMode(enable);
  704. sdlMouseRelative_ = enable && (result == 0);
  705. if (result == -1)
  706. SDL_SetWindowGrab(window, enable);
  707. }
  708. #endif
  709. void Input::SetMouseMode(MouseMode mode, bool suppressEvent)
  710. {
  711. const MouseMode previousMode = mouseMode_;
  712. #ifdef __EMSCRIPTEN__
  713. SetMouseModeEmscripten(mode, suppressEvent);
  714. #else
  715. if (mode != mouseMode_)
  716. {
  717. if (initialized_)
  718. {
  719. SuppressNextMouseMove();
  720. mouseMode_ = mode;
  721. SDL_Window* const window = graphics_->GetWindow();
  722. auto* const ui = GetSubsystem<UI>();
  723. Cursor* const cursor = ui->GetCursor();
  724. // Handle changing from previous mode
  725. if (previousMode == MM_ABSOLUTE)
  726. {
  727. if (!mouseVisible_)
  728. SetMouseModeAbsolute(SDL_FALSE);
  729. }
  730. if (previousMode == MM_RELATIVE)
  731. {
  732. SetMouseModeRelative(SDL_FALSE);
  733. ResetMouseVisible();
  734. }
  735. else if (previousMode == MM_WRAP)
  736. SDL_SetWindowGrab(window, SDL_FALSE);
  737. // Handle changing to new mode
  738. if (mode == MM_ABSOLUTE)
  739. {
  740. if (!mouseVisible_)
  741. SetMouseModeAbsolute(SDL_TRUE);
  742. }
  743. else if (mode == MM_RELATIVE)
  744. {
  745. SetMouseVisible(false, true);
  746. SetMouseModeRelative(SDL_TRUE);
  747. }
  748. else if (mode == MM_WRAP)
  749. {
  750. SetMouseGrabbed(true, suppressEvent);
  751. SDL_SetWindowGrab(window, SDL_TRUE);
  752. }
  753. if (mode != MM_WRAP)
  754. SetMouseGrabbed(!(mouseVisible_ || (cursor && cursor->IsVisible())), suppressEvent);
  755. }
  756. else
  757. {
  758. // Allow to set desired mouse mode before initialization
  759. mouseMode_ = mode;
  760. }
  761. }
  762. #endif
  763. if (!suppressEvent)
  764. {
  765. lastMouseMode_ = mode;
  766. if (mouseMode_ != previousMode)
  767. {
  768. VariantMap& eventData = GetEventDataMap();
  769. eventData[MouseModeChanged::P_MODE] = mode;
  770. eventData[MouseModeChanged::P_MOUSELOCKED] = IsMouseLocked();
  771. SendEvent(E_MOUSEMODECHANGED, eventData);
  772. }
  773. }
  774. }
  775. void Input::ResetMouseMode()
  776. {
  777. SetMouseMode(lastMouseMode_, false);
  778. }
  779. void Input::SetToggleFullscreen(bool enable)
  780. {
  781. toggleFullscreen_ = enable;
  782. }
  783. static void PopulateKeyBindingMap(HashMap<String, int>& keyBindingMap)
  784. {
  785. if (keyBindingMap.Empty())
  786. {
  787. keyBindingMap.Insert(MakePair<String, int>("SPACE", KEY_SPACE));
  788. keyBindingMap.Insert(MakePair<String, int>("LCTRL", KEY_LCTRL));
  789. keyBindingMap.Insert(MakePair<String, int>("RCTRL", KEY_RCTRL));
  790. keyBindingMap.Insert(MakePair<String, int>("LSHIFT", KEY_LSHIFT));
  791. keyBindingMap.Insert(MakePair<String, int>("RSHIFT", KEY_RSHIFT));
  792. keyBindingMap.Insert(MakePair<String, int>("LALT", KEY_LALT));
  793. keyBindingMap.Insert(MakePair<String, int>("RALT", KEY_RALT));
  794. keyBindingMap.Insert(MakePair<String, int>("LGUI", KEY_LGUI));
  795. keyBindingMap.Insert(MakePair<String, int>("RGUI", KEY_RGUI));
  796. keyBindingMap.Insert(MakePair<String, int>("TAB", KEY_TAB));
  797. keyBindingMap.Insert(MakePair<String, int>("RETURN", KEY_RETURN));
  798. keyBindingMap.Insert(MakePair<String, int>("RETURN2", KEY_RETURN2));
  799. keyBindingMap.Insert(MakePair<String, int>("ENTER", KEY_KP_ENTER));
  800. keyBindingMap.Insert(MakePair<String, int>("SELECT", KEY_SELECT));
  801. keyBindingMap.Insert(MakePair<String, int>("LEFT", KEY_LEFT));
  802. keyBindingMap.Insert(MakePair<String, int>("RIGHT", KEY_RIGHT));
  803. keyBindingMap.Insert(MakePair<String, int>("UP", KEY_UP));
  804. keyBindingMap.Insert(MakePair<String, int>("DOWN", KEY_DOWN));
  805. keyBindingMap.Insert(MakePair<String, int>("PAGEUP", KEY_PAGEUP));
  806. keyBindingMap.Insert(MakePair<String, int>("PAGEDOWN", KEY_PAGEDOWN));
  807. keyBindingMap.Insert(MakePair<String, int>("F1", KEY_F1));
  808. keyBindingMap.Insert(MakePair<String, int>("F2", KEY_F2));
  809. keyBindingMap.Insert(MakePair<String, int>("F3", KEY_F3));
  810. keyBindingMap.Insert(MakePair<String, int>("F4", KEY_F4));
  811. keyBindingMap.Insert(MakePair<String, int>("F5", KEY_F5));
  812. keyBindingMap.Insert(MakePair<String, int>("F6", KEY_F6));
  813. keyBindingMap.Insert(MakePair<String, int>("F7", KEY_F7));
  814. keyBindingMap.Insert(MakePair<String, int>("F8", KEY_F8));
  815. keyBindingMap.Insert(MakePair<String, int>("F9", KEY_F9));
  816. keyBindingMap.Insert(MakePair<String, int>("F10", KEY_F10));
  817. keyBindingMap.Insert(MakePair<String, int>("F11", KEY_F11));
  818. keyBindingMap.Insert(MakePair<String, int>("F12", KEY_F12));
  819. }
  820. }
  821. static void PopulateMouseButtonBindingMap(HashMap<String, int>& mouseButtonBindingMap)
  822. {
  823. if (mouseButtonBindingMap.Empty())
  824. {
  825. mouseButtonBindingMap.Insert(MakePair<String, int>("LEFT", SDL_BUTTON_LEFT));
  826. mouseButtonBindingMap.Insert(MakePair<String, int>("MIDDLE", SDL_BUTTON_MIDDLE));
  827. mouseButtonBindingMap.Insert(MakePair<String, int>("RIGHT", SDL_BUTTON_RIGHT));
  828. mouseButtonBindingMap.Insert(MakePair<String, int>("X1", SDL_BUTTON_X1));
  829. mouseButtonBindingMap.Insert(MakePair<String, int>("X2", SDL_BUTTON_X2));
  830. }
  831. }
  832. SDL_JoystickID Input::AddScreenJoystick(XMLFile* layoutFile, XMLFile* styleFile)
  833. {
  834. static HashMap<String, int> keyBindingMap;
  835. static HashMap<String, int> mouseButtonBindingMap;
  836. if (!graphics_)
  837. {
  838. URHO3D_LOGWARNING("Cannot add screen joystick in headless mode");
  839. return -1;
  840. }
  841. // If layout file is not given, use the default screen joystick layout
  842. if (!layoutFile)
  843. {
  844. auto* cache = GetSubsystem<ResourceCache>();
  845. layoutFile = cache->GetResource<XMLFile>("UI/ScreenJoystick.xml");
  846. if (!layoutFile) // Error is already logged
  847. return -1;
  848. }
  849. auto* ui = GetSubsystem<UI>();
  850. SharedPtr<UIElement> screenJoystick = ui->LoadLayout(layoutFile, styleFile);
  851. if (!screenJoystick) // Error is already logged
  852. return -1;
  853. screenJoystick->SetSize(ui->GetRoot()->GetSize());
  854. ui->GetRoot()->AddChild(screenJoystick);
  855. // Get an unused ID for the screen joystick
  856. /// \todo After a real joystick has been plugged in 1073741824 times, the ranges will overlap
  857. SDL_JoystickID joystickID = SCREEN_JOYSTICK_START_ID;
  858. while (joysticks_.Contains(joystickID))
  859. ++joystickID;
  860. JoystickState& state = joysticks_[joystickID];
  861. state.joystickID_ = joystickID;
  862. state.name_ = screenJoystick->GetName();
  863. state.screenJoystick_ = screenJoystick;
  864. unsigned numButtons = 0;
  865. unsigned numAxes = 0;
  866. unsigned numHats = 0;
  867. const Vector<SharedPtr<UIElement>>& children = state.screenJoystick_->GetChildren();
  868. for (Vector<SharedPtr<UIElement>>::ConstIterator iter = children.Begin(); iter != children.End(); ++iter)
  869. {
  870. UIElement* element = iter->Get();
  871. String name = element->GetName();
  872. if (name.StartsWith("Button"))
  873. {
  874. ++numButtons;
  875. // Check whether the button has key binding
  876. auto* text = element->GetChildDynamicCast<Text>("KeyBinding", false);
  877. if (text)
  878. {
  879. text->SetVisible(false);
  880. const String& key = text->GetText();
  881. int keyBinding;
  882. if (key.Length() == 1)
  883. keyBinding = key[0];
  884. else
  885. {
  886. PopulateKeyBindingMap(keyBindingMap);
  887. HashMap<String, int>::Iterator i = keyBindingMap.Find(key);
  888. if (i != keyBindingMap.End())
  889. keyBinding = i->second_;
  890. else
  891. {
  892. URHO3D_LOGERRORF("Unsupported key binding: %s", key.CString());
  893. keyBinding = M_MAX_INT;
  894. }
  895. }
  896. if (keyBinding != M_MAX_INT)
  897. element->SetVar(VAR_BUTTON_KEY_BINDING, keyBinding);
  898. }
  899. // Check whether the button has mouse button binding
  900. text = element->GetChildDynamicCast<Text>("MouseButtonBinding", false);
  901. if (text)
  902. {
  903. text->SetVisible(false);
  904. const String& mouseButton = text->GetText();
  905. PopulateMouseButtonBindingMap(mouseButtonBindingMap);
  906. HashMap<String, int>::Iterator i = mouseButtonBindingMap.Find(mouseButton);
  907. if (i != mouseButtonBindingMap.End())
  908. element->SetVar(VAR_BUTTON_MOUSE_BUTTON_BINDING, i->second_);
  909. else
  910. URHO3D_LOGERRORF("Unsupported mouse button binding: %s", mouseButton.CString());
  911. }
  912. }
  913. else if (name.StartsWith("Axis"))
  914. {
  915. ++numAxes;
  916. ///\todo Axis emulation for screen joystick is not fully supported yet.
  917. URHO3D_LOGWARNING("Axis emulation for screen joystick is not fully supported yet");
  918. }
  919. else if (name.StartsWith("Hat"))
  920. {
  921. ++numHats;
  922. auto* text = element->GetChildDynamicCast<Text>("KeyBinding", false);
  923. if (text)
  924. {
  925. text->SetVisible(false);
  926. String keyBinding = text->GetText();
  927. int mappedKeyBinding[4] = {KEY_W, KEY_S, KEY_A, KEY_D};
  928. Vector<String> keyBindings;
  929. if (keyBinding.Contains(' ')) // e.g.: "UP DOWN LEFT RIGHT"
  930. keyBindings = keyBinding.Split(' '); // Attempt to split the text using ' ' as separator
  931. else if (keyBinding.Length() == 4)
  932. {
  933. keyBindings.Resize(4); // e.g.: "WSAD"
  934. for (unsigned i = 0; i < 4; ++i)
  935. keyBindings[i] = keyBinding.Substring(i, 1);
  936. }
  937. if (keyBindings.Size() == 4)
  938. {
  939. PopulateKeyBindingMap(keyBindingMap);
  940. for (unsigned j = 0; j < 4; ++j)
  941. {
  942. if (keyBindings[j].Length() == 1)
  943. mappedKeyBinding[j] = keyBindings[j][0];
  944. else
  945. {
  946. HashMap<String, int>::Iterator i = keyBindingMap.Find(keyBindings[j]);
  947. if (i != keyBindingMap.End())
  948. mappedKeyBinding[j] = i->second_;
  949. else
  950. URHO3D_LOGERRORF("%s - %s cannot be mapped, fallback to '%c'", name.CString(), keyBindings[j].CString(),
  951. mappedKeyBinding[j]);
  952. }
  953. }
  954. }
  955. else
  956. URHO3D_LOGERRORF("%s has invalid key binding %s, fallback to WSAD", name.CString(), keyBinding.CString());
  957. element->SetVar(VAR_BUTTON_KEY_BINDING, IntRect(mappedKeyBinding));
  958. }
  959. }
  960. element->SetVar(VAR_SCREEN_JOYSTICK_ID, joystickID);
  961. }
  962. // Make sure all the children are non-focusable so they do not mistakenly to be considered as active UI input controls by application
  963. PODVector<UIElement*> allChildren;
  964. state.screenJoystick_->GetChildren(allChildren, true);
  965. for (PODVector<UIElement*>::Iterator iter = allChildren.Begin(); iter != allChildren.End(); ++iter)
  966. (*iter)->SetFocusMode(FM_NOTFOCUSABLE);
  967. state.Initialize(numButtons, numAxes, numHats);
  968. // There could be potentially more than one screen joystick, however they all will be handled by a same handler method
  969. // So there is no harm to replace the old handler with the new handler in each call to SubscribeToEvent()
  970. SubscribeToEvent(E_TOUCHBEGIN, URHO3D_HANDLER(Input, HandleScreenJoystickTouch));
  971. SubscribeToEvent(E_TOUCHMOVE, URHO3D_HANDLER(Input, HandleScreenJoystickTouch));
  972. SubscribeToEvent(E_TOUCHEND, URHO3D_HANDLER(Input, HandleScreenJoystickTouch));
  973. return joystickID;
  974. }
  975. bool Input::RemoveScreenJoystick(SDL_JoystickID id)
  976. {
  977. if (!joysticks_.Contains(id))
  978. {
  979. URHO3D_LOGERRORF("Failed to remove non-existing screen joystick ID #%d", id);
  980. return false;
  981. }
  982. JoystickState& state = joysticks_[id];
  983. if (!state.screenJoystick_)
  984. {
  985. URHO3D_LOGERRORF("Failed to remove joystick with ID #%d which is not a screen joystick", id);
  986. return false;
  987. }
  988. state.screenJoystick_->Remove();
  989. joysticks_.Erase(id);
  990. return true;
  991. }
  992. void Input::SetScreenJoystickVisible(SDL_JoystickID id, bool enable)
  993. {
  994. if (joysticks_.Contains(id))
  995. {
  996. JoystickState& state = joysticks_[id];
  997. if (state.screenJoystick_)
  998. state.screenJoystick_->SetVisible(enable);
  999. }
  1000. }
  1001. void Input::SetScreenKeyboardVisible(bool enable)
  1002. {
  1003. if (enable != SDL_IsTextInputActive())
  1004. {
  1005. if (enable)
  1006. SDL_StartTextInput();
  1007. else
  1008. SDL_StopTextInput();
  1009. }
  1010. }
  1011. void Input::SetTouchEmulation(bool enable)
  1012. {
  1013. #if !defined(__ANDROID__) && !defined(IOS)
  1014. if (enable != touchEmulation_)
  1015. {
  1016. if (enable)
  1017. {
  1018. // Touch emulation needs the mouse visible
  1019. if (!mouseVisible_)
  1020. SetMouseVisible(true);
  1021. // Add a virtual touch device the first time we are enabling emulated touch
  1022. if (!SDL_GetNumTouchDevices())
  1023. SDL_AddTouch(0, SDL_TOUCH_DEVICE_INDIRECT_RELATIVE, "Emulated Touch");
  1024. }
  1025. else
  1026. ResetTouches();
  1027. touchEmulation_ = enable;
  1028. }
  1029. #endif
  1030. }
  1031. bool Input::RecordGesture()
  1032. {
  1033. // If have no touch devices, fail
  1034. if (!SDL_GetNumTouchDevices())
  1035. {
  1036. URHO3D_LOGERROR("Can not record gesture: no touch devices");
  1037. return false;
  1038. }
  1039. return SDL_RecordGesture(-1) != 0;
  1040. }
  1041. bool Input::SaveGestures(Serializer& dest)
  1042. {
  1043. RWOpsWrapper<Serializer> wrapper(dest);
  1044. return SDL_SaveAllDollarTemplates(wrapper.GetRWOps()) != 0;
  1045. }
  1046. bool Input::SaveGesture(Serializer& dest, unsigned gestureID)
  1047. {
  1048. RWOpsWrapper<Serializer> wrapper(dest);
  1049. return SDL_SaveDollarTemplate(gestureID, wrapper.GetRWOps()) != 0;
  1050. }
  1051. unsigned Input::LoadGestures(Deserializer& source)
  1052. {
  1053. // If have no touch devices, fail
  1054. if (!SDL_GetNumTouchDevices())
  1055. {
  1056. URHO3D_LOGERROR("Can not load gestures: no touch devices");
  1057. return 0;
  1058. }
  1059. RWOpsWrapper<Deserializer> wrapper(source);
  1060. return (unsigned)SDL_LoadDollarTemplates(-1, wrapper.GetRWOps());
  1061. }
  1062. bool Input::RemoveGesture(unsigned gestureID)
  1063. {
  1064. #ifdef __EMSCRIPTEN__
  1065. return false;
  1066. #else
  1067. return SDL_RemoveDollarTemplate(gestureID) != 0;
  1068. #endif
  1069. }
  1070. void Input::RemoveAllGestures()
  1071. {
  1072. #ifndef __EMSCRIPTEN__
  1073. SDL_RemoveAllDollarTemplates();
  1074. #endif
  1075. }
  1076. SDL_JoystickID Input::OpenJoystick(unsigned index)
  1077. {
  1078. SDL_Joystick* joystick = SDL_JoystickOpen(index);
  1079. if (!joystick)
  1080. {
  1081. URHO3D_LOGERRORF("Cannot open joystick #%d", index);
  1082. return -1;
  1083. }
  1084. // Create joystick state for the new joystick
  1085. int joystickID = SDL_JoystickInstanceID(joystick);
  1086. JoystickState& state = joysticks_[joystickID];
  1087. state.joystick_ = joystick;
  1088. state.joystickID_ = joystickID;
  1089. state.name_ = SDL_JoystickName(joystick);
  1090. if (SDL_IsGameController(index))
  1091. state.controller_ = SDL_GameControllerOpen(index);
  1092. auto numButtons = (unsigned)SDL_JoystickNumButtons(joystick);
  1093. auto numAxes = (unsigned)SDL_JoystickNumAxes(joystick);
  1094. auto numHats = (unsigned)SDL_JoystickNumHats(joystick);
  1095. // When the joystick is a controller, make sure there's enough axes & buttons for the standard controller mappings
  1096. if (state.controller_)
  1097. {
  1098. if (numButtons < SDL_CONTROLLER_BUTTON_MAX)
  1099. numButtons = SDL_CONTROLLER_BUTTON_MAX;
  1100. if (numAxes < SDL_CONTROLLER_AXIS_MAX)
  1101. numAxes = SDL_CONTROLLER_AXIS_MAX;
  1102. }
  1103. state.Initialize(numButtons, numAxes, numHats);
  1104. return joystickID;
  1105. }
  1106. Key Input::GetKeyFromName(const String& name) const
  1107. {
  1108. return (Key)SDL_GetKeyFromName(name.CString());
  1109. }
  1110. Key Input::GetKeyFromScancode(Scancode scancode) const
  1111. {
  1112. return (Key)SDL_GetKeyFromScancode((SDL_Scancode)scancode);
  1113. }
  1114. String Input::GetKeyName(Key key) const
  1115. {
  1116. return String(SDL_GetKeyName(key));
  1117. }
  1118. Scancode Input::GetScancodeFromKey(Key key) const
  1119. {
  1120. return (Scancode)SDL_GetScancodeFromKey(key);
  1121. }
  1122. Scancode Input::GetScancodeFromName(const String& name) const
  1123. {
  1124. return (Scancode)SDL_GetScancodeFromName(name.CString());
  1125. }
  1126. String Input::GetScancodeName(Scancode scancode) const
  1127. {
  1128. return SDL_GetScancodeName((SDL_Scancode)scancode);
  1129. }
  1130. bool Input::GetKeyDown(Key key) const
  1131. {
  1132. return keyDown_.Contains(SDL_tolower(key));
  1133. }
  1134. bool Input::GetKeyPress(Key key) const
  1135. {
  1136. return keyPress_.Contains(SDL_tolower(key));
  1137. }
  1138. bool Input::GetScancodeDown(Scancode scancode) const
  1139. {
  1140. return scancodeDown_.Contains(scancode);
  1141. }
  1142. bool Input::GetScancodePress(Scancode scancode) const
  1143. {
  1144. return scancodePress_.Contains(scancode);
  1145. }
  1146. bool Input::GetMouseButtonDown(MouseButtonFlags button) const
  1147. {
  1148. return mouseButtonDown_ & button;
  1149. }
  1150. bool Input::GetMouseButtonPress(MouseButtonFlags button) const
  1151. {
  1152. return mouseButtonPress_ & button;
  1153. }
  1154. bool Input::GetQualifierDown(Qualifier qualifier) const
  1155. {
  1156. if (qualifier == QUAL_SHIFT)
  1157. return GetKeyDown(KEY_LSHIFT) || GetKeyDown(KEY_RSHIFT);
  1158. if (qualifier == QUAL_CTRL)
  1159. return GetKeyDown(KEY_LCTRL) || GetKeyDown(KEY_RCTRL);
  1160. if (qualifier == QUAL_ALT)
  1161. return GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT);
  1162. return false;
  1163. }
  1164. bool Input::GetQualifierPress(Qualifier qualifier) const
  1165. {
  1166. if (qualifier == QUAL_SHIFT)
  1167. return GetKeyPress(KEY_LSHIFT) || GetKeyPress(KEY_RSHIFT);
  1168. if (qualifier == QUAL_CTRL)
  1169. return GetKeyPress(KEY_LCTRL) || GetKeyPress(KEY_RCTRL);
  1170. if (qualifier == QUAL_ALT)
  1171. return GetKeyPress(KEY_LALT) || GetKeyPress(KEY_RALT);
  1172. return false;
  1173. }
  1174. QualifierFlags Input::GetQualifiers() const
  1175. {
  1176. QualifierFlags ret;
  1177. if (GetQualifierDown(QUAL_SHIFT))
  1178. ret |= QUAL_SHIFT;
  1179. if (GetQualifierDown(QUAL_CTRL))
  1180. ret |= QUAL_CTRL;
  1181. if (GetQualifierDown(QUAL_ALT))
  1182. ret |= QUAL_ALT;
  1183. return ret;
  1184. }
  1185. IntVector2 Input::GetMousePosition() const
  1186. {
  1187. IntVector2 ret = IntVector2::ZERO;
  1188. if (!initialized_)
  1189. return ret;
  1190. SDL_GetMouseState(&ret.x_, &ret.y_);
  1191. ret.x_ = (int)(ret.x_ * inputScale_.x_);
  1192. ret.y_ = (int)(ret.y_ * inputScale_.y_);
  1193. return ret;
  1194. }
  1195. IntVector2 Input::GetMouseMove() const
  1196. {
  1197. if (!suppressNextMouseMove_)
  1198. return mouseMoveScaled_ ? mouseMove_ : IntVector2((int)(mouseMove_.x_ * inputScale_.x_), (int)(mouseMove_.y_ * inputScale_.y_));
  1199. else
  1200. return IntVector2::ZERO;
  1201. }
  1202. int Input::GetMouseMoveX() const
  1203. {
  1204. if (!suppressNextMouseMove_)
  1205. return mouseMoveScaled_ ? mouseMove_.x_ : (int)(mouseMove_.x_ * inputScale_.x_);
  1206. else
  1207. return 0;
  1208. }
  1209. int Input::GetMouseMoveY() const
  1210. {
  1211. if (!suppressNextMouseMove_)
  1212. return mouseMoveScaled_ ? mouseMove_.y_ : mouseMove_.y_ * inputScale_.y_;
  1213. else
  1214. return 0;
  1215. }
  1216. TouchState* Input::GetTouch(unsigned index) const
  1217. {
  1218. if (index >= touches_.Size())
  1219. return nullptr;
  1220. HashMap<int, TouchState>::ConstIterator i = touches_.Begin();
  1221. while (index--)
  1222. ++i;
  1223. return const_cast<TouchState*>(&i->second_);
  1224. }
  1225. JoystickState* Input::GetJoystickByIndex(unsigned index)
  1226. {
  1227. unsigned compare = 0;
  1228. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  1229. {
  1230. if (compare++ == index)
  1231. return &(i->second_);
  1232. }
  1233. return nullptr;
  1234. }
  1235. JoystickState* Input::GetJoystickByName(const String& name)
  1236. {
  1237. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  1238. {
  1239. if (i->second_.name_ == name)
  1240. return &(i->second_);
  1241. }
  1242. return nullptr;
  1243. }
  1244. JoystickState* Input::GetJoystick(SDL_JoystickID id)
  1245. {
  1246. HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Find(id);
  1247. return i != joysticks_.End() ? &(i->second_) : nullptr;
  1248. }
  1249. bool Input::IsScreenJoystickVisible(SDL_JoystickID id) const
  1250. {
  1251. HashMap<SDL_JoystickID, JoystickState>::ConstIterator i = joysticks_.Find(id);
  1252. return i != joysticks_.End() && i->second_.screenJoystick_ && i->second_.screenJoystick_->IsVisible();
  1253. }
  1254. bool Input::GetScreenKeyboardSupport() const
  1255. {
  1256. return SDL_HasScreenKeyboardSupport();
  1257. }
  1258. bool Input::IsScreenKeyboardVisible() const
  1259. {
  1260. return SDL_IsTextInputActive();
  1261. }
  1262. bool Input::IsMouseLocked() const
  1263. {
  1264. #ifdef __EMSCRIPTEN__
  1265. return emscriptenPointerLock_;
  1266. #else
  1267. return !((mouseMode_ == MM_ABSOLUTE && mouseVisible_) || mouseMode_ == MM_FREE);
  1268. #endif
  1269. }
  1270. bool Input::IsMinimized() const
  1271. {
  1272. // Return minimized state also when unfocused in fullscreen
  1273. if (!inputFocus_ && graphics_ && graphics_->GetFullscreen())
  1274. return true;
  1275. else
  1276. return minimized_;
  1277. }
  1278. void Input::Initialize()
  1279. {
  1280. auto* graphics = GetSubsystem<Graphics>();
  1281. if (!graphics || !graphics->IsInitialized())
  1282. return;
  1283. graphics_ = graphics;
  1284. // In external window mode only visible mouse is supported
  1285. if (graphics_->GetExternalWindow())
  1286. mouseVisible_ = true;
  1287. // Set the initial activation
  1288. initialized_ = true;
  1289. #ifndef __EMSCRIPTEN__
  1290. GainFocus();
  1291. #else
  1292. // Note: Page visibility and focus are slightly different, however we can't query last focus with Emscripten (1.29.0)
  1293. if (emscriptenInput_->IsVisible())
  1294. GainFocus();
  1295. else
  1296. LoseFocus();
  1297. #endif
  1298. ResetJoysticks();
  1299. ResetState();
  1300. SubscribeToEvent(E_BEGINFRAME, URHO3D_HANDLER(Input, HandleBeginFrame));
  1301. #ifdef __EMSCRIPTEN__
  1302. SubscribeToEvent(E_ENDFRAME, URHO3D_HANDLER(Input, HandleEndFrame));
  1303. #endif
  1304. #ifdef _WIN32
  1305. // Register callback for resizing in order to repaint.
  1306. if (SDL_Window* window = graphics_->GetWindow())
  1307. {
  1308. SDL_SetWindowData(window, "URHO3D_CONTEXT", GetContext());
  1309. SDL_AddEventWatch(Win32_ResizingEventWatcher, window);
  1310. }
  1311. #endif
  1312. URHO3D_LOGINFO("Initialized input");
  1313. }
  1314. void Input::ResetJoysticks()
  1315. {
  1316. joysticks_.Clear();
  1317. // Open each detected joystick automatically on startup
  1318. auto size = static_cast<unsigned>(SDL_NumJoysticks());
  1319. for (unsigned i = 0; i < size; ++i)
  1320. OpenJoystick(i);
  1321. }
  1322. void Input::ResetInputAccumulation()
  1323. {
  1324. // Reset input accumulation for this frame
  1325. keyPress_.Clear();
  1326. scancodePress_.Clear();
  1327. mouseButtonPress_ = MOUSEB_NONE;
  1328. mouseMove_ = IntVector2::ZERO;
  1329. mouseMoveWheel_ = 0;
  1330. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  1331. {
  1332. for (unsigned j = 0; j < i->second_.buttonPress_.Size(); ++j)
  1333. i->second_.buttonPress_[j] = false;
  1334. }
  1335. // Reset touch delta movement
  1336. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  1337. {
  1338. TouchState& state = i->second_;
  1339. state.lastPosition_ = state.position_;
  1340. state.delta_ = IntVector2::ZERO;
  1341. }
  1342. }
  1343. void Input::GainFocus()
  1344. {
  1345. ResetState();
  1346. inputFocus_ = true;
  1347. focusedThisFrame_ = false;
  1348. // Restore mouse mode
  1349. #ifndef __EMSCRIPTEN__
  1350. const MouseMode mm = mouseMode_;
  1351. mouseMode_ = MM_FREE;
  1352. SetMouseMode(mm, true);
  1353. #endif
  1354. SuppressNextMouseMove();
  1355. // Re-establish mouse cursor hiding as necessary
  1356. if (!mouseVisible_)
  1357. SDL_ShowCursor(SDL_FALSE);
  1358. SendInputFocusEvent();
  1359. }
  1360. void Input::LoseFocus()
  1361. {
  1362. ResetState();
  1363. inputFocus_ = false;
  1364. focusedThisFrame_ = false;
  1365. // Show the mouse cursor when inactive
  1366. SDL_ShowCursor(SDL_TRUE);
  1367. // Change mouse mode -- removing any cursor grabs, etc.
  1368. #ifndef __EMSCRIPTEN__
  1369. const MouseMode mm = mouseMode_;
  1370. SetMouseMode(MM_FREE, true);
  1371. // Restore flags to reflect correct mouse state.
  1372. mouseMode_ = mm;
  1373. #endif
  1374. SendInputFocusEvent();
  1375. }
  1376. void Input::ResetState()
  1377. {
  1378. keyDown_.Clear();
  1379. keyPress_.Clear();
  1380. scancodeDown_.Clear();
  1381. scancodePress_.Clear();
  1382. /// \todo Check if resetting joystick state on input focus loss is even necessary
  1383. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  1384. i->second_.Reset();
  1385. ResetTouches();
  1386. // Use SetMouseButton() to reset the state so that mouse events will be sent properly
  1387. SetMouseButton(MOUSEB_LEFT, false, 0);
  1388. SetMouseButton(MOUSEB_RIGHT, false, 0);
  1389. SetMouseButton(MOUSEB_MIDDLE, false, 0);
  1390. mouseMove_ = IntVector2::ZERO;
  1391. mouseMoveWheel_ = 0;
  1392. mouseButtonPress_ = MOUSEB_NONE;
  1393. }
  1394. void Input::ResetTouches()
  1395. {
  1396. for (HashMap<int, TouchState>::Iterator i = touches_.Begin(); i != touches_.End(); ++i)
  1397. {
  1398. TouchState& state = i->second_;
  1399. using namespace TouchEnd;
  1400. VariantMap& eventData = GetEventDataMap();
  1401. eventData[P_TOUCHID] = state.touchID_;
  1402. eventData[P_X] = state.position_.x_;
  1403. eventData[P_Y] = state.position_.y_;
  1404. SendEvent(E_TOUCHEND, eventData);
  1405. }
  1406. touches_.Clear();
  1407. touchIDMap_.Clear();
  1408. availableTouchIDs_.Clear();
  1409. for (int i = 0; i < TOUCHID_MAX; i++)
  1410. availableTouchIDs_.Push(i);
  1411. }
  1412. unsigned Input::GetTouchIndexFromID(int touchID)
  1413. {
  1414. HashMap<int, int>::ConstIterator i = touchIDMap_.Find(touchID);
  1415. if (i != touchIDMap_.End())
  1416. {
  1417. return (unsigned)i->second_;
  1418. }
  1419. unsigned index = PopTouchIndex();
  1420. touchIDMap_[touchID] = index;
  1421. return index;
  1422. }
  1423. unsigned Input::PopTouchIndex()
  1424. {
  1425. if (availableTouchIDs_.Empty())
  1426. return 0;
  1427. auto index = (unsigned)availableTouchIDs_.Front();
  1428. availableTouchIDs_.PopFront();
  1429. return index;
  1430. }
  1431. void Input::PushTouchIndex(int touchID)
  1432. {
  1433. HashMap<int, int>::ConstIterator ci = touchIDMap_.Find(touchID);
  1434. if (ci == touchIDMap_.End())
  1435. return;
  1436. int index = touchIDMap_[touchID];
  1437. touchIDMap_.Erase(touchID);
  1438. // Sorted insertion
  1439. bool inserted = false;
  1440. for (List<int>::Iterator i = availableTouchIDs_.Begin(); i != availableTouchIDs_.End(); ++i)
  1441. {
  1442. if (*i == index)
  1443. {
  1444. // This condition can occur when TOUCHID_MAX is reached.
  1445. inserted = true;
  1446. break;
  1447. }
  1448. if (*i > index)
  1449. {
  1450. availableTouchIDs_.Insert(i, index);
  1451. inserted = true;
  1452. break;
  1453. }
  1454. }
  1455. // If empty, or the lowest value then insert at end.
  1456. if (!inserted)
  1457. availableTouchIDs_.Push(index);
  1458. }
  1459. void Input::SendInputFocusEvent()
  1460. {
  1461. using namespace InputFocus;
  1462. VariantMap& eventData = GetEventDataMap();
  1463. eventData[P_FOCUS] = HasFocus();
  1464. eventData[P_MINIMIZED] = IsMinimized();
  1465. SendEvent(E_INPUTFOCUS, eventData);
  1466. }
  1467. void Input::SetMouseButton(MouseButton button, bool newState, int clicks)
  1468. {
  1469. if (newState)
  1470. {
  1471. if (!(mouseButtonDown_ & button))
  1472. mouseButtonPress_ |= button;
  1473. mouseButtonDown_ |= button;
  1474. }
  1475. else
  1476. {
  1477. if (!(mouseButtonDown_ & button))
  1478. return;
  1479. mouseButtonDown_ &= ~button;
  1480. }
  1481. using namespace MouseButtonDown;
  1482. VariantMap& eventData = GetEventDataMap();
  1483. eventData[P_BUTTON] = button;
  1484. eventData[P_BUTTONS] = (unsigned)mouseButtonDown_;
  1485. eventData[P_QUALIFIERS] = (unsigned)GetQualifiers();
  1486. eventData[P_CLICKS] = clicks;
  1487. SendEvent(newState ? E_MOUSEBUTTONDOWN : E_MOUSEBUTTONUP, eventData);
  1488. }
  1489. void Input::SetKey(Key key, Scancode scancode, bool newState)
  1490. {
  1491. bool repeat = false;
  1492. if (newState)
  1493. {
  1494. scancodeDown_.Insert(scancode);
  1495. scancodePress_.Insert(scancode);
  1496. if (!keyDown_.Contains(key))
  1497. {
  1498. keyDown_.Insert(key);
  1499. keyPress_.Insert(key);
  1500. }
  1501. else
  1502. repeat = true;
  1503. }
  1504. else
  1505. {
  1506. scancodeDown_.Erase(scancode);
  1507. if (!keyDown_.Erase(key))
  1508. return;
  1509. }
  1510. using namespace KeyDown;
  1511. VariantMap& eventData = GetEventDataMap();
  1512. eventData[P_KEY] = key;
  1513. eventData[P_SCANCODE] = scancode;
  1514. eventData[P_BUTTONS] = (unsigned)mouseButtonDown_;
  1515. eventData[P_QUALIFIERS] = (unsigned)GetQualifiers();
  1516. if (newState)
  1517. eventData[P_REPEAT] = repeat;
  1518. SendEvent(newState ? E_KEYDOWN : E_KEYUP, eventData);
  1519. if ((key == KEY_RETURN || key == KEY_RETURN2 || key == KEY_KP_ENTER) && newState && !repeat && toggleFullscreen_ &&
  1520. (GetKeyDown(KEY_LALT) || GetKeyDown(KEY_RALT)))
  1521. graphics_->ToggleFullscreen();
  1522. }
  1523. void Input::SetMouseWheel(int delta)
  1524. {
  1525. if (delta)
  1526. {
  1527. mouseMoveWheel_ += delta;
  1528. using namespace MouseWheel;
  1529. VariantMap& eventData = GetEventDataMap();
  1530. eventData[P_WHEEL] = delta;
  1531. eventData[P_BUTTONS] = (unsigned)mouseButtonDown_;
  1532. eventData[P_QUALIFIERS] = (unsigned)GetQualifiers();
  1533. SendEvent(E_MOUSEWHEEL, eventData);
  1534. }
  1535. }
  1536. void Input::SetMousePosition(const IntVector2& position)
  1537. {
  1538. if (!graphics_)
  1539. return;
  1540. SDL_WarpMouseInWindow(graphics_->GetWindow(), (int)(position.x_ / inputScale_.x_), (int)(position.y_ / inputScale_.y_));
  1541. }
  1542. void Input::CenterMousePosition()
  1543. {
  1544. const IntVector2 center(graphics_->GetWidth() / 2, graphics_->GetHeight() / 2);
  1545. if (GetMousePosition() != center)
  1546. {
  1547. SetMousePosition(center);
  1548. lastMousePosition_ = center;
  1549. }
  1550. }
  1551. void Input::SuppressNextMouseMove()
  1552. {
  1553. suppressNextMouseMove_ = true;
  1554. mouseMove_ = IntVector2::ZERO;
  1555. }
  1556. void Input::UnsuppressMouseMove()
  1557. {
  1558. suppressNextMouseMove_ = false;
  1559. mouseMove_ = IntVector2::ZERO;
  1560. lastMousePosition_ = GetMousePosition();
  1561. }
  1562. void Input::HandleSDLEvent(void* sdlEvent)
  1563. {
  1564. SDL_Event& evt = *static_cast<SDL_Event*>(sdlEvent);
  1565. // While not having input focus, skip key/mouse/touch/joystick events, except for the "click to focus" mechanism
  1566. if (!inputFocus_ && evt.type >= SDL_KEYDOWN && evt.type <= SDL_MULTIGESTURE)
  1567. {
  1568. #ifdef REQUIRE_CLICK_TO_FOCUS
  1569. // Require the click to be at least 1 pixel inside the window to disregard clicks in the title bar
  1570. if (evt.type == SDL_MOUSEBUTTONDOWN && evt.button.x > 0 && evt.button.y > 0 && evt.button.x < graphics_->GetWidth() - 1 &&
  1571. evt.button.y < graphics_->GetHeight() - 1)
  1572. {
  1573. focusedThisFrame_ = true;
  1574. // Do not cause the click to actually go throughfin
  1575. return;
  1576. }
  1577. else if (evt.type == SDL_FINGERDOWN)
  1578. {
  1579. // When focusing by touch, call GainFocus() immediately as it resets the state; a touch has sustained state
  1580. // which should be kept
  1581. GainFocus();
  1582. }
  1583. else
  1584. #endif
  1585. return;
  1586. }
  1587. // Possibility for custom handling or suppression of default handling for the SDL event
  1588. {
  1589. using namespace SDLRawInput;
  1590. VariantMap eventData = GetEventDataMap();
  1591. eventData[P_SDLEVENT] = &evt;
  1592. eventData[P_CONSUMED] = false;
  1593. SendEvent(E_SDLRAWINPUT, eventData);
  1594. if (eventData[P_CONSUMED].GetBool())
  1595. return;
  1596. }
  1597. switch (evt.type)
  1598. {
  1599. case SDL_KEYDOWN:
  1600. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), (Scancode)evt.key.keysym.scancode, true);
  1601. break;
  1602. case SDL_KEYUP:
  1603. SetKey(ConvertSDLKeyCode(evt.key.keysym.sym, evt.key.keysym.scancode), (Scancode)evt.key.keysym.scancode, false);
  1604. break;
  1605. case SDL_TEXTINPUT:
  1606. {
  1607. using namespace TextInput;
  1608. VariantMap textInputEventData;
  1609. textInputEventData[P_TEXT] = textInput_ = &evt.text.text[0];
  1610. SendEvent(E_TEXTINPUT, textInputEventData);
  1611. }
  1612. break;
  1613. case SDL_TEXTEDITING:
  1614. {
  1615. using namespace TextEditing;
  1616. VariantMap textEditingEventData;
  1617. textEditingEventData[P_COMPOSITION] = &evt.edit.text[0];
  1618. textEditingEventData[P_CURSOR] = evt.edit.start;
  1619. textEditingEventData[P_SELECTION_LENGTH] = evt.edit.length;
  1620. SendEvent(E_TEXTEDITING, textEditingEventData);
  1621. }
  1622. break;
  1623. case SDL_MOUSEBUTTONDOWN:
  1624. if (!touchEmulation_)
  1625. {
  1626. const auto mouseButton = static_cast<MouseButton>(1u << (evt.button.button - 1u)); // NOLINT(misc-misplaced-widening-cast)
  1627. SetMouseButton(mouseButton, true, evt.button.clicks);
  1628. }
  1629. else
  1630. {
  1631. int x, y;
  1632. SDL_GetMouseState(&x, &y);
  1633. x = (int)(x * inputScale_.x_);
  1634. y = (int)(y * inputScale_.y_);
  1635. SDL_Event event;
  1636. event.type = SDL_FINGERDOWN;
  1637. event.tfinger.touchId = 0;
  1638. event.tfinger.fingerId = evt.button.button - 1;
  1639. event.tfinger.pressure = 1.0f;
  1640. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1641. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1642. event.tfinger.dx = 0;
  1643. event.tfinger.dy = 0;
  1644. SDL_PushEvent(&event);
  1645. }
  1646. break;
  1647. case SDL_MOUSEBUTTONUP:
  1648. if (!touchEmulation_)
  1649. {
  1650. const auto mouseButton = static_cast<MouseButton>(1u << (evt.button.button - 1u)); // NOLINT(misc-misplaced-widening-cast)
  1651. SetMouseButton(mouseButton, false, evt.button.clicks);
  1652. }
  1653. else
  1654. {
  1655. int x, y;
  1656. SDL_GetMouseState(&x, &y);
  1657. x = (int)(x * inputScale_.x_);
  1658. y = (int)(y * inputScale_.y_);
  1659. SDL_Event event;
  1660. event.type = SDL_FINGERUP;
  1661. event.tfinger.touchId = 0;
  1662. event.tfinger.fingerId = evt.button.button - 1;
  1663. event.tfinger.pressure = 0.0f;
  1664. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1665. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1666. event.tfinger.dx = 0;
  1667. event.tfinger.dy = 0;
  1668. SDL_PushEvent(&event);
  1669. }
  1670. break;
  1671. case SDL_MOUSEMOTION:
  1672. #ifndef __EMSCRIPTEN__
  1673. if ((sdlMouseRelative_ || mouseVisible_ || mouseMode_ == MM_FREE) && !touchEmulation_)
  1674. #else
  1675. if ((mouseVisible_ || emscriptenPointerLock_ || mouseMode_ == MM_FREE) && !touchEmulation_)
  1676. #endif
  1677. {
  1678. #ifdef __EMSCRIPTEN__
  1679. if (emscriptenExitingPointerLock_)
  1680. {
  1681. SuppressNextMouseMove();
  1682. break;
  1683. }
  1684. #endif
  1685. // Accumulate without scaling for accuracy, needs to be scaled to backbuffer coordinates when asked
  1686. mouseMove_.x_ += evt.motion.xrel;
  1687. mouseMove_.y_ += evt.motion.yrel;
  1688. mouseMoveScaled_ = false;
  1689. if (!suppressNextMouseMove_)
  1690. {
  1691. using namespace MouseMove;
  1692. VariantMap& eventData = GetEventDataMap();
  1693. eventData[P_X] = (int)(evt.motion.x * inputScale_.x_);
  1694. eventData[P_Y] = (int)(evt.motion.y * inputScale_.y_);
  1695. // The "on-the-fly" motion data needs to be scaled now, though this may reduce accuracy
  1696. eventData[P_DX] = (int)(evt.motion.xrel * inputScale_.x_);
  1697. eventData[P_DY] = (int)(evt.motion.yrel * inputScale_.y_);
  1698. eventData[P_BUTTONS] = (unsigned)mouseButtonDown_;
  1699. eventData[P_QUALIFIERS] = (unsigned)GetQualifiers();
  1700. SendEvent(E_MOUSEMOVE, eventData);
  1701. }
  1702. }
  1703. // Only the left mouse button "finger" moves along with the mouse movement
  1704. else if (touchEmulation_ && touches_.Contains(0))
  1705. {
  1706. int x, y;
  1707. SDL_GetMouseState(&x, &y);
  1708. x = (int)(x * inputScale_.x_);
  1709. y = (int)(y * inputScale_.y_);
  1710. SDL_Event event;
  1711. event.type = SDL_FINGERMOTION;
  1712. event.tfinger.touchId = 0;
  1713. event.tfinger.fingerId = 0;
  1714. event.tfinger.pressure = 1.0f;
  1715. event.tfinger.x = (float)x / (float)graphics_->GetWidth();
  1716. event.tfinger.y = (float)y / (float)graphics_->GetHeight();
  1717. event.tfinger.dx = (float)evt.motion.xrel * inputScale_.x_ / (float)graphics_->GetWidth();
  1718. event.tfinger.dy = (float)evt.motion.yrel * inputScale_.y_ / (float)graphics_->GetHeight();
  1719. SDL_PushEvent(&event);
  1720. }
  1721. break;
  1722. case SDL_MOUSEWHEEL:
  1723. if (!touchEmulation_)
  1724. SetMouseWheel(evt.wheel.y);
  1725. break;
  1726. case SDL_FINGERDOWN:
  1727. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1728. {
  1729. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffffu);
  1730. TouchState& state = touches_[touchID];
  1731. state.touchID_ = touchID;
  1732. state.lastPosition_ = state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  1733. (int)(evt.tfinger.y * graphics_->GetHeight()));
  1734. state.delta_ = IntVector2::ZERO;
  1735. state.pressure_ = evt.tfinger.pressure;
  1736. using namespace TouchBegin;
  1737. VariantMap& eventData = GetEventDataMap();
  1738. eventData[P_TOUCHID] = touchID;
  1739. eventData[P_X] = state.position_.x_;
  1740. eventData[P_Y] = state.position_.y_;
  1741. eventData[P_PRESSURE] = state.pressure_;
  1742. SendEvent(E_TOUCHBEGIN, eventData);
  1743. // Finger touch may move the mouse cursor. Suppress next mouse move when cursor hidden to prevent jumps
  1744. if (!mouseVisible_)
  1745. SuppressNextMouseMove();
  1746. }
  1747. break;
  1748. case SDL_FINGERUP:
  1749. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1750. {
  1751. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffffu);
  1752. TouchState& state = touches_[touchID];
  1753. using namespace TouchEnd;
  1754. VariantMap& eventData = GetEventDataMap();
  1755. // Do not trust the position in the finger up event. Instead use the last position stored in the
  1756. // touch structure
  1757. eventData[P_TOUCHID] = touchID;
  1758. eventData[P_X] = state.position_.x_;
  1759. eventData[P_Y] = state.position_.y_;
  1760. SendEvent(E_TOUCHEND, eventData);
  1761. // Add touch index back to list of available touch Ids
  1762. PushTouchIndex(evt.tfinger.fingerId & 0x7ffffffu);
  1763. touches_.Erase(touchID);
  1764. }
  1765. break;
  1766. case SDL_FINGERMOTION:
  1767. if (evt.tfinger.touchId != SDL_TOUCH_MOUSEID)
  1768. {
  1769. int touchID = GetTouchIndexFromID(evt.tfinger.fingerId & 0x7ffffffu);
  1770. // We don't want this event to create a new touches_ event if it doesn't exist (touchEmulation)
  1771. if (touchEmulation_ && !touches_.Contains(touchID))
  1772. break;
  1773. TouchState& state = touches_[touchID];
  1774. state.touchID_ = touchID;
  1775. state.position_ = IntVector2((int)(evt.tfinger.x * graphics_->GetWidth()),
  1776. (int)(evt.tfinger.y * graphics_->GetHeight()));
  1777. state.delta_ = state.position_ - state.lastPosition_;
  1778. state.pressure_ = evt.tfinger.pressure;
  1779. using namespace TouchMove;
  1780. VariantMap& eventData = GetEventDataMap();
  1781. eventData[P_TOUCHID] = touchID;
  1782. eventData[P_X] = state.position_.x_;
  1783. eventData[P_Y] = state.position_.y_;
  1784. eventData[P_DX] = (int)(evt.tfinger.dx * graphics_->GetWidth());
  1785. eventData[P_DY] = (int)(evt.tfinger.dy * graphics_->GetHeight());
  1786. eventData[P_PRESSURE] = state.pressure_;
  1787. SendEvent(E_TOUCHMOVE, eventData);
  1788. // Finger touch may move the mouse cursor. Suppress next mouse move when cursor hidden to prevent jumps
  1789. if (!mouseVisible_)
  1790. SuppressNextMouseMove();
  1791. }
  1792. break;
  1793. case SDL_DOLLARRECORD:
  1794. {
  1795. using namespace GestureRecorded;
  1796. VariantMap& eventData = GetEventDataMap();
  1797. eventData[P_GESTUREID] = (int)evt.dgesture.gestureId;
  1798. SendEvent(E_GESTURERECORDED, eventData);
  1799. }
  1800. break;
  1801. case SDL_DOLLARGESTURE:
  1802. {
  1803. using namespace GestureInput;
  1804. VariantMap& eventData = GetEventDataMap();
  1805. eventData[P_GESTUREID] = (int)evt.dgesture.gestureId;
  1806. eventData[P_CENTERX] = (int)(evt.dgesture.x * graphics_->GetWidth());
  1807. eventData[P_CENTERY] = (int)(evt.dgesture.y * graphics_->GetHeight());
  1808. eventData[P_NUMFINGERS] = (int)evt.dgesture.numFingers;
  1809. eventData[P_ERROR] = evt.dgesture.error;
  1810. SendEvent(E_GESTUREINPUT, eventData);
  1811. }
  1812. break;
  1813. case SDL_MULTIGESTURE:
  1814. {
  1815. using namespace MultiGesture;
  1816. VariantMap& eventData = GetEventDataMap();
  1817. eventData[P_CENTERX] = (int)(evt.mgesture.x * graphics_->GetWidth());
  1818. eventData[P_CENTERY] = (int)(evt.mgesture.y * graphics_->GetHeight());
  1819. eventData[P_NUMFINGERS] = (int)evt.mgesture.numFingers;
  1820. eventData[P_DTHETA] = M_RADTODEG * evt.mgesture.dTheta;
  1821. eventData[P_DDIST] = evt.mgesture.dDist;
  1822. SendEvent(E_MULTIGESTURE, eventData);
  1823. }
  1824. break;
  1825. case SDL_JOYDEVICEADDED:
  1826. {
  1827. using namespace JoystickConnected;
  1828. SDL_JoystickID joystickID = OpenJoystick((unsigned)evt.jdevice.which);
  1829. VariantMap& eventData = GetEventDataMap();
  1830. eventData[P_JOYSTICKID] = joystickID;
  1831. SendEvent(E_JOYSTICKCONNECTED, eventData);
  1832. }
  1833. break;
  1834. case SDL_JOYDEVICEREMOVED:
  1835. {
  1836. using namespace JoystickDisconnected;
  1837. joysticks_.Erase(evt.jdevice.which);
  1838. VariantMap& eventData = GetEventDataMap();
  1839. eventData[P_JOYSTICKID] = evt.jdevice.which;
  1840. SendEvent(E_JOYSTICKDISCONNECTED, eventData);
  1841. }
  1842. break;
  1843. case SDL_JOYBUTTONDOWN:
  1844. {
  1845. using namespace JoystickButtonDown;
  1846. unsigned button = evt.jbutton.button;
  1847. SDL_JoystickID joystickID = evt.jbutton.which;
  1848. JoystickState& state = joysticks_[joystickID];
  1849. // Skip ordinary joystick event for a controller
  1850. if (!state.controller_)
  1851. {
  1852. VariantMap& eventData = GetEventDataMap();
  1853. eventData[P_JOYSTICKID] = joystickID;
  1854. eventData[P_BUTTON] = button;
  1855. if (button < state.buttons_.Size())
  1856. {
  1857. state.buttons_[button] = true;
  1858. state.buttonPress_[button] = true;
  1859. SendEvent(E_JOYSTICKBUTTONDOWN, eventData);
  1860. }
  1861. }
  1862. }
  1863. break;
  1864. case SDL_JOYBUTTONUP:
  1865. {
  1866. using namespace JoystickButtonUp;
  1867. unsigned button = evt.jbutton.button;
  1868. SDL_JoystickID joystickID = evt.jbutton.which;
  1869. JoystickState& state = joysticks_[joystickID];
  1870. if (!state.controller_)
  1871. {
  1872. VariantMap& eventData = GetEventDataMap();
  1873. eventData[P_JOYSTICKID] = joystickID;
  1874. eventData[P_BUTTON] = button;
  1875. if (button < state.buttons_.Size())
  1876. {
  1877. if (!state.controller_)
  1878. state.buttons_[button] = false;
  1879. SendEvent(E_JOYSTICKBUTTONUP, eventData);
  1880. }
  1881. }
  1882. }
  1883. break;
  1884. case SDL_JOYAXISMOTION:
  1885. {
  1886. using namespace JoystickAxisMove;
  1887. SDL_JoystickID joystickID = evt.jaxis.which;
  1888. JoystickState& state = joysticks_[joystickID];
  1889. if (!state.controller_)
  1890. {
  1891. VariantMap& eventData = GetEventDataMap();
  1892. eventData[P_JOYSTICKID] = joystickID;
  1893. eventData[P_AXIS] = evt.jaxis.axis;
  1894. eventData[P_POSITION] = Clamp((float)evt.jaxis.value / 32767.0f, -1.0f, 1.0f);
  1895. if (evt.jaxis.axis < state.axes_.Size())
  1896. {
  1897. // If the joystick is a controller, only use the controller axis mappings
  1898. // (we'll also get the controller event)
  1899. if (!state.controller_)
  1900. state.axes_[evt.jaxis.axis] = eventData[P_POSITION].GetFloat();
  1901. SendEvent(E_JOYSTICKAXISMOVE, eventData);
  1902. }
  1903. }
  1904. }
  1905. break;
  1906. case SDL_JOYHATMOTION:
  1907. {
  1908. using namespace JoystickHatMove;
  1909. SDL_JoystickID joystickID = evt.jaxis.which;
  1910. JoystickState& state = joysticks_[joystickID];
  1911. VariantMap& eventData = GetEventDataMap();
  1912. eventData[P_JOYSTICKID] = joystickID;
  1913. eventData[P_HAT] = evt.jhat.hat;
  1914. eventData[P_POSITION] = evt.jhat.value;
  1915. if (evt.jhat.hat < state.hats_.Size())
  1916. {
  1917. state.hats_[evt.jhat.hat] = evt.jhat.value;
  1918. SendEvent(E_JOYSTICKHATMOVE, eventData);
  1919. }
  1920. }
  1921. break;
  1922. case SDL_CONTROLLERBUTTONDOWN:
  1923. {
  1924. using namespace JoystickButtonDown;
  1925. unsigned button = evt.cbutton.button;
  1926. SDL_JoystickID joystickID = evt.cbutton.which;
  1927. JoystickState& state = joysticks_[joystickID];
  1928. VariantMap& eventData = GetEventDataMap();
  1929. eventData[P_JOYSTICKID] = joystickID;
  1930. eventData[P_BUTTON] = button;
  1931. if (button < state.buttons_.Size())
  1932. {
  1933. state.buttons_[button] = true;
  1934. state.buttonPress_[button] = true;
  1935. SendEvent(E_JOYSTICKBUTTONDOWN, eventData);
  1936. }
  1937. }
  1938. break;
  1939. case SDL_CONTROLLERBUTTONUP:
  1940. {
  1941. using namespace JoystickButtonUp;
  1942. unsigned button = evt.cbutton.button;
  1943. SDL_JoystickID joystickID = evt.cbutton.which;
  1944. JoystickState& state = joysticks_[joystickID];
  1945. VariantMap& eventData = GetEventDataMap();
  1946. eventData[P_JOYSTICKID] = joystickID;
  1947. eventData[P_BUTTON] = button;
  1948. if (button < state.buttons_.Size())
  1949. {
  1950. state.buttons_[button] = false;
  1951. SendEvent(E_JOYSTICKBUTTONUP, eventData);
  1952. }
  1953. }
  1954. break;
  1955. case SDL_CONTROLLERAXISMOTION:
  1956. {
  1957. using namespace JoystickAxisMove;
  1958. SDL_JoystickID joystickID = evt.caxis.which;
  1959. JoystickState& state = joysticks_[joystickID];
  1960. VariantMap& eventData = GetEventDataMap();
  1961. eventData[P_JOYSTICKID] = joystickID;
  1962. eventData[P_AXIS] = evt.caxis.axis;
  1963. eventData[P_POSITION] = Clamp((float)evt.caxis.value / 32767.0f, -1.0f, 1.0f);
  1964. if (evt.caxis.axis < state.axes_.Size())
  1965. {
  1966. state.axes_[evt.caxis.axis] = eventData[P_POSITION].GetFloat();
  1967. SendEvent(E_JOYSTICKAXISMOVE, eventData);
  1968. }
  1969. }
  1970. break;
  1971. case SDL_WINDOWEVENT:
  1972. {
  1973. switch (evt.window.event)
  1974. {
  1975. case SDL_WINDOWEVENT_MINIMIZED:
  1976. minimized_ = true;
  1977. SendInputFocusEvent();
  1978. break;
  1979. case SDL_WINDOWEVENT_MAXIMIZED:
  1980. case SDL_WINDOWEVENT_RESTORED:
  1981. #if defined(IOS) || defined(TVOS) || defined (__ANDROID__)
  1982. // On iOS/tvOS we never lose the GL context, but may have done GPU object changes that could not be applied yet. Apply them now
  1983. // On Android the old GL context may be lost already, restore GPU objects to the new GL context
  1984. graphics_->Restore_OGL();
  1985. #endif
  1986. minimized_ = false;
  1987. SendInputFocusEvent();
  1988. break;
  1989. case SDL_WINDOWEVENT_RESIZED:
  1990. graphics_->OnWindowResized();
  1991. break;
  1992. case SDL_WINDOWEVENT_MOVED:
  1993. graphics_->OnWindowMoved();
  1994. break;
  1995. default: break;
  1996. }
  1997. }
  1998. break;
  1999. case SDL_DROPFILE:
  2000. {
  2001. using namespace DropFile;
  2002. VariantMap& eventData = GetEventDataMap();
  2003. eventData[P_FILENAME] = GetInternalPath(String(evt.drop.file));
  2004. SDL_free(evt.drop.file);
  2005. SendEvent(E_DROPFILE, eventData);
  2006. }
  2007. break;
  2008. case SDL_QUIT:
  2009. SendEvent(E_EXITREQUESTED);
  2010. break;
  2011. default: break;
  2012. }
  2013. }
  2014. void Input::HandleScreenMode(StringHash eventType, VariantMap& eventData)
  2015. {
  2016. if (!initialized_)
  2017. Initialize();
  2018. // Re-enable cursor clipping, and re-center the cursor (if needed) to the new screen size, so that there is no erroneous
  2019. // mouse move event. Also get new window ID if it changed
  2020. SDL_Window* window = graphics_->GetWindow();
  2021. windowID_ = SDL_GetWindowID(window);
  2022. // Resize screen joysticks to new screen size
  2023. for (HashMap<SDL_JoystickID, JoystickState>::Iterator i = joysticks_.Begin(); i != joysticks_.End(); ++i)
  2024. {
  2025. UIElement* screenjoystick = i->second_.screenJoystick_;
  2026. if (screenjoystick)
  2027. screenjoystick->SetSize(graphics_->GetWidth(), graphics_->GetHeight());
  2028. }
  2029. if (graphics_->GetFullscreen() || !mouseVisible_)
  2030. focusedThisFrame_ = true;
  2031. // After setting a new screen mode we should not be minimized
  2032. minimized_ = (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) != 0;
  2033. // Calculate input coordinate scaling from SDL window to backbuffer ratio
  2034. int winWidth, winHeight;
  2035. int gfxWidth = graphics_->GetWidth();
  2036. int gfxHeight = graphics_->GetHeight();
  2037. SDL_GetWindowSize(window, &winWidth, &winHeight);
  2038. if (winWidth > 0 && winHeight > 0 && gfxWidth > 0 && gfxHeight > 0)
  2039. {
  2040. inputScale_.x_ = (float)gfxWidth / (float)winWidth;
  2041. inputScale_.y_ = (float)gfxHeight / (float)winHeight;
  2042. }
  2043. else
  2044. inputScale_ = Vector2::ONE;
  2045. }
  2046. void Input::HandleBeginFrame(StringHash eventType, VariantMap& eventData)
  2047. {
  2048. // Update input right at the beginning of the frame
  2049. SendEvent(E_INPUTBEGIN);
  2050. Update();
  2051. SendEvent(E_INPUTEND);
  2052. }
  2053. #ifdef __EMSCRIPTEN__
  2054. void Input::HandleEndFrame(StringHash eventType, VariantMap& eventData)
  2055. {
  2056. if (suppressNextMouseMove_ && mouseMove_ != IntVector2::ZERO)
  2057. UnsuppressMouseMove();
  2058. ResetInputAccumulation();
  2059. }
  2060. #endif
  2061. void Input::HandleScreenJoystickTouch(StringHash eventType, VariantMap& eventData)
  2062. {
  2063. using namespace TouchBegin;
  2064. // Only interested in events from screen joystick(s)
  2065. TouchState& state = touches_[eventData[P_TOUCHID].GetInt()];
  2066. IntVector2 position(int(state.position_.x_ / GetSubsystem<UI>()->GetScale()), int(state.position_.y_ / GetSubsystem<UI>()->GetScale()));
  2067. UIElement* element = eventType == E_TOUCHBEGIN ? GetSubsystem<UI>()->GetElementAt(position) : state.touchedElement_;
  2068. if (!element)
  2069. return;
  2070. Variant variant = element->GetVar(VAR_SCREEN_JOYSTICK_ID);
  2071. if (variant.IsEmpty())
  2072. return;
  2073. SDL_JoystickID joystickID = variant.GetInt();
  2074. if (eventType == E_TOUCHEND)
  2075. state.touchedElement_.Reset();
  2076. else
  2077. state.touchedElement_ = element;
  2078. // Prepare a fake SDL event
  2079. SDL_Event evt;
  2080. const String& name = element->GetName();
  2081. if (name.StartsWith("Button"))
  2082. {
  2083. if (eventType == E_TOUCHMOVE)
  2084. return;
  2085. // Determine whether to inject a joystick event or keyboard/mouse event
  2086. const Variant& keyBindingVar = element->GetVar(VAR_BUTTON_KEY_BINDING);
  2087. const Variant& mouseButtonBindingVar = element->GetVar(VAR_BUTTON_MOUSE_BUTTON_BINDING);
  2088. if (keyBindingVar.IsEmpty() && mouseButtonBindingVar.IsEmpty())
  2089. {
  2090. evt.type = eventType == E_TOUCHBEGIN ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP;
  2091. evt.jbutton.which = joystickID;
  2092. evt.jbutton.button = (Uint8)ToUInt(name.Substring(6));
  2093. }
  2094. else
  2095. {
  2096. if (!keyBindingVar.IsEmpty())
  2097. {
  2098. evt.type = eventType == E_TOUCHBEGIN ? SDL_KEYDOWN : SDL_KEYUP;
  2099. evt.key.keysym.sym = ToLower(keyBindingVar.GetInt());
  2100. evt.key.keysym.scancode = SDL_SCANCODE_UNKNOWN;
  2101. }
  2102. if (!mouseButtonBindingVar.IsEmpty())
  2103. {
  2104. // Mouse button are sent as extra events besides key events
  2105. // Disable touch emulation handling during this to prevent endless loop
  2106. bool oldTouchEmulation = touchEmulation_;
  2107. touchEmulation_ = false;
  2108. SDL_Event mouseEvent;
  2109. mouseEvent.type = eventType == E_TOUCHBEGIN ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
  2110. mouseEvent.button.button = (Uint8)mouseButtonBindingVar.GetInt();
  2111. HandleSDLEvent(&mouseEvent);
  2112. touchEmulation_ = oldTouchEmulation;
  2113. }
  2114. }
  2115. }
  2116. else if (name.StartsWith("Hat"))
  2117. {
  2118. Variant keyBindingVar = element->GetVar(VAR_BUTTON_KEY_BINDING);
  2119. if (keyBindingVar.IsEmpty())
  2120. {
  2121. evt.type = SDL_JOYHATMOTION;
  2122. evt.jaxis.which = joystickID;
  2123. evt.jhat.hat = (Uint8)ToUInt(name.Substring(3));
  2124. evt.jhat.value = HAT_CENTER;
  2125. if (eventType != E_TOUCHEND)
  2126. {
  2127. IntVector2 relPosition = position - element->GetScreenPosition() - element->GetSize() / 2;
  2128. if (relPosition.y_ < 0 && Abs(relPosition.x_ * 3 / 2) < Abs(relPosition.y_))
  2129. evt.jhat.value |= HAT_UP;
  2130. if (relPosition.y_ > 0 && Abs(relPosition.x_ * 3 / 2) < Abs(relPosition.y_))
  2131. evt.jhat.value |= HAT_DOWN;
  2132. if (relPosition.x_ < 0 && Abs(relPosition.y_ * 3 / 2) < Abs(relPosition.x_))
  2133. evt.jhat.value |= HAT_LEFT;
  2134. if (relPosition.x_ > 0 && Abs(relPosition.y_ * 3 / 2) < Abs(relPosition.x_))
  2135. evt.jhat.value |= HAT_RIGHT;
  2136. }
  2137. }
  2138. else
  2139. {
  2140. // Hat is binded by 4 integers representing keysyms for 'w', 's', 'a', 'd' or something similar
  2141. IntRect keyBinding = keyBindingVar.GetIntRect();
  2142. if (eventType == E_TOUCHEND)
  2143. {
  2144. evt.type = SDL_KEYUP;
  2145. evt.key.keysym.sym = element->GetVar(VAR_LAST_KEYSYM).GetInt();
  2146. if (!evt.key.keysym.sym)
  2147. return;
  2148. element->SetVar(VAR_LAST_KEYSYM, 0);
  2149. }
  2150. else
  2151. {
  2152. evt.type = SDL_KEYDOWN;
  2153. IntVector2 relPosition = position - element->GetScreenPosition() - element->GetSize() / 2;
  2154. if (relPosition.y_ < 0 && Abs(relPosition.x_ * 3 / 2) < Abs(relPosition.y_))
  2155. evt.key.keysym.sym = keyBinding.left_; // The integers are encoded in WSAD order to l-t-r-b
  2156. else if (relPosition.y_ > 0 && Abs(relPosition.x_ * 3 / 2) < Abs(relPosition.y_))
  2157. evt.key.keysym.sym = keyBinding.top_;
  2158. else if (relPosition.x_ < 0 && Abs(relPosition.y_ * 3 / 2) < Abs(relPosition.x_))
  2159. evt.key.keysym.sym = keyBinding.right_;
  2160. else if (relPosition.x_ > 0 && Abs(relPosition.y_ * 3 / 2) < Abs(relPosition.x_))
  2161. evt.key.keysym.sym = keyBinding.bottom_;
  2162. else
  2163. return;
  2164. if (eventType == E_TOUCHMOVE && evt.key.keysym.sym != element->GetVar(VAR_LAST_KEYSYM).GetInt())
  2165. {
  2166. // Dragging past the directional boundary will cause an additional key up event for previous key symbol
  2167. SDL_Event keyEvent;
  2168. keyEvent.type = SDL_KEYUP;
  2169. keyEvent.key.keysym.sym = element->GetVar(VAR_LAST_KEYSYM).GetInt();
  2170. if (keyEvent.key.keysym.sym)
  2171. {
  2172. keyEvent.key.keysym.scancode = SDL_SCANCODE_UNKNOWN;
  2173. HandleSDLEvent(&keyEvent);
  2174. }
  2175. element->SetVar(VAR_LAST_KEYSYM, 0);
  2176. }
  2177. evt.key.keysym.scancode = SDL_SCANCODE_UNKNOWN;
  2178. element->SetVar(VAR_LAST_KEYSYM, evt.key.keysym.sym);
  2179. }
  2180. }
  2181. }
  2182. else
  2183. return;
  2184. // Handle the fake SDL event to turn it into Urho3D genuine event
  2185. HandleSDLEvent(&evt);
  2186. }
  2187. }