UIViewInput.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. //
  2. // Copyright (c) 2014-2015, THUNDERBEAST GAMES LLC All rights reserved
  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 <TurboBadger/tb_widgets.h>
  23. using namespace tb;
  24. #include "../Core/Timer.h"
  25. #include "../Input/Input.h"
  26. #include "../Input/InputEvents.h"
  27. #include "UI.h"
  28. #include "UIEvents.h"
  29. #include "UIView.h"
  30. namespace Atomic
  31. {
  32. static MODIFIER_KEYS GetModifierKeys(int qualifiers, bool superKey)
  33. {
  34. MODIFIER_KEYS code = TB_MODIFIER_NONE;
  35. if (qualifiers & QUAL_ALT) code |= TB_ALT;
  36. if (qualifiers & QUAL_CTRL) code |= TB_CTRL;
  37. if (qualifiers & QUAL_SHIFT) code |= TB_SHIFT;
  38. if (superKey) code |= TB_SUPER;
  39. return code;
  40. }
  41. // @return Return the upper case of a ascii charcter. Only for shortcut handling.
  42. static int toupr_ascii(int ascii)
  43. {
  44. if (ascii >= 'a' && ascii <= 'z')
  45. return ascii + 'A' - 'a';
  46. return ascii;
  47. }
  48. bool UIView::FilterDefaultInput(bool keyEvent) const
  49. {
  50. if (!GetInputEnabled())
  51. return true;
  52. if (ui_.Null() || ui_->GetFocusedView() != this)
  53. return true;
  54. if (ui_->inputDisabled_ || ui_->consoleVisible_)
  55. return true;
  56. if (renderTexture_ && !keyEvent)
  57. return true;
  58. if (!keyEvent && !GetMouseEnabled())
  59. return true;
  60. if (keyEvent && !GetKeyboardEnabled() || ui_->keyboardDisabled_)
  61. return true;
  62. return false;
  63. }
  64. void UIView::HandleMouseButtonDown(StringHash eventType, VariantMap& eventData)
  65. {
  66. if (FilterDefaultInput())
  67. return;
  68. using namespace MouseButtonDown;
  69. unsigned button = eventData[P_BUTTON].GetUInt();
  70. IntVector2 pos;
  71. pos = GetSubsystem<Input>()->GetMousePosition();
  72. Input* input = GetSubsystem<Input>();
  73. int qualifiers = input->GetQualifiers();
  74. #ifdef ATOMIC_PLATFORM_OSX
  75. bool superdown = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  76. #else
  77. bool superdown = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  78. #endif
  79. MODIFIER_KEYS mod = GetModifierKeys(qualifiers, superdown);
  80. static double last_time = 0;
  81. static int counter = 1;
  82. Time* t = GetSubsystem<Time>();
  83. double time = t->GetElapsedTime() * 1000;
  84. if (time < last_time + 600)
  85. counter++;
  86. else
  87. counter = 1;
  88. last_time = time;
  89. if (button == MOUSEB_RIGHT)
  90. widget_->InvokeRightPointerDown(pos.x_, pos.y_, counter, mod);
  91. else
  92. widget_->InvokePointerDown(pos.x_, pos.y_, counter, mod, false);
  93. }
  94. void UIView::HandleMouseButtonUp(StringHash eventType, VariantMap& eventData)
  95. {
  96. if (FilterDefaultInput())
  97. return;
  98. using namespace MouseButtonUp;
  99. unsigned button = eventData[P_BUTTON].GetUInt();
  100. IntVector2 pos;
  101. Input* input = GetSubsystem<Input>();
  102. pos = input->GetMousePosition();
  103. int qualifiers = input->GetQualifiers();
  104. #ifdef ATOMIC_PLATFORM_OSX
  105. bool superdown = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  106. #else
  107. bool superdown = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  108. #endif
  109. MODIFIER_KEYS mod = GetModifierKeys(qualifiers, superdown);
  110. if (button == MOUSEB_RIGHT)
  111. widget_->InvokeRightPointerUp(pos.x_, pos.y_, mod);
  112. else
  113. widget_->InvokePointerUp(pos.x_, pos.y_, mod, false);
  114. }
  115. void UIView::HandleMouseMove(StringHash eventType, VariantMap& eventData)
  116. {
  117. using namespace MouseMove;
  118. if (FilterDefaultInput())
  119. return;
  120. int px = eventData[P_X].GetInt();
  121. int py = eventData[P_Y].GetInt();
  122. widget_->InvokePointerMove(px, py, tb::TB_MODIFIER_NONE, false);
  123. ui_->tooltipHoverTime_ = 0;
  124. }
  125. void UIView::HandleMouseWheel(StringHash eventType, VariantMap& eventData)
  126. {
  127. if (FilterDefaultInput())
  128. return;
  129. using namespace MouseWheel;
  130. int delta = eventData[P_WHEEL].GetInt();
  131. Input* input = GetSubsystem<Input>();
  132. widget_->InvokeWheel(input->GetMousePosition().x_, input->GetMousePosition().y_, 0, -delta, tb::TB_MODIFIER_NONE);
  133. }
  134. //Touch Input
  135. void UIView::HandleTouchBegin(StringHash eventType, VariantMap& eventData)
  136. {
  137. if (FilterDefaultInput())
  138. return;
  139. using namespace TouchBegin;
  140. int touchId = eventData[P_TOUCHID].GetInt();
  141. int px = eventData[P_X].GetInt();
  142. int py = eventData[P_Y].GetInt();
  143. static double last_time = 0;
  144. static int counter = 1;
  145. Time* t = GetSubsystem<Time>();
  146. double time = t->GetElapsedTime() * 1000;
  147. if (time < last_time + 600)
  148. counter++;
  149. else
  150. counter = 1;
  151. last_time = time;
  152. widget_->InvokePointerDown(px, py, counter, TB_MODIFIER_NONE, true, touchId);
  153. }
  154. void UIView::HandleTouchMove(StringHash eventType, VariantMap& eventData)
  155. {
  156. if (FilterDefaultInput())
  157. return;
  158. using namespace TouchMove;
  159. int touchId = eventData[P_TOUCHID].GetInt();
  160. int px = eventData[P_X].GetInt();
  161. int py = eventData[P_Y].GetInt();
  162. widget_->InvokePointerMove(px, py, TB_MODIFIER_NONE, true, touchId);
  163. }
  164. void UIView::HandleTouchEnd(StringHash eventType, VariantMap& eventData)
  165. {
  166. if (FilterDefaultInput())
  167. return;
  168. using namespace TouchEnd;
  169. int touchId = eventData[P_TOUCHID].GetInt();
  170. int px = eventData[P_X].GetInt();
  171. int py = eventData[P_Y].GetInt();
  172. widget_->InvokePointerUp(px, py, TB_MODIFIER_NONE, true, touchId);
  173. }
  174. static bool InvokeShortcut(UI* ui, int key, SPECIAL_KEY special_key, MODIFIER_KEYS modifierkeys, bool down)
  175. {
  176. #ifdef __APPLE__
  177. bool shortcut_key = (modifierkeys & TB_SUPER) ? true : false;
  178. #else
  179. bool shortcut_key = (modifierkeys & TB_CTRL) ? true : false;
  180. #endif
  181. if (!down || (!shortcut_key && special_key ==TB_KEY_UNDEFINED))
  182. return false;
  183. bool reverse_key = (modifierkeys & TB_SHIFT) ? true : false;
  184. int upper_key = toupr_ascii(key);
  185. TBID id;
  186. if (upper_key == 'X')
  187. id = TBIDC("cut");
  188. else if (upper_key == 'C' || special_key == TB_KEY_INSERT)
  189. id = TBIDC("copy");
  190. else if (upper_key == 'V' || (special_key == TB_KEY_INSERT && reverse_key))
  191. id = TBIDC("paste");
  192. else if (upper_key == 'A')
  193. id = TBIDC("selectall");
  194. else if (upper_key == 'Z' || upper_key == 'Y')
  195. {
  196. bool undo = upper_key == 'Z';
  197. if (reverse_key)
  198. undo = !undo;
  199. id = undo ? TBIDC("undo") : TBIDC("redo");
  200. }
  201. else if (upper_key == 'N')
  202. id = TBIDC("new");
  203. else if (upper_key == 'O')
  204. id = TBIDC("open");
  205. else if (upper_key == 'S')
  206. id = TBIDC("save");
  207. else if (upper_key == 'W')
  208. id = TBIDC("close");
  209. else if (upper_key == 'F')
  210. id = TBIDC("find");
  211. #ifdef ATOMIC_PLATFORM_OSX
  212. else if (upper_key == 'G' && (modifierkeys & TB_SHIFT))
  213. id = TBIDC("findprev");
  214. else if (upper_key == 'G')
  215. id = TBIDC("findnext");
  216. #else
  217. else if (special_key == TB_KEY_F3 && (modifierkeys & TB_SHIFT))
  218. id = TBIDC("findprev");
  219. else if (special_key == TB_KEY_F3)
  220. id = TBIDC("findnext");
  221. #endif
  222. else if (upper_key == 'P')
  223. id = TBIDC("play");
  224. else if (special_key == TB_KEY_PAGE_UP)
  225. id = TBIDC("prev_doc");
  226. else if (special_key == TB_KEY_PAGE_DOWN)
  227. id = TBIDC("next_doc");
  228. else
  229. return false;
  230. TBWidgetEvent ev(EVENT_TYPE_SHORTCUT);
  231. ev.modifierkeys = modifierkeys;
  232. ev.ref_id = id;
  233. TBWidget* eventWidget = TBWidget::focused_widget;
  234. if (id == TBIDC("save") || id == TBIDC("close")) {
  235. while (eventWidget && !eventWidget->GetDelegate()) {
  236. eventWidget = eventWidget->GetParent();
  237. }
  238. }
  239. if (!eventWidget || !eventWidget->InvokeEvent(ev))
  240. {
  241. VariantMap evData;
  242. evData[UIUnhandledShortcut::P_REFID] = id;
  243. ui->SendEvent(E_UIUNHANDLEDSHORTCUT, evData);
  244. return false;
  245. }
  246. return true;
  247. }
  248. static bool InvokeKey(UI* ui, TBWidget* root, unsigned int key, SPECIAL_KEY special_key, MODIFIER_KEYS modifierkeys, bool keydown)
  249. {
  250. if (InvokeShortcut(ui, key, special_key, modifierkeys, keydown))
  251. return true;
  252. root->InvokeKey(key, special_key, modifierkeys, keydown);
  253. return true;
  254. }
  255. void UIView::HandleKey(bool keydown, int keycode, int scancode)
  256. {
  257. if (keydown && (keycode == KEY_ESCAPE || keycode == KEY_RETURN || keycode == KEY_RETURN2 || keycode == KEY_KP_ENTER)
  258. && TBWidget::focused_widget)
  259. {
  260. SendEvent(E_UIWIDGETFOCUSESCAPED);
  261. }
  262. #ifndef ATOMIC_PLATFORM_OSX
  263. if (keycode == KEY_LCTRL || keycode == KEY_RCTRL)
  264. return;
  265. #else
  266. if (keycode == KEY_LGUI || keycode == KEY_RGUI)
  267. return;
  268. #endif
  269. Input* input = GetSubsystem<Input>();
  270. int qualifiers = input->GetQualifiers();
  271. #ifndef ATOMIC_PLATFORM_OSX
  272. bool superdown = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  273. #else
  274. bool superdown = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  275. #endif
  276. MODIFIER_KEYS mod = GetModifierKeys(qualifiers, superdown);
  277. SPECIAL_KEY specialKey = TB_KEY_UNDEFINED;
  278. switch (keycode)
  279. {
  280. case KEY_RETURN:
  281. case KEY_RETURN2:
  282. case KEY_KP_ENTER:
  283. specialKey = TB_KEY_ENTER;
  284. break;
  285. case KEY_F1:
  286. specialKey = TB_KEY_F1;
  287. break;
  288. case KEY_F2:
  289. specialKey = TB_KEY_F2;
  290. break;
  291. case KEY_F3:
  292. specialKey = TB_KEY_F3;
  293. break;
  294. case KEY_F4:
  295. specialKey = TB_KEY_F4;
  296. break;
  297. case KEY_F5:
  298. specialKey = TB_KEY_F5;
  299. break;
  300. case KEY_F6:
  301. specialKey = TB_KEY_F6;
  302. break;
  303. case KEY_F7:
  304. specialKey = TB_KEY_F7;
  305. break;
  306. case KEY_F8:
  307. specialKey = TB_KEY_F8;
  308. break;
  309. case KEY_F9:
  310. specialKey = TB_KEY_F9;
  311. break;
  312. case KEY_F10:
  313. specialKey = TB_KEY_F10;
  314. break;
  315. case KEY_F11:
  316. specialKey = TB_KEY_F11;
  317. break;
  318. case KEY_F12:
  319. specialKey = TB_KEY_F12;
  320. break;
  321. case KEY_LEFT:
  322. specialKey = TB_KEY_LEFT;
  323. break;
  324. case KEY_UP:
  325. specialKey = TB_KEY_UP;
  326. break;
  327. case KEY_RIGHT:
  328. specialKey = TB_KEY_RIGHT;
  329. break;
  330. case KEY_DOWN:
  331. specialKey = TB_KEY_DOWN;
  332. break;
  333. case KEY_PAGEUP:
  334. specialKey = TB_KEY_PAGE_UP;
  335. break;
  336. case KEY_PAGEDOWN:
  337. specialKey = TB_KEY_PAGE_DOWN;
  338. break;
  339. case KEY_HOME:
  340. specialKey = TB_KEY_HOME;
  341. break;
  342. case KEY_END:
  343. specialKey = TB_KEY_END;
  344. break;
  345. case KEY_INSERT:
  346. specialKey = TB_KEY_INSERT;
  347. break;
  348. case KEY_TAB:
  349. specialKey = TB_KEY_TAB;
  350. break;
  351. case KEY_DELETE:
  352. specialKey = TB_KEY_DELETE;
  353. break;
  354. case KEY_BACKSPACE:
  355. specialKey = TB_KEY_BACKSPACE;
  356. break;
  357. case KEY_ESCAPE:
  358. specialKey = TB_KEY_ESC;
  359. break;
  360. }
  361. if (specialKey == TB_KEY_UNDEFINED)
  362. {
  363. if (mod & TB_SUPER)
  364. {
  365. InvokeKey(ui_, widget_, keycode, TB_KEY_UNDEFINED, mod, keydown);
  366. }
  367. }
  368. else
  369. {
  370. InvokeKey(ui_, widget_, 0, specialKey, mod, keydown);
  371. }
  372. }
  373. void UIView::HandleKeyDown(StringHash eventType, VariantMap& eventData)
  374. {
  375. if (FilterDefaultInput(true))
  376. return;
  377. using namespace KeyDown;
  378. int keycode = eventData[P_KEY].GetInt();
  379. int scancode = eventData[P_SCANCODE].GetInt();
  380. HandleKey(true, keycode, scancode);
  381. // Send Global Shortcut
  382. Input* input = GetSubsystem<Input>();
  383. #ifndef ATOMIC_PLATFORM_OSX
  384. bool superdown = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
  385. if (keycode == KEY_LCTRL || keycode == KEY_RCTRL)
  386. superdown = false;
  387. #else
  388. bool superdown = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
  389. if (keycode == KEY_LGUI || keycode == KEY_RGUI)
  390. superdown = false;
  391. #endif
  392. if (!superdown)
  393. return;
  394. VariantMap shortcutData;
  395. shortcutData[UIShortcut::P_KEY] = keycode;
  396. shortcutData[UIShortcut::P_QUALIFIERS] = eventData[P_QUALIFIERS].GetInt();
  397. SendEvent(E_UISHORTCUT, shortcutData);
  398. }
  399. void UIView::HandleKeyUp(StringHash eventType, VariantMap& eventData)
  400. {
  401. if (FilterDefaultInput(true))
  402. return;
  403. using namespace KeyUp;
  404. int keycode = eventData[P_KEY].GetInt();
  405. int scancode = eventData[P_SCANCODE].GetInt();
  406. HandleKey(false, keycode, scancode);
  407. }
  408. void UIView::HandleTextInput(StringHash eventType, VariantMap& eventData)
  409. {
  410. if (FilterDefaultInput(true))
  411. return;
  412. using namespace TextInput;
  413. const String& text = eventData[P_TEXT].GetString();
  414. for (unsigned i = 0; i < text.Length(); i++)
  415. {
  416. InvokeKey(ui_, widget_, text[i], TB_KEY_UNDEFINED, TB_MODIFIER_NONE, true);
  417. InvokeKey(ui_, widget_, text[i], TB_KEY_UNDEFINED, TB_MODIFIER_NONE, false);
  418. }
  419. }
  420. }