ManaPlus
inputmanager.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2012-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "input/inputmanager.h"
23 
24 #include "configuration.h"
25 #include "game.h"
26 #include "settings.h"
27 
28 #include "being/localplayer.h"
29 #include "being/playerinfo.h"
30 
31 #include "input/inputactionmap.h"
33 #include "input/joystick.h"
34 #include "input/keyboardconfig.h"
35 #ifdef USE_SDL2
37 #endif // USE_SDL2
38 
40 
41 #include "gui/gui.h"
42 #include "gui/sdlinput.h"
43 
44 #include "gui/widgets/selldialog.h"
45 #include "gui/widgets/textfield.h"
46 
48 
49 #include "gui/windows/buydialog.h"
50 #include "gui/windows/chatwindow.h"
52 #include "gui/windows/npcdialog.h"
54 #include "gui/windows/textdialog.h"
56 
57 #include "utils/checkutils.h"
58 #include "utils/foreach.h"
59 #include "utils/gettext.h"
60 #include "utils/stdmove.h"
61 #include "utils/timer.h"
62 
63 #include "gui/focushandler.h"
64 
65 #include <algorithm>
66 
67 #include "debug.h"
68 
70 
71 class QuitDialog;
72 
73 extern QuitDialog *quitDialog;
74 
75 namespace
76 {
78 } // namespace
79 
81  mSetupInput(nullptr),
82  mNewKeyIndex(InputAction::NO_VALUE),
83  mMask(1),
84  mNameMap(),
85  mChatMap(),
86  mKey()
87 {
88 }
89 
91 {
92 #ifdef __SWITCH__
93  SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "1");
94 #endif
95  for (size_t i = 0;
97  i ++)
98  {
99  InputFunction &kf = mKey[i];
100  mKeyStr[i].clear();
101  for (size_t f = 0; f < inputFunctionSize; f ++)
102  {
103  InputItem &ki = kf.values[f];
105  ki.value = -1;
106  }
107  }
108 
110 
111  resetKeys();
112  retrieve();
113  update();
114 }
115 
117 {
118  keyboard.update();
119  if (joystick != nullptr)
120  joystick->update();
121 }
122 
124 {
125  for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
126  {
127  const std::string &restrict cmd = inputActionData[i].chatCommand;
128  if (!cmd.empty())
129  {
130  StringVect tokens;
131  splitToStringVector(tokens, cmd, '|');
132  FOR_EACH (StringVectCIter, it, tokens)
133  mChatMap[*it] = i;
134  }
135 #ifdef USE_SDL2
136  const std::string cf = std::string("sdl2")
138 #else // USE_SDL2
139 
140  const std::string cf = inputActionData[i].configField;
141 #endif // USE_SDL2
142 
143  InputFunction &restrict kf = mKey[i];
144  if (!cf.empty())
145  {
146  mNameMap[cf] = static_cast<InputActionT>(i);
147  const std::string keyStr = config.getValue(cf, "");
148  const size_t keyStrSize = keyStr.size();
149  if (keyStr.empty())
150  {
151  updateKeyString(kf, i);
152  continue;
153  }
154 
155  StringVect keys;
156  splitToStringVector(keys, keyStr, ',');
157  unsigned int i2 = 0;
158  for (StringVectCIter it = keys.begin(), it_end = keys.end();
159  it != it_end && i2 < inputFunctionSize; ++ it)
160  {
161  std::string keyStr2 = *it;
162  if (keyStrSize < 2)
163  continue;
165  if ((keyStr2[0] < '0' || keyStr2[0] > '9')
166  && keyStr2[0] != '-')
167  {
168  switch (keyStr2[0])
169  {
170  case 'm':
171  type = InputType::MOUSE;
172  break;
173  case 'j':
174  type = InputType::JOYSTICK;
175  break;
176  default:
177  break;
178  }
179  keyStr2 = keyStr2.substr(1);
180  }
181  const int key = atoi(keyStr2.c_str());
182  if (key >= -255 && key < SDLK_LAST)
183  {
184  kf.values[i2] = InputItem(type, key);
185  i2 ++;
186  }
187  }
188  for (; i2 < inputFunctionSize; i2 ++)
189  kf.values[i2] = InputItem();
190  }
191  updateKeyString(kf, i);
192  }
193 }
194 
196 {
197  for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
198  {
199 #ifdef USE_SDL2
200  const std::string cf = std::string("sdl2")
202 #else // USE_SDL2
203 
204  const std::string cf = inputActionData[i].configField;
205 #endif // USE_SDL2
206 
207  if (!cf.empty())
208  {
209  std::string keyStr;
210  const InputFunction &restrict kf = mKey[i];
211 
212  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
213  {
214  const InputItem &restrict key = kf.values[i2];
215  if (key.type != InputType::UNKNOWN)
216  {
217  std::string tmp("k");
218  switch (key.type)
219  {
220  case InputType::MOUSE:
221  tmp = "m";
222  break;
223  case InputType::JOYSTICK:
224  tmp = "j";
225  break;
226  case InputType::KEYBOARD:
227  case InputType::UNKNOWN:
228  default:
229  break;
230  }
231  if (key.value != -1)
232  {
233  if (keyStr.empty())
234  {
235  keyStr.append(tmp).append(toString(key.value));
236  }
237  else
238  {
239  keyStr.append(strprintf(",%s%d",
240  tmp.c_str(), key.value));
241  }
242  }
243  }
244  }
245  if (keyStr.empty())
246  keyStr = "-1";
247 
248  config.setValue(cf, keyStr);
249  }
250  }
251 }
252 
254 {
255  InputFunction &restrict key = mKey[CAST_SIZE(i)];
256  for (size_t i2 = 1; i2 < inputFunctionSize; i2 ++)
257  {
258  InputItem &restrict ki2 = key.values[i2];
259  ki2.type = InputType::UNKNOWN;
260  ki2.value = -1;
261  }
262  const InputActionData &restrict kd =
264  InputItem &restrict val0 = key.values[0];
265  val0.type = kd.defaultType1;
266  InputItem &restrict val1 = key.values[1];
267  val1.type = kd.defaultType2;
268 #ifdef USE_SDL2
269  if (kd.defaultType1 == InputType::KEYBOARD)
270  {
271  val0.value = SDL_GetScancodeFromKey(kd.defaultValue1);
272  if (val0.value == SDL_SCANCODE_UNKNOWN)
273  val0.value = -1;
274  }
275  else
276  val0.value = kd.defaultValue1;
277  if (kd.defaultType2 == InputType::KEYBOARD)
278  {
279  val1.value = SDL_GetScancodeFromKey(kd.defaultValue2);
280  if (val1.value == SDL_SCANCODE_UNKNOWN)
281  val1.value = -1;
282  }
283  else
284  val1.value = kd.defaultValue2;
285 #else // USE_SDL2
286 
287  val0.value = kd.defaultValue1;
288  val1.value = kd.defaultValue2;
289 #endif // USE_SDL2
290 
291  updateKeyString(key, CAST_SIZE(i));
292 }
293 
295 {
296  for (int i = 0; i < CAST_S32(InputAction::TOTAL); i++)
297  resetKey(static_cast<InputActionT>(i));
298 }
299 
301 {
303  {
304  resetKey(i);
305  update();
306  }
307 }
308 
310  InputActionT &restrict key2) const restrict2
311 {
316  for (int i = 0; i < CAST_S32(InputAction::TOTAL); i++)
317  {
318  const InputActionData &restrict kdi = inputActionData[i];
319  if (*kdi.configField == 0)
320  continue;
321 
322  const InputFunction &restrict ki = mKey[i];
323  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
324  {
325  const InputItem &restrict vali2 = ki.values[i2];
326  if (vali2.value == -1)
327  continue;
328 
329  size_t j;
330  for (j = i, j++; j < CAST_S32(InputAction::TOTAL); j++)
331  {
332  if ((kdi.grp & inputActionData[j].grp) == 0
333  || (*kdi.configField == 0))
334  {
335  continue;
336  }
337 
338  for (size_t j2 = 0; j2 < inputFunctionSize; j2 ++)
339  {
340  const InputItem &restrict valj2 = mKey[j].values[j2];
341  // Allow for item shortcut and emote keys to overlap
342  // as well as emote and ignore keys, but no other keys
343  if (valj2.type != InputType::UNKNOWN
344  && vali2.value == valj2.value
345  && vali2.type == valj2.type)
346  {
347  key1 = static_cast<InputActionT>(i);
348  key2 = static_cast<InputActionT>(j);
349  return true;
350  }
351  }
352  }
353  }
354  }
355  return false;
356 }
357 
359 {
360 #ifndef DYECMD
362 #endif // DYECMD
363 }
364 
366 {
367  if (!isActionActive0(index))
368  return false;
369 
370  const InputActionData &restrict key =
371  inputActionData[CAST_SIZE(index)];
372 // logger->log("isActionActive mask=%d, condition=%d, index=%d",
373 // mMask, key.condition, index);
374  if ((key.condition & mMask) != key.condition)
375  return false;
376  return true;
377 }
378 
380 {
381  if (keyboard.isActionActive(index))
382  return true;
383  if ((joystick != nullptr) && joystick->isActionActive(index))
384  return true;
385  return touchManager.isActionActive(index);
386 }
387 
389 {
390  if (CAST_S32(index) < 0 || index >= InputAction::TOTAL)
391  index = InputAction::MOVE_UP;
392  return mKey[CAST_SIZE(index)];
393 }
394 
395 std::string InputManager::getKeyStringLong(const InputActionT index) const
396  restrict2
397 {
398  std::string keyStr;
399  const InputFunction &restrict ki = mKey[CAST_SIZE(index)];
400 
401  for (size_t i = 0; i < inputFunctionSize; i ++)
402  {
403  const InputItem &restrict key = ki.values[i];
404  std::string str;
405  if (key.type == InputType::KEYBOARD)
406  {
407  if (key.value >= 0)
408  {
409  str = KeyboardConfig::getKeyName(key.value);
410  }
411  else if (key.value < -1)
412  {
413  // TRANSLATORS: long key name. must be short.
414  str = strprintf(_("key_%d"), -key.value);
415  }
416  }
417  else if (key.type == InputType::JOYSTICK)
418  {
419  // TRANSLATORS: long joystick button name. must be short.
420  str = strprintf(_("JButton%d"), key.value + 1);
421  }
422  if (!str.empty())
423  {
424  if (keyStr.empty())
425  keyStr = str;
426  else
427  keyStr.append(", ").append(str);
428  }
429  }
430 
431  if (keyStr.empty())
432  {
433  // TRANSLATORS: unknown long key type
434  return _("unknown key");
435  }
436  return keyStr;
437 }
438 
440  const size_t actionIdx) restrict2
441 {
442  std::string keyStr;
443  for (size_t i = 0; i < inputFunctionSize; i ++)
444  {
445  const InputItem &restrict key = ki.values[i];
446  std::string str;
447  if (key.type == InputType::KEYBOARD)
448  {
449  if (key.value >= 0)
450  {
452  KeyboardConfig::getKeyName(key.value));
453  }
454  else if (key.value < -1)
455  {
456  // TRANSLATORS: short key name. must be very short.
457  str = strprintf(_("key_%d"), -key.value);
458  }
459  }
460  else if (key.type == InputType::JOYSTICK)
461  {
462  // TRANSLATORS: short joystick button name. muse be very short
463  str = strprintf(_("JB%d"), key.value + 1);
464  }
465  if (!str.empty())
466  {
467  if (keyStr.empty())
468  keyStr = str;
469  else
470  keyStr.append(", ").append(str);
471  }
472  }
473 
474  if (keyStr.empty())
475  {
476  // TRANSLATORS: unknown short key type. must be short
477  mKeyStr[actionIdx] = _("u key");
478  }
479  else
480  {
481  mKeyStr[actionIdx] = STD_MOVE(keyStr);
482  }
483 }
484 
485 std::string InputManager::getKeyValueString(const InputActionT index) const
486  restrict2
487 {
488  return mKeyStr[CAST_SIZE(index)];
489 }
490 
491 std::string InputManager::getKeyValueByName(const std::string &restrict
492  keyName) restrict2
493 {
494  const StringInpActionMapCIter it = mNameMap.find(keyName);
495 
496  if (it == mNameMap.end())
497  return std::string();
498  return getKeyValueString((*it).second);
499 }
500 
501 std::string InputManager::getKeyValueByNameLong(const std::string &restrict
502  keyName) restrict2
503 {
504  const StringInpActionMapCIter it = mNameMap.find(keyName);
505 
506  if (it == mNameMap.end())
507  return std::string();
508  return getKeyStringLong((*it).second);
509 }
510 
512  const InputTypeT type,
513  const int val) restrict2
514 {
515  if (CAST_S32(action) < 0 || action >= InputAction::TOTAL)
516  return;
517 
518  int idx = -1;
519  InputFunction &restrict key = mKey[CAST_SIZE(action)];
520  for (size_t i = 0; i < inputFunctionSize; i ++)
521  {
522  const InputItem &restrict val2 = key.values[i];
523  if (val2.type == InputType::UNKNOWN ||
524  (val2.type == type && val2.value == val))
525  {
526  idx = CAST_S32(i);
527  break;
528  }
529  }
530  if (idx == -1)
531  {
532  for (size_t i = 1; i < inputFunctionSize; i ++)
533  {
534  InputItem &restrict val1 = key.values[i - 1];
535  InputItem &restrict val2 = key.values[i];
536  val1.type = val2.type;
537  val1.value = val2.value;
538  }
539  idx = inputFunctionSize - 1;
540  }
541 
542  key.values[idx] = InputItem(type, val);
543  updateKeyString(key, CAST_SIZE(action));
544 }
545 
546 void InputManager::setNewKey(const SDL_Event &event,
547  const InputTypeT type) restrict2
548 {
549  int val = -1;
550  if (type == InputType::KEYBOARD)
552  else if (type == InputType::JOYSTICK && (joystick != nullptr))
553  val = joystick->getButtonFromEvent(event);
554 
555  if (val != -1)
556  {
557  addActionKey(mNewKeyIndex, type, val);
558  update();
559  }
560 }
561 
563 {
565  for (size_t i = 0; i < inputFunctionSize; i ++)
566  {
567  InputItem &restrict val = key.values[i];
568  val.type = InputType::UNKNOWN;
569  val.value = -1;
570  }
572  update();
573 }
574 
575 #ifndef DYECMD
576 bool InputManager::handleAssignKey(const SDL_Event &restrict event,
577  const InputTypeT type) restrict2
578 {
579  if ((setupWindow != nullptr) && setupWindow->isWindowVisible() &&
580  getNewKeyIndex() > InputAction::NO_VALUE)
581  {
582  setNewKey(event, type);
583  callbackNewKey();
584  setNewKeyIndex(InputAction::NO_VALUE);
585  return true;
586  }
587  return false;
588 }
589 #else // DYECMD
590 
591 bool InputManager::handleAssignKey(const SDL_Event &restrict event A_UNUSED,
592  const InputTypeT type A_UNUSED) restrict2
593 {
594  return false;
595 }
596 #endif // DYECMD
597 
598 bool InputManager::handleEvent(const SDL_Event &restrict event) restrict2
599 {
600  BLOCK_START("InputManager::handleEvent")
601  switch (event.type)
602  {
603  case SDL_KEYDOWN:
604  {
605 #ifdef USE_SDL2
606  if (keyboard.ignoreKey(event))
607  {
608  BLOCK_END("InputManager::handleEvent")
609  return true;
610  }
611 #endif // USE_SDL2
612 
614  updateConditionMask(true);
615  if (handleAssignKey(event, InputType::KEYBOARD))
616  {
617  BLOCK_END("InputManager::handleEvent")
618  return true;
619  }
620 
622  // send straight to gui for certain windows
623 #ifndef DYECMD
624  if ((quitDialog != nullptr) || TextDialog::isActive())
625  {
626  if (guiInput != nullptr)
627  guiInput->pushInput(event);
628  if (gui != nullptr)
629  gui->handleInput();
630  BLOCK_END("InputManager::handleEvent")
631  return true;
632  }
633 #endif // DYECMD
634 
635  break;
636  }
637  case SDL_KEYUP:
638  {
639 #ifdef USE_SDL2
640  if (keyboard.ignoreKey(event))
641  {
642  BLOCK_END("InputManager::handleEvent")
643  return true;
644  }
645 #endif // USE_SDL2
646 
648  updateConditionMask(false);
650  break;
651  }
652  case SDL_JOYBUTTONDOWN:
653  {
654  updateConditionMask(true);
655 // joystick.handleActicateButton(event);
656  if (handleAssignKey(event, InputType::JOYSTICK))
657  {
658  BLOCK_END("InputManager::handleEvent")
659  return true;
660  }
661  break;
662  }
663  case SDL_JOYBUTTONUP:
664  {
665  updateConditionMask(false);
666 // joystick.handleDeActicateButton(event);
667  break;
668  }
669 #ifdef USE_SDL2
670  case SDL_FINGERDOWN:
671  multiTouchManager.handleFingerDown(event);
672  break;
673  case SDL_FINGERUP:
674  multiTouchManager.handleFingerUp(event);
675  break;
676 #else // USE_SDL2
677 #ifdef ANDROID
678  case SDL_ACCELEROMETER:
679  {
680  break;
681  }
682 #endif // ANDROID
683 #endif // USE_SDL2
684 
685  default:
686  break;
687  }
688 
689  if (guiInput != nullptr)
690  guiInput->pushInput(event);
691  if (gui != nullptr)
692  {
693  const bool res = gui->handleInput();
694  if (res && event.type == SDL_KEYDOWN)
695  {
696  BLOCK_END("InputManager::handleEvent")
697  return true;
698  }
699  }
700 
701  switch (event.type)
702  {
703  case SDL_KEYDOWN:
704  if (isActionActive(InputAction::IGNORE_INPUT_1) ||
705  isActionActive(InputAction::IGNORE_INPUT_2))
706  {
707  BLOCK_END("InputManager::handleEvent")
708  return true;
709  }
710  if (triggerAction(keyboard.getActionVector(event)))
711  {
712  BLOCK_END("InputManager::handleEvent")
713  return true;
714  }
715  break;
716 
717 // disabled temporary
718 // case SDL_KEYUP:
719 // if (triggerAction(keyboard.getActionVector(event)))
720 // {
721 // BLOCK_END("InputManager::handleEvent")
722 // return true;
723 // }
724 // break;
725 
726  case SDL_JOYBUTTONDOWN:
727  if ((joystick != nullptr) && joystick->validate())
728  {
729  if (triggerAction(joystick->getActionVector(event)))
730  {
731  BLOCK_END("InputManager::handleEvent")
732  return true;
733  }
734  }
735  break;
736 #ifdef ANDROID
737 #ifndef USE_SDL2
738  case SDL_ACCELEROMETER:
739  {
740  break;
741  }
742 #endif // USE_SDL2
743 #endif // ANDROID
744 
745  default:
746  break;
747  }
748 
749  BLOCK_END("InputManager::handleEvent")
750  return false;
751 }
752 
754 {
755  const int time = tick_time;
756  keyboard.handleRepeat(time);
757  if (joystick != nullptr)
758  joystick->handleRepeat(time);
759 }
760 
762 {
763  mMask = 1;
764  if (keyboard.isEnabled())
765  mMask |= InputCondition::ENABLED;
766 #ifndef DYECMD
767  if (((chatWindow == nullptr) || !chatWindow->isInputFocused()) &&
770  ((tradeWindow == nullptr) || !tradeWindow->isInpupFocused()))
771  {
772  if (gui != nullptr)
773  {
774  FocusHandler *restrict const focus = gui->getFocusHandler();
775  if (focus != nullptr)
776  {
777  if (dynamic_cast<TextField*>(focus->getFocused()) == nullptr)
778  mMask |= InputCondition::NOINPUT;
779  }
780  else
781  {
782  mMask |= InputCondition::NOINPUT;
783  }
784  }
785  else
786  {
787  mMask |= InputCondition::NOINPUT;
788  }
789  }
790 
792  mMask |= InputCondition::NOBUYSELL;
793 
794  if (!PlayerInfo::isVending())
795  mMask |= InputCondition::NOVENDING;
796  if (!PlayerInfo::isInRoom())
797  mMask |= InputCondition::NOROOM;
798 
799  const NpcDialog *restrict const dialog = NpcDialog::getActive();
800  if ((dialog == nullptr) || !dialog->isTextInputFocused())
802  if ((dialog == nullptr) || (dialog->isCloseState() != 0))
803  {
806  mMask |= InputCondition::NOTALKING;
807  }
808  if ((setupWindow == nullptr) || !setupWindow->isWindowVisible())
809  mMask |= InputCondition::NOSETUP;
810 
811  if ((Game::instance() != nullptr) && Game::instance()->getValidSpeed())
813 
814  if (Game::instance() != nullptr)
815  mMask |= InputCondition::INGAME;
816 
817  if (localPlayer != nullptr)
818  {
819  if (localPlayer->getFollow().empty())
820  mMask |= InputCondition::NOFOLLOW;
821 
822  if (!localPlayer->isTrickDead())
823  mMask |= InputCondition::NOBLOCK;
824 
825  if (localPlayer->isAlive())
826  mMask |= InputCondition::ALIVE;
827  }
828  else
829  {
830  mMask |= InputCondition::NOFOLLOW;
831  mMask |= InputCondition::NOBLOCK;
832  }
833 #endif // DYECMD
834 
835  if (!settings.awayMode)
836  mMask |= InputCondition::NOAWAY;
837 
838  if (gui != nullptr && gui->getFocusHandler()->getModalFocused() == nullptr)
839  mMask |= InputCondition::NOMODAL;
840 
842  mMask |= InputCondition::EMODS;
843 
844  if (!isActionActive0(InputAction::STOP_ATTACK)
845  && !isActionActive0(InputAction::UNTARGET))
846  {
847  mMask |= InputCondition::NOTARGET;
848  }
849  // enable it temporary
850  mMask |= InputCondition::KEY_DOWN;
851 // if (pressed == true)
852 // mMask |= InputCondition::KEY_DOWN;
853 // else
854 // mMask |= InputCondition::KEY_UP;
855 }
856 
857 bool InputManager::checkKey(const InputActionData *restrict const key) const
858  restrict2
859 {
860  // logger->log("checkKey mask=%d, condition=%d", mMask, key->condition);
861  if ((key == nullptr) || (key->condition & mMask) != key->condition)
862  return false;
863 
864  return key->modKeyIndex == InputAction::NO_VALUE
865  || isActionActive0(key->modKeyIndex);
866 }
867 
869  const InputActionT keyNum) restrict2
870 {
871  // no validation to keyNum because it validated in caller
872 
873  if (checkKey(key))
874  {
875  InputEvent evt(keyNum, mMask);
877  CAST_SIZE(keyNum)].action);
878  if ((func != nullptr) && func(evt))
879  return true;
880  }
881  return false;
882 }
883 
885 {
886  if (keyNum < InputAction::MOVE_UP || keyNum >= InputAction::TOTAL)
887  return;
888 
890  keyNum)].action);
891  if (func != nullptr)
892  {
893  InputEvent evt(keyNum, mMask);
894  func(evt);
895  }
896 }
897 
898 bool InputManager::executeChatCommand(const std::string &restrict cmd,
899  const std::string &restrict args,
900  ChatTab *restrict const tab) restrict2
901 {
902  const StringIntMapCIter it = mChatMap.find(cmd);
903  if (it != mChatMap.end())
904  {
905  ActionFuncPtr func = *(inputActionData[(*it).second].action);
906  if (func != nullptr)
907  {
908  InputEvent evt(args, tab, mMask);
909  func(evt);
910  return true;
911  }
912  }
913  else
914  {
915  reportAlways("Unknown chat command: /%s %s",
916  cmd.c_str(),
917  args.c_str())
918  }
919  return false;
920 }
921 
923  const std::string &restrict args,
924  ChatTab *restrict const tab)
925  restrict2
926 {
927  const StringIntMapCIter it = mChatMap.find(cmd);
928  if (it != mChatMap.end())
929  {
930  const InputActionData &restrict data = inputActionData[(*it).second];
931  if (data.isProtected == Protected_true)
932  return false;
933  ActionFuncPtr func = *(data.action);
934  if (func != nullptr)
935  {
936  InputEvent evt(args, tab, mMask);
937  func(evt);
938  return true;
939  }
940  }
941  return false;
942 }
943 
945  const std::string &restrict args,
946  ChatTab *restrict const tab) restrict2
947 {
948  if (CAST_S32(keyNum) < 0 || keyNum >= InputAction::TOTAL)
949  return false;
951  keyNum)].action);
952  if (func != nullptr)
953  {
954  InputEvent evt(args, tab, mMask);
955  func(evt);
956  return true;
957  }
958  return false;
959 }
960 
962  KeyToIdMap &restrict idMap,
963  KeyTimeMap &restrict keyTimeMap,
964  const InputTypeT type) const restrict2
965 {
966  actionMap.clear();
967  keyTimeMap.clear();
968 
969  for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i ++)
970  {
971  const InputFunction &restrict key = mKey[i];
973  if (kd.action != nullptr)
974  {
975  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
976  {
977  const InputItem &restrict ki = key.values[i2];
978  if (ki.type == type && ki.value != -1)
979  {
980  actionMap[ki.value].push_back(
981  static_cast<InputActionT>(i));
982  }
983  }
984  }
985  if (kd.configField != nullptr && (kd.grp & Input::GRP_GUICHAN) != 0)
986  {
987  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
988  {
989  const InputItem &restrict ki = key.values[i2];
990  if (ki.type == type && ki.value != -1)
991  idMap[ki.value] = static_cast<InputActionT>(i);
992  }
993  }
994  if (kd.configField != nullptr && (kd.grp & Input::GRP_REPEAT) != 0)
995  {
996  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
997  {
998  const InputItem &restrict ki = key.values[i2];
999  if (ki.type == type && ki.value != -1)
1000  keyTimeMap[ki.value] = 0;
1001  }
1002  }
1003  }
1004 
1006  FOR_EACH (KeyToActionMapIter, it, actionMap)
1007  {
1008  KeysVector *const keys = &it->second;
1009  if (keys->size() > 1)
1010  std::sort(keys->begin(), keys->end(), inputActionDataSorter);
1011  }
1012 }
1013 
1015  restrict2
1016 {
1017  if (ptrs == nullptr)
1018  return false;
1019 
1020 // logger->log("ptrs: %d", (int)ptrs.size());
1021 
1022  FOR_EACHP (KeysVectorCIter, it, ptrs)
1023  {
1024  const InputActionT keyNum = *it;
1025  if (CAST_S32(keyNum) < 0 || keyNum >= InputAction::TOTAL)
1026  continue;
1027 
1028  if (invokeKey(&inputActionData[CAST_SIZE(keyNum)], keyNum))
1029  return true;
1030  }
1031  return false;
1032 }
1033 
1035  const int grp,
1036  const InputTypeT type) const restrict2
1037 {
1038  for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i++)
1039  {
1040  const InputFunction &restrict key = mKey[i];
1041  const InputActionData &restrict kd = inputActionData[i];
1042  for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
1043  {
1044  const InputItem &restrict vali2 = key.values[i2];
1045  if (value == vali2.value &&
1046  (grp & kd.grp) != 0 && vali2.type == type)
1047  {
1048  return static_cast<InputActionT>(i);
1049  }
1050  }
1051  }
1052  return InputAction::NO_VALUE;
1053 }
1054 
1056  const restrict2
1057 {
1058  // for now support only keyboard events
1059  if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
1060  {
1061  const InputActionT idx = keyboard.getActionId(event);
1062  if (CAST_S32(idx) >= 0 &&
1063  checkKey(&inputActionData[CAST_SIZE(idx)]))
1064  {
1065  return idx;
1066  }
1067  }
1068  return InputAction::NO_VALUE;
1069 }
1070 
1072 {
1073  for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
1074  {
1075  const std::string cf = inputActionData[i].configField;
1076  if (field == cf)
1077  return static_cast<InputActionT>(i);
1078  }
1079  return InputAction::NO_VALUE;
1080 }
1081 
1082 void InputManager::addChatCommands(std::list<std::string> &restrict arr)
1083 {
1084  const int sz = CAST_S32(InputAction::TOTAL);
1085  for (int i = 0; i < sz; i++)
1086  {
1087  const InputActionData &restrict ad = inputActionData[i];
1088  std::string cmd = ad.chatCommand;
1089  if (!cmd.empty())
1090  {
1091  StringVect tokens;
1092  splitToStringVector(tokens, cmd, '|');
1093  FOR_EACH (StringVectCIter, it, tokens)
1094  {
1095  cmd = std::string("/").append(*it);
1096  if (ad.useArgs == UseArgs_true)
1097  cmd.append(" ");
1098  arr.push_back(cmd);
1099  }
1100  }
1101  }
1102 }
bool(* ActionFuncPtr)(InputEvent &event)
Definition: actionfuncptr.h:27
#define CAST_S32
Definition: cast.h:30
#define CAST_SIZE
Definition: cast.h:34
ChatWindow * chatWindow
Definition: chatwindow.cpp:94
#define reportAlways(...)
Definition: checkutils.h:253
bool isTrickDead() const
Definition: actorsprite.h:184
bool isAlive() const
Definition: being.h:488
static bool isActive()
Definition: buydialog.h:164
bool isInputFocused() const
Definition: chatwindow.cpp:579
std::string getValue(const std::string &key, const std::string &deflt) const
void setValue(const std::string &key, const std::string &value)
Widget * getModalFocused() const
static Game * instance()
Definition: game.h:82
FocusHandler * getFocusHandler() const
Definition: gui.h:154
bool handleInput()
Definition: gui.cpp:388
const InputActionData * keys
static void addChatCommands(std::list< std::string > &arr)
void executeAction(const InputActionT keyNum)
void updateConditionMask(const bool pressed)
static void update()
static InputActionT getActionByConfigField(const std::string &field)
void updateKeyString(const InputFunction &ki, const size_t actionIdx)
StringInpActionMap mNameMap
Definition: inputmanager.h:180
void updateKeyActionMap(KeyToActionMap &actionMap, KeyToIdMap &idMap, KeyTimeMap &keyTimeMap, const InputTypeT type) const
bool checkKey(const InputActionData *const key) const
InputActionT getKeyIndex(const int value, const int grp, const InputTypeT type) const
std::string mKeyStr[static_cast< size_t >(InputAction::TOTAL)]
Definition: inputmanager.h:184
bool executeRemoteChatCommand(const std::string &cmd, const std::string &args, ChatTab *const tab)
bool handleAssignKey(const SDL_Event &event, const InputTypeT type)
void store() const
void unassignKey()
StringIntMap mChatMap
Definition: inputmanager.h:181
InputFunction mKey[static_cast< size_t >(InputAction::TOTAL)]
Definition: inputmanager.h:183
InputFunction & getKey(InputActionT index) A_CONST
bool handleEvent(const SDL_Event &event)
InputActionT getActionByKey(const SDL_Event &event) const
Setup_Input * mSetupInput
Definition: inputmanager.h:174
void resetKey(const InputActionT i)
void setNewKey(const SDL_Event &event, const InputTypeT type)
std::string getKeyValueByNameLong(const std::string &keyName)
static void handleRepeat()
void callbackNewKey()
std::string getKeyValueByName(const std::string &keyName)
std::string getKeyStringLong(const InputActionT index) const
bool hasConflicts(InputActionT &key1, InputActionT &key2) const
static bool isActionActive0(const InputActionT index)
bool triggerAction(const KeysVector *const ptrs)
InputActionT mNewKeyIndex
Definition: inputmanager.h:176
bool invokeKey(const InputActionData *const key, const InputActionT keyNum)
bool executeChatCommand(const std::string &cmd, const std::string &args, ChatTab *const tab)
bool isActionActive(const InputActionT index) const
void makeDefault(const InputActionT i)
void addActionKey(const InputActionT action, const InputTypeT type, const int val)
std::string getKeyValueString(const InputActionT index) const
static bool isAnyInputFocused()
static bool isStorageActive()
KeysVector * getActionVector(const SDL_Event &event)
Definition: joystick.cpp:365
void handleRepeat(const int time)
Definition: joystick.cpp:424
void update()
Definition: joystick.cpp:359
bool isActionActive(const InputActionT index) const
Definition: joystick.cpp:394
int getButtonFromEvent(const SDL_Event &event) const
Definition: joystick.cpp:387
bool validate() const
Definition: joystick.cpp:415
InputActionT getActionId(const SDL_Event &event)
void refreshActiveKeys()
static std::string getKeyShortString(const std::string &key)
void handleActivateKey(const SDL_Event &event)
bool isEnabled() const
void handleRepeat(const int time)
KeysVector * getActionVector(const SDL_Event &event)
bool isActionActive(const InputActionT index) const
static std::string getKeyName(const int key)
static int getKeyValueFromEvent(const SDL_Event &event)
void handleDeActicateKey(const SDL_Event &event)
const std::string & getFollow() const
Definition: localplayer.h:336
static bool isAnyInputFocused()
Definition: npcdialog.cpp:768
static NpcDialog * getActive()
Definition: npcdialog.cpp:852
void action(const ActionEvent &event)
Definition: quitdialog.cpp:150
void pushInput(const SDL_Event &event)
Definition: sdlinput.cpp:136
static bool isActive()
Definition: selldialog.h:112
bool awayMode
Definition: settings.h:158
bool disableGameModifiers
Definition: settings.h:157
void newKeyCallback(const InputActionT index)
static bool isActive()
Definition: textdialog.h:72
bool isActionActive(const InputActionT index) const
bool isInpupFocused() const
bool isWindowVisible() const
Definition: window.h:484
Configuration config
#define FOR_EACHP(type, iter, array)
Definition: foreach.h:31
#define FOR_EACH(type, iter, array)
Definition: foreach.h:25
#define _(s)
Definition: gettext.h:35
Gui * gui
Definition: gui.cpp:111
InputAction ::T InputActionT
Definition: inputaction.h:717
static const InputActionData inputActionData[static_cast< size_t >(InputAction::TOTAL)]
std::map< int, KeysVector > KeyToActionMap
Definition: inputevent.h:40
KeysVector::const_iterator KeysVectorCIter
Definition: inputevent.h:38
KeyToActionMap::iterator KeyToActionMapIter
Definition: inputevent.h:41
std::map< int, InputActionT > KeyToIdMap
Definition: inputevent.h:43
std::vector< InputActionT > KeysVector
Definition: inputevent.h:34
std::map< int, int > KeyTimeMap
Definition: inputevent.h:46
const size_t inputFunctionSize
Definition: inputfunction.h:29
InputManager inputManager
QuitDialog * quitDialog
Definition: game.cpp:158
StringInpActionMap::const_iterator StringInpActionMapCIter
Definition: inputmanager.h:44
InputType ::T InputTypeT
Definition: inputtype.h:42
Joystick * joystick
Definition: joystick.cpp:43
KeyboardConfig keyboard
#define restrict
Definition: localconsts.h:165
#define restrict2
Definition: localconsts.h:166
#define nullptr
Definition: localconsts.h:45
#define A_UNUSED
Definition: localconsts.h:160
LocalPlayer * localPlayer
uint32_t data
volatile int tick_time
Definition: timer.cpp:53
MultiTouchManager multiTouchManager
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
@ KEYBOARD
Definition: inputtype.h:38
@ JOYSTICK
Definition: inputtype.h:40
@ GRP_GUICHAN
Definition: inputgroup.h:39
@ GRP_REPEAT
Definition: inputgroup.h:40
bool isInRoom()
Definition: playerinfo.cpp:643
bool isVending()
Definition: playerinfo.cpp:663
void update()
Definition: useragent.cpp:32
InputActionSortFunctor inputActionDataSorter
#define BLOCK_END(name)
Definition: perfomance.h:80
#define BLOCK_START(name)
Definition: perfomance.h:79
const bool Protected_true
Definition: protected.h:30
SDLInput * guiInput
Definition: sdlinput.cpp:101
Settings settings
Definition: settings.cpp:32
SetupWindow * setupWindow
Definition: setupwindow.cpp:64
#define STD_MOVE(var)
Definition: stdmove.h:28
StringIntMap::const_iterator StringIntMapCIter
Definition: stringmap.h:30
std::string strprintf(const char *const format,...)
void splitToStringVector(StringVect &tokens, const std::string &text, const char separator)
StringVect::const_iterator StringVectCIter
Definition: stringvector.h:31
std::vector< std::string > StringVect
Definition: stringvector.h:29
const ActionFuncPtr action
const char *const configField
const std::string chatCommand
InputItem values[inputFunctionSize]
Definition: inputfunction.h:35
int value
Definition: inputitem.h:45
InputTypeT type
Definition: inputitem.h:44
TouchManager touchManager
TradeWindow * tradeWindow
Definition: tradewindow.cpp:65
const bool UseArgs_true
Definition: useargs.h:30