Input.cpp 48 KB

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