Input.cpp 51 KB

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