Input.cpp 60 KB

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