3
* Copyright (C) 2012-2013 The ManaPlus Developers
5
* This file is part of The ManaPlus Client.
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program. If not, see <http://www.gnu.org/licenses/>.
21
#include "inputmanager.h"
24
#include "configuration.h"
27
#include "keyboardconfig.h"
28
#include "keyboarddata.h"
29
#include "localplayer.h"
30
#include "touchmanager.h"
32
#include "gui/chatwindow.h"
34
#include "gui/inventorywindow.h"
35
#include "gui/npcdialog.h"
36
#include "gui/npcpostdialog.h"
37
#include "gui/sdlinput.h"
38
#include "gui/setup.h"
39
#include "gui/setup_input.h"
40
#include "gui/textdialog.h"
41
#include "gui/tradewindow.h"
43
#include <guichan/exception.hpp>
44
#include <guichan/focushandler.hpp>
50
InputManager inputManager;
52
extern QuitDialog *quitDialog;
54
static class KeyFunctor final
57
bool operator() (const int key1, const int key2) const
59
return keys[key1].priority >= keys[key2].priority;
66
InputManager::InputManager() :
68
mNewKeyIndex(Input::KEY_NO_VALUE),
74
void InputManager::init()
76
for (unsigned int i = 0; i < Input::KEY_TOTAL; i++)
78
KeyFunction &kf = mKey[i];
79
for (unsigned int f = 0; f < KeyFunctionSize; f ++)
81
KeyItem &ki = kf.values[f];
82
ki.type = INPUT_UNKNOWN;
87
mNewKeyIndex = Input::KEY_NO_VALUE;
94
void InputManager::update() const
101
void InputManager::retrieve()
103
for (int i = 0; i < Input::KEY_TOTAL; i++)
106
const std::string cf = std::string("sdl2") + keyData[i].configField;
108
const std::string cf = keyData[i].configField;
113
KeyFunction &kf = mKey[i];
114
const std::string keyStr = config.getValue(cf, "");
115
const int keyStrSize = keyStr.size();
120
splitToStringVector(keys, keyStr, ',');
122
for (StringVectCIter it = keys.begin(), it_end = keys.end();
123
it != it_end && i2 < KeyFunctionSize; ++ it)
125
std::string keyStr2 = *it;
128
int type = INPUT_KEYBOARD;
129
if ((keyStr2[0] < '0' || keyStr2[0] > '9')
130
&& keyStr2[0] != '-')
138
type = INPUT_JOYSTICK;
143
keyStr2 = keyStr2.substr(1);
145
const int key = atoi(keyStr2.c_str());
146
if (key >= -255 && key < SDLK_LAST)
148
kf.values[i2] = KeyItem(type, key);
156
void InputManager::store() const
158
for (int i = 0; i < Input::KEY_TOTAL; i++)
161
const std::string cf = std::string("sdl2") + keyData[i].configField;
163
const std::string cf = keyData[i].configField;
168
const KeyFunction &kf = mKey[i];
170
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
172
const KeyItem &key = kf.values[i2];
173
if (key.type != INPUT_UNKNOWN)
175
std::string tmp = "k";
191
keyStr.append(tmp).append(toString(key.value));
195
keyStr.append(strprintf(",%s%d",
196
tmp.c_str(), key.value));
204
config.setValue(cf, keyStr);
209
void InputManager::resetKeys()
211
for (int i = 0; i < Input::KEY_TOTAL; i++)
213
KeyFunction &key = mKey[i];
214
for (size_t i2 = 1; i2 < KeyFunctionSize; i2 ++)
216
KeyItem &ki2 = key.values[i2];
217
ki2.type = INPUT_UNKNOWN;
220
const KeyData &kd = keyData[i];
221
KeyItem &val0 = key.values[0];
222
val0.type = kd.defaultType1;
223
KeyItem &val1 = key.values[1];
224
val1.type = kd.defaultType2;
226
if (kd.defaultType1 == INPUT_KEYBOARD)
227
val0.value = SDL_GetScancodeFromKey(kd.defaultValue1);
229
val0.value = kd.defaultValue1;
230
if (kd.defaultType2 == INPUT_KEYBOARD)
231
val1.value = SDL_GetScancodeFromKey(kd.defaultValue2);
233
val1.value = kd.defaultValue2;
235
val0.value = kd.defaultValue1;
236
val1.value = kd.defaultValue2;
241
void InputManager::makeDefault(const int i)
243
if (i >= 0 && i < Input::KEY_TOTAL)
245
KeyFunction &key = mKey[i];
246
for (size_t i2 = 1; i2 < KeyFunctionSize; i2 ++)
248
KeyItem &ki2 = key.values[i2];
249
ki2.type = INPUT_UNKNOWN;
252
const KeyData &kd = keyData[i];
253
KeyItem &val0 = key.values[0];
254
val0.type = kd.defaultType1;
255
KeyItem &val1 = key.values[1];
256
val1.type = kd.defaultType2;
259
if (kd.defaultType1 == INPUT_KEYBOARD)
260
val0.value = SDL_GetScancodeFromKey(kd.defaultValue1);
262
val0.value = kd.defaultValue1;
263
if (kd.defaultType2 == INPUT_KEYBOARD)
264
val1.value = SDL_GetScancodeFromKey(kd.defaultValue2);
266
val1.value = kd.defaultValue2;
268
val0.value = kd.defaultValue1;
269
val1.value = kd.defaultValue2;
276
bool InputManager::hasConflicts(int &key1, int &key2) const
279
* No need to parse the square matrix: only check one triangle
280
* that's enough to detect conflicts
282
for (int i = 0; i < Input::KEY_TOTAL; i++)
284
const KeyData &kdi = keyData[i];
285
if (!*kdi.configField)
288
const KeyFunction &ki = mKey[i];
289
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
291
const KeyItem &vali2 = ki.values[i2];
292
if (vali2.value == Input::KEY_NO_VALUE)
296
for (j = i, j++; j < Input::KEY_TOTAL; j++)
298
if ((kdi.grp & keyData[j].grp) == 0 || !*kdi.configField)
301
for (size_t j2 = 0; j2 < KeyFunctionSize; j2 ++)
303
const KeyItem &valj2 = mKey[j].values[j2];
304
// Allow for item shortcut and emote keys to overlap
305
// as well as emote and ignore keys, but no other keys
306
if (valj2.type != INPUT_UNKNOWN
307
&& vali2.value == valj2.value
308
&& vali2.type == valj2.type)
310
key1 = static_cast<int>(i);
311
key2 = static_cast<int>(j);
321
void InputManager::callbackNewKey()
323
mSetupInput->newKeyCallback(mNewKeyIndex);
326
bool InputManager::isActionActive(const int index)
328
if (keyboard.isActionActive(index))
330
if (joystick && joystick->isActionActive(index))
332
return touchManager.isActionActive(index);
335
KeyFunction &InputManager::getKey(int index)
337
if (index < 0 || index >= Input::KEY_TOTAL)
342
std::string InputManager::getKeyStringLong(const int index) const
345
const KeyFunction &ki = mKey[index];
347
for (size_t i = 0; i < KeyFunctionSize; i ++)
349
const KeyItem &key = ki.values[i];
351
if (key.type == INPUT_KEYBOARD)
355
str = keyboard.getKeyName(key.value);
357
else if (key.value < -1)
359
// TRANSLATORS: long key name. must be short.
360
str = strprintf(_("key_%d"), -key.value);
363
else if (key.type == INPUT_JOYSTICK)
365
// TRANSLATORS: long joystick button name. must be short.
366
str = strprintf(_("JButton%d"), key.value + 1);
373
keyStr.append(" ").append(str);
379
// TRANSLATORS: unknown long key type
380
return _("unknown key");
385
std::string InputManager::getKeyValueString(const int index) const
388
const KeyFunction &ki = mKey[index];
390
for (size_t i = 0; i < KeyFunctionSize; i ++)
392
const KeyItem &key = ki.values[i];
394
if (key.type == INPUT_KEYBOARD)
398
str = keyboard.getKeyShortString(
399
keyboard.getKeyName(key.value));
401
else if (key.value < -1)
403
// TRANSLATORS: short key name. must be very short.
404
str = strprintf(_("key_%d"), -key.value);
407
else if (key.type == INPUT_JOYSTICK)
409
// TRANSLATORS: short joystick button name. muse be very short
410
str = strprintf(_("JB%d"), key.value + 1);
417
keyStr.append(" ").append(str);
423
// TRANSLATORS: unknown short key type. must be short
429
std::string InputManager::getKeyValueByName(const std::string &keyName)
431
const std::map<std::string, int>::const_iterator
432
it = mNameMap.find(keyName);
434
if (it == mNameMap.end())
435
return std::string();
436
return getKeyValueString((*it).second);
439
void InputManager::addActionKey(const int action, const int type,
442
if (action < 0 || action >= Input::KEY_TOTAL)
446
KeyFunction &key = mKey[action];
447
for (size_t i = 0; i < KeyFunctionSize; i ++)
449
const KeyItem &val2 = key.values[i];
450
if (val2.type == INPUT_UNKNOWN || (val2.type == type
451
&& val2.value == val))
453
idx = static_cast<int>(i);
459
for (size_t i = 1; i < KeyFunctionSize; i ++)
461
KeyItem &val1 = key.values[i - 1];
462
KeyItem &val2 = key.values[i];
463
val1.type = val2.type;
464
val1.value = val2.value;
466
idx = KeyFunctionSize - 1;
469
key.values[idx] = KeyItem(type, val);
472
void InputManager::setNewKey(const SDL_Event &event, const int type)
475
if (type == INPUT_KEYBOARD)
476
val = keyboard.getKeyValueFromEvent(event);
477
else if (type == INPUT_JOYSTICK && joystick)
478
val = joystick->getButtonFromEvent(event);
482
addActionKey(mNewKeyIndex, type, val);
487
void InputManager::unassignKey()
489
KeyFunction &key = mKey[mNewKeyIndex];
490
for (size_t i = 0; i < KeyFunctionSize; i ++)
492
KeyItem &val = key.values[i];
493
val.type = INPUT_UNKNOWN;
499
bool InputManager::handleAssignKey(const SDL_Event &event, const int type)
501
if (setupWindow && setupWindow->isWindowVisible() &&
502
getNewKeyIndex() > Input::KEY_NO_VALUE)
504
setNewKey(event, type);
506
setNewKeyIndex(Input::KEY_NO_VALUE);
512
bool InputManager::handleEvent(const SDL_Event &event)
518
updateConditionMask();
519
if (handleAssignKey(event, INPUT_KEYBOARD))
522
keyboard.handleActicateKey(event);
523
// send straight to gui for certain windows
524
if (quitDialog || TextDialog::isActive() ||
525
NpcPostDialog::isActive())
530
guiInput->pushInput(event);
534
catch (const gcn::Exception &e)
536
const char *const err = e.getMessage().c_str();
537
logger->log("Warning: guichan input exception: %s", err);
545
updateConditionMask();
546
keyboard.handleDeActicateKey(event);
549
case SDL_JOYBUTTONDOWN:
551
updateConditionMask();
552
// joystick.handleActicateButton(event);
553
if (handleAssignKey(event, INPUT_JOYSTICK))
557
case SDL_JOYBUTTONUP:
559
updateConditionMask();
560
// joystick.handleDeActicateButton(event);
564
case SDL_ACCELEROMETER:
576
guiInput->pushInput(event);
578
catch (const gcn::Exception &e)
580
const char *const err = e.getMessage().c_str();
581
logger->log("Warning: guichan input exception: %s", err);
585
const bool res = gui->handleInput();
586
if (res && event.type == SDL_KEYDOWN)
593
if (triggerAction(keyboard.getActionVector(event)))
597
case SDL_JOYBUTTONDOWN:
598
if (joystick && joystick->validate())
600
if (triggerAction(joystick->getActionVector(event)))
605
case SDL_ACCELEROMETER:
617
void InputManager::handleRepeat() const
619
const int time = tick_time;
620
keyboard.handleRepeat(time);
622
joystick->handleRepeat(time);
625
void InputManager::updateConditionMask()
628
if (keyboard.isEnabled())
629
mMask |= COND_ENABLED;
630
if ((!chatWindow || !chatWindow->isInputFocused()) &&
631
!NpcDialog::isAnyInputFocused() &&
632
!InventoryWindow::isAnyInputFocused() &&
633
(!tradeWindow || !tradeWindow->isInpupFocused()))
635
mMask |= COND_NOINPUT;
638
if (!player_node || !player_node->getAway())
639
mMask |= COND_NOAWAY;
641
if (!setupWindow || !setupWindow->isWindowVisible())
642
mMask |= COND_NOSETUP;
644
if (Game::instance() && Game::instance()->getValidSpeed())
645
mMask |= COND_VALIDSPEED;
647
if (gui && !gui->getFocusHandler()->getModalFocused())
648
mMask |= COND_NOMODAL;
650
const NpcDialog *const dialog = NpcDialog::getActive();
651
if (!dialog || !dialog->isTextInputFocused())
652
mMask |= COND_NONPCINPUT;
654
if (!player_node || !player_node->getDisableGameModifiers())
657
if (!isActionActive(Input::KEY_STOP_ATTACK)
658
&& !isActionActive(Input::KEY_UNTARGET))
660
mMask |= COND_NOTARGET;
662
if (Game::instance())
663
mMask |= COND_INGAME;
665
if (!player_node || player_node->getFollow().empty())
666
mMask |= COND_NOFOLLOW;
669
bool InputManager::checkKey(const KeyData *const key) const
671
// logger->log("mask=%d, condition=%d", mMask, key->condition);
672
if (!key || (key->condition & mMask) != key->condition)
675
return (key->modKeyIndex == Input::KEY_NO_VALUE
676
|| isActionActive(key->modKeyIndex));
679
bool InputManager::invokeKey(const KeyData *const key, const int keyNum)
681
// no validation to keyNum because it validated in caller
685
InputEvent evt(keyNum, mMask);
686
ActionFuncPtr func = *(keyData[keyNum].action);
687
if (func && func(evt))
693
void InputManager::executeAction(const int keyNum)
695
if (keyNum < 0 || keyNum >= Input::KEY_TOTAL)
698
InputEvent evt(keyNum, mMask);
699
ActionFuncPtr func = *(keyData[keyNum].action);
704
void InputManager::updateKeyActionMap(KeyToActionMap &actionMap,
706
KeyTimeMap &keyTimeMap,
707
const int type) const
712
for (size_t i = 0; i < Input::KEY_TOTAL; i ++)
714
const KeyFunction &key = mKey[i];
715
const KeyData &kd = keyData[i];
718
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
720
const KeyItem &ki = key.values[i2];
721
if (ki.type == type && ki.value != -1)
722
actionMap[ki.value].push_back(static_cast<int>(i));
725
if (kd.configField && (kd.grp & Input::GRP_GUICHAN))
727
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
729
const KeyItem &ki = key.values[i2];
730
if (ki.type == type && ki.value != -1)
731
idMap[ki.value] = static_cast<int>(i);
734
if (kd.configField && (kd.grp & Input::GRP_REPEAT))
736
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
738
const KeyItem &ki = key.values[i2];
739
if (ki.type == type && ki.value != -1)
740
keyTimeMap[ki.value] = 0;
745
keyDataSorter.keys = &keyData[0];
746
FOR_EACH (KeyToActionMapIter, it, actionMap)
748
KeysVector *const keys = &it->second;
749
if (keys && keys->size() > 1)
750
std::sort(keys->begin(), keys->end(), keyDataSorter);
754
bool InputManager::triggerAction(const KeysVector *const ptrs)
759
// logger->log("ptrs: %d", (int)ptrs.size());
761
FOR_EACHP (KeysVectorCIter, it, ptrs)
763
const int keyNum = *it;
764
if (keyNum < 0 || keyNum >= Input::KEY_TOTAL)
767
if (invokeKey(&keyData[keyNum], keyNum))
773
int InputManager::getKeyIndex(const int value, const int grp,
774
const int type) const
776
for (size_t i = 0; i < Input::KEY_TOTAL; i++)
778
const KeyFunction &key = mKey[i];
779
const KeyData &kd = keyData[i];
780
for (size_t i2 = 0; i2 < KeyFunctionSize; i2 ++)
782
const KeyItem &vali2 = key.values[i2];
783
if (value == vali2.value && (grp & kd.grp) != 0
784
&& vali2.type == type)
786
return static_cast<int>(i);
790
return Input::KEY_NO_VALUE;
793
int InputManager::getActionByKey(const SDL_Event &event) const
795
// for now support only keyboard events
796
if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
798
const int idx = keyboard.getActionId(event);
799
if (idx >= 0 && checkKey(&keyData[idx]))
802
return Input::KEY_NO_VALUE;