GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/input/inputmanager.cpp Lines: 56 430 13.0 %
Date: 2017-11-29 Branches: 50 450 11.1 %

Line Branch Exec Source
1
/*
2
 *  The ManaPlus Client
3
 *  Copyright (C) 2012-2017  The ManaPlus Developers
4
 *
5
 *  This file is part of The ManaPlus Client.
6
 *
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
10
 *  any later version.
11
 *
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.
16
 *
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/>.
19
 */
20
21
#include "input/inputmanager.h"
22
23
#include "configuration.h"
24
#include "game.h"
25
#include "settings.h"
26
27
#include "being/localplayer.h"
28
#include "being/playerinfo.h"
29
30
#include "input/inputactionmap.h"
31
#include "input/inputactionsortfunctor.h"
32
#include "input/joystick.h"
33
#include "input/keyboardconfig.h"
34
#ifdef USE_SDL2
35
#include "input/touch/multitouchmanager.h"
36
#endif  // USE_SDL2
37
38
#include "input/touch/touchmanager.h"
39
40
#include "gui/gui.h"
41
#include "gui/sdlinput.h"
42
43
#include "gui/widgets/selldialog.h"
44
#include "gui/widgets/textfield.h"
45
46
#include "gui/widgets/tabs/setup_input.h"
47
48
#include "gui/windows/buydialog.h"
49
#include "gui/windows/chatwindow.h"
50
#include "gui/windows/inventorywindow.h"
51
#include "gui/windows/npcdialog.h"
52
#include "gui/windows/setupwindow.h"
53
#include "gui/windows/textdialog.h"
54
#include "gui/windows/tradewindow.h"
55
56
#include "utils/checkutils.h"
57
#include "utils/foreach.h"
58
#include "utils/gettext.h"
59
#include "utils/stdmove.h"
60
#include "utils/timer.h"
61
62
#include "gui/focushandler.h"
63
64
#include <algorithm>
65
66
#include "debug.h"
67
68
2
InputManager inputManager;
69
70
class QuitDialog;
71
72
extern QuitDialog *quitDialog;
73
74
namespace
75
{
76
    InputActionSortFunctor inputActionDataSorter;
77
}  // namespace
78
79
2
InputManager::InputManager() :
80
    mSetupInput(nullptr),
81
    mNewKeyIndex(InputAction::NO_VALUE),
82
    mMask(1),
83
    mNameMap(),
84
    mChatMap(),
85

2678
    mKey()
86
{
87
2
}
88
89
void InputManager::init() restrict2
90
{
91
    for (size_t i = 0;
92
         i < CAST_SIZE(InputAction::TOTAL);
93
         i ++)
94
    {
95
        InputFunction &kf = mKey[i];
96
        mKeyStr[i].clear();
97
        for (size_t f = 0; f < inputFunctionSize; f ++)
98
        {
99
            InputItem &ki = kf.values[f];
100
            ki.type = InputType::UNKNOWN;
101
            ki.value = -1;
102
        }
103
    }
104
105
    mNewKeyIndex = InputAction::NO_VALUE;
106
107
    resetKeys();
108
    retrieve();
109
    update();
110
}
111
112
void InputManager::update()
113
{
114
    keyboard.update();
115
    if (joystick != nullptr)
116
        joystick->update();
117
}
118
119
void InputManager::retrieve() restrict2
120
{
121
    for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
122
    {
123
        const std::string &restrict cmd = inputActionData[i].chatCommand;
124
        if (!cmd.empty())
125
        {
126
            StringVect tokens;
127
            splitToStringVector(tokens, cmd, '|');
128
            FOR_EACH (StringVectCIter, it, tokens)
129
                mChatMap[*it] = i;
130
        }
131
#ifdef USE_SDL2
132
        const std::string cf = std::string("sdl2")
133
            + inputActionData[i].configField;
134
#else  // USE_SDL2
135
136
        const std::string cf = inputActionData[i].configField;
137
#endif  // USE_SDL2
138
139
        InputFunction &restrict kf = mKey[i];
140
        if (!cf.empty())
141
        {
142
            mNameMap[cf] = static_cast<InputActionT>(i);
143
            const std::string keyStr = config.getValue(cf, "");
144
            const size_t keyStrSize = keyStr.size();
145
            if (keyStr.empty())
146
            {
147
                updateKeyString(kf, i);
148
                continue;
149
            }
150
151
            StringVect keys;
152
            splitToStringVector(keys, keyStr, ',');
153
            unsigned int i2 = 0;
154
            for (StringVectCIter it = keys.begin(), it_end = keys.end();
155
                 it != it_end && i2 < inputFunctionSize; ++ it)
156
            {
157
                std::string keyStr2 = *it;
158
                if (keyStrSize < 2)
159
                    continue;
160
                InputTypeT type = InputType::KEYBOARD;
161
                if ((keyStr2[0] < '0' || keyStr2[0] > '9')
162
                    && keyStr2[0] != '-')
163
                {
164
                    switch (keyStr2[0])
165
                    {
166
                        case 'm':
167
                            type = InputType::MOUSE;
168
                            break;
169
                        case 'j':
170
                            type = InputType::JOYSTICK;
171
                            break;
172
                        default:
173
                            break;
174
                    }
175
                    keyStr2 = keyStr2.substr(1);
176
                }
177
                const int key = atoi(keyStr2.c_str());
178
                if (key >= -255 && key < SDLK_LAST)
179
                {
180
                    kf.values[i2] = InputItem(type, key);
181
                    i2 ++;
182
                }
183
            }
184
            for (; i2 < inputFunctionSize; i2 ++)
185
                kf.values[i2] = InputItem();
186
        }
187
        updateKeyString(kf, i);
188
    }
189
}
190
191
void InputManager::store() const restrict2
192
{
193
    for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
194
    {
195
#ifdef USE_SDL2
196
        const std::string cf = std::string("sdl2")
197
            + inputActionData[i].configField;
198
#else  // USE_SDL2
199
200
        const std::string cf = inputActionData[i].configField;
201
#endif  // USE_SDL2
202
203
        if (!cf.empty())
204
        {
205
            std::string keyStr;
206
            const InputFunction &restrict kf = mKey[i];
207
208
            for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
209
            {
210
                const InputItem &restrict key = kf.values[i2];
211
                if (key.type != InputType::UNKNOWN)
212
                {
213
                    std::string tmp("k");
214
                    switch (key.type)
215
                    {
216
                        case InputType::MOUSE:
217
                            tmp = "m";
218
                            break;
219
                        case InputType::JOYSTICK:
220
                            tmp = "j";
221
                            break;
222
                        case InputType::KEYBOARD:
223
                        case InputType::UNKNOWN:
224
                        default:
225
                            break;
226
                    }
227
                    if (key.value != -1)
228
                    {
229
                        if (keyStr.empty())
230
                        {
231
                            keyStr.append(tmp).append(toString(key.value));
232
                        }
233
                        else
234
                        {
235
                            keyStr.append(strprintf(",%s%d",
236
                                tmp.c_str(), key.value));
237
                        }
238
                    }
239
                }
240
            }
241
            if (keyStr.empty())
242
                keyStr = "-1";
243
244
            config.setValue(cf, keyStr);
245
        }
246
    }
247
}
248
249
void InputManager::resetKey(const InputActionT i) restrict2
250
{
251
    InputFunction &restrict key = mKey[CAST_SIZE(i)];
252
    for (size_t i2 = 1; i2 < inputFunctionSize; i2 ++)
253
    {
254
        InputItem &restrict ki2 = key.values[i2];
255
        ki2.type = InputType::UNKNOWN;
256
        ki2.value = -1;
257
    }
258
    const InputActionData &restrict kd =
259
        inputActionData[CAST_SIZE(i)];
260
    InputItem &restrict val0 = key.values[0];
261
    val0.type = kd.defaultType1;
262
    InputItem &restrict val1 = key.values[1];
263
    val1.type = kd.defaultType2;
264
#ifdef USE_SDL2
265
    if (kd.defaultType1 == InputType::KEYBOARD)
266
        val0.value = SDL_GetScancodeFromKey(kd.defaultValue1);
267
    else
268
        val0.value = kd.defaultValue1;
269
    if (kd.defaultType2 == InputType::KEYBOARD)
270
        val1.value = SDL_GetScancodeFromKey(kd.defaultValue2);
271
    else
272
        val1.value = kd.defaultValue2;
273
    if (val0.value == SDL_SCANCODE_UNKNOWN)
274
        val0.value = -1;
275
    if (val1.value == SDL_SCANCODE_UNKNOWN)
276
        val1.value = -1;
277
#else  // USE_SDL2
278
279
    val0.value = kd.defaultValue1;
280
    val1.value = kd.defaultValue2;
281
#endif  // USE_SDL2
282
283
    updateKeyString(key, CAST_SIZE(i));
284
}
285
286
void InputManager::resetKeys() restrict2
287
{
288
    for (int i = 0; i < CAST_S32(InputAction::TOTAL); i++)
289
        resetKey(static_cast<InputActionT>(i));
290
}
291
292
void InputManager::makeDefault(const InputActionT i) restrict2
293
{
294
    if (i > InputAction::NO_VALUE && i < InputAction::TOTAL)
295
    {
296
        resetKey(i);
297
        update();
298
    }
299
}
300
301
bool InputManager::hasConflicts(InputActionT &restrict key1,
302
                                InputActionT &restrict key2) const restrict2
303
{
304
    /**
305
     * No need to parse the square matrix: only check one triangle
306
     * that's enough to detect conflicts
307
     */
308
    for (int i = 0; i < CAST_S32(InputAction::TOTAL); i++)
309
    {
310
        const InputActionData &restrict kdi = inputActionData[i];
311
        if (*kdi.configField == 0)
312
            continue;
313
314
        const InputFunction &restrict ki = mKey[i];
315
        for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
316
        {
317
            const InputItem &restrict vali2 = ki.values[i2];
318
            if (vali2.value == -1)
319
                continue;
320
321
            size_t j;
322
            for (j = i, j++; j < CAST_S32(InputAction::TOTAL); j++)
323
            {
324
                if ((kdi.grp & inputActionData[j].grp) == 0
325
                    || (*kdi.configField == 0))
326
                {
327
                    continue;
328
                }
329
330
                for (size_t j2 = 0; j2 < inputFunctionSize; j2 ++)
331
                {
332
                    const InputItem &restrict valj2 = mKey[j].values[j2];
333
                    // Allow for item shortcut and emote keys to overlap
334
                    // as well as emote and ignore keys, but no other keys
335
                    if (valj2.type != InputType::UNKNOWN
336
                        && vali2.value == valj2.value
337
                        && vali2.type == valj2.type)
338
                    {
339
                        key1 = static_cast<InputActionT>(i);
340
                        key2 = static_cast<InputActionT>(j);
341
                        return true;
342
                    }
343
                }
344
            }
345
        }
346
    }
347
    return false;
348
}
349
350
void InputManager::callbackNewKey() restrict2
351
{
352
#ifndef DYECMD
353
    mSetupInput->newKeyCallback(mNewKeyIndex);
354
#endif  // DYECMD
355
}
356
357
4
bool InputManager::isActionActive(const InputActionT index) const restrict2
358
{
359

4
    if (!isActionActive0(index))
360
        return false;
361
362
    const InputActionData &restrict key =
363
        inputActionData[CAST_SIZE(index)];
364
//    logger->log("isActionActive mask=%d, condition=%d, index=%d",
365
//        mMask, key.condition, index);
366
    if ((key.condition & mMask) != key.condition)
367
        return false;
368
    return true;
369
}
370
371
4
bool InputManager::isActionActive0(const InputActionT index)
372
{
373
4
    if (keyboard.isActionActive(index))
374
        return true;
375

4
    if ((joystick != nullptr) && joystick->isActionActive(index))
376
        return true;
377
4
    return touchManager.isActionActive(index);
378
}
379
380
InputFunction &InputManager::getKey(InputActionT index) restrict2
381
{
382
    if (CAST_S32(index) < 0 || index >= InputAction::TOTAL)
383
        index = InputAction::MOVE_UP;
384
    return mKey[CAST_SIZE(index)];
385
}
386
387
150
std::string InputManager::getKeyStringLong(const InputActionT index) const
388
                                           restrict2
389
{
390
300
    std::string keyStr;
391
150
    const InputFunction &restrict ki = mKey[CAST_SIZE(index)];
392
393
600
    for (size_t i = 0; i < inputFunctionSize; i ++)
394
    {
395
450
        const InputItem &restrict key = ki.values[i];
396
900
        std::string str;
397
450
        if (key.type == InputType::KEYBOARD)
398
        {
399
            if (key.value >= 0)
400
            {
401
                str = KeyboardConfig::getKeyName(key.value);
402
            }
403
            else if (key.value < -1)
404
            {
405
                // TRANSLATORS: long key name. must be short.
406
                str = strprintf(_("key_%d"), -key.value);
407
            }
408
        }
409
450
        else if (key.type == InputType::JOYSTICK)
410
        {
411
            // TRANSLATORS: long joystick button name. must be short.
412
            str = strprintf(_("JButton%d"), key.value + 1);
413
        }
414
450
        if (!str.empty())
415
        {
416
            if (keyStr.empty())
417
                keyStr = str;
418
            else
419
                keyStr.append(", ").append(str);
420
        }
421
    }
422
423
150
    if (keyStr.empty())
424
    {
425
        // TRANSLATORS: unknown long key type
426
450
        return _("unknown key");
427
    }
428
    return keyStr;
429
}
430
431
void InputManager::updateKeyString(const InputFunction &ki,
432
                                   const size_t actionIdx) restrict2
433
{
434
    std::string keyStr;
435
    for (size_t i = 0; i < inputFunctionSize; i ++)
436
    {
437
        const InputItem &restrict key = ki.values[i];
438
        std::string str;
439
        if (key.type == InputType::KEYBOARD)
440
        {
441
            if (key.value >= 0)
442
            {
443
                str = KeyboardConfig::getKeyShortString(
444
                    KeyboardConfig::getKeyName(key.value));
445
            }
446
            else if (key.value < -1)
447
            {
448
                // TRANSLATORS: short key name. must be very short.
449
                str = strprintf(_("key_%d"), -key.value);
450
            }
451
        }
452
        else if (key.type == InputType::JOYSTICK)
453
        {
454
            // TRANSLATORS: short joystick button name. muse be very short
455
            str = strprintf(_("JB%d"), key.value + 1);
456
        }
457
        if (!str.empty())
458
        {
459
            if (keyStr.empty())
460
                keyStr = str;
461
            else
462
                keyStr.append(", ").append(str);
463
        }
464
    }
465
466
    if (keyStr.empty())
467
    {
468
        // TRANSLATORS: unknown short key type. must be short
469
        mKeyStr[actionIdx] = _("u key");
470
    }
471
    else
472
    {
473
        mKeyStr[actionIdx] = STD_MOVE(keyStr);
474
    }
475
}
476
477
std::string InputManager::getKeyValueString(const InputActionT index) const
478
                                            restrict2
479
{
480
    return mKeyStr[CAST_SIZE(index)];
481
}
482
483
std::string InputManager::getKeyValueByName(const std::string &restrict
484
                                            keyName) restrict2
485
{
486
    const StringInpActionMapCIter it = mNameMap.find(keyName);
487
488
    if (it == mNameMap.end())
489
        return std::string();
490
    return getKeyValueString((*it).second);
491
}
492
493
std::string InputManager::getKeyValueByNameLong(const std::string &restrict
494
                                                keyName) restrict2
495
{
496
    const StringInpActionMapCIter it = mNameMap.find(keyName);
497
498
    if (it == mNameMap.end())
499
        return std::string();
500
    return getKeyStringLong((*it).second);
501
}
502
503
void InputManager::addActionKey(const InputActionT action,
504
                                const InputTypeT type,
505
                                const int val) restrict2
506
{
507
    if (CAST_S32(action) < 0 || action >= InputAction::TOTAL)
508
        return;
509
510
    int idx = -1;
511
    InputFunction &restrict key = mKey[CAST_SIZE(action)];
512
    for (size_t i = 0; i < inputFunctionSize; i ++)
513
    {
514
        const InputItem &restrict val2 = key.values[i];
515
        if (val2.type == InputType::UNKNOWN ||
516
            (val2.type == type && val2.value == val))
517
        {
518
            idx = CAST_S32(i);
519
            break;
520
        }
521
    }
522
    if (idx == -1)
523
    {
524
        for (size_t i = 1; i < inputFunctionSize; i ++)
525
        {
526
            InputItem &restrict val1 = key.values[i - 1];
527
            InputItem &restrict val2 = key.values[i];
528
            val1.type = val2.type;
529
            val1.value = val2.value;
530
        }
531
        idx = inputFunctionSize - 1;
532
    }
533
534
    key.values[idx] = InputItem(type, val);
535
    updateKeyString(key, CAST_SIZE(action));
536
}
537
538
void InputManager::setNewKey(const SDL_Event &event,
539
                             const InputTypeT type) restrict2
540
{
541
    int val = -1;
542
    if (type == InputType::KEYBOARD)
543
        val = KeyboardConfig::getKeyValueFromEvent(event);
544
    else if (type == InputType::JOYSTICK && (joystick != nullptr))
545
        val = joystick->getButtonFromEvent(event);
546
547
    if (val != -1)
548
    {
549
        addActionKey(mNewKeyIndex, type, val);
550
        update();
551
    }
552
}
553
554
void InputManager::unassignKey() restrict2
555
{
556
    InputFunction &restrict key = mKey[CAST_SIZE(mNewKeyIndex)];
557
    for (size_t i = 0; i < inputFunctionSize; i ++)
558
    {
559
        InputItem &restrict val = key.values[i];
560
        val.type = InputType::UNKNOWN;
561
        val.value = -1;
562
    }
563
    updateKeyString(key, CAST_SIZE(mNewKeyIndex));
564
    update();
565
}
566
567
#ifndef DYECMD
568
bool InputManager::handleAssignKey(const SDL_Event &restrict event,
569
                                   const InputTypeT type) restrict2
570
{
571
    if ((setupWindow != nullptr) && setupWindow->isWindowVisible() &&
572
        getNewKeyIndex() > InputAction::NO_VALUE)
573
    {
574
        setNewKey(event, type);
575
        callbackNewKey();
576
        setNewKeyIndex(InputAction::NO_VALUE);
577
        return true;
578
    }
579
    return false;
580
}
581
#else  // DYECMD
582
583
bool InputManager::handleAssignKey(const SDL_Event &restrict event A_UNUSED,
584
                                   const InputTypeT type A_UNUSED) restrict2
585
{
586
    return false;
587
}
588
#endif  // DYECMD
589
590
bool InputManager::handleEvent(const SDL_Event &restrict event) restrict2
591
{
592
    BLOCK_START("InputManager::handleEvent")
593
    switch (event.type)
594
    {
595
        case SDL_KEYDOWN:
596
        {
597
#ifdef USE_SDL2
598
            if (keyboard.ignoreKey(event))
599
            {
600
                BLOCK_END("InputManager::handleEvent")
601
                return true;
602
            }
603
#endif  // USE_SDL2
604
605
            keyboard.refreshActiveKeys();
606
            updateConditionMask(true);
607
            if (handleAssignKey(event, InputType::KEYBOARD))
608
            {
609
                BLOCK_END("InputManager::handleEvent")
610
                return true;
611
            }
612
613
            keyboard.handleActivateKey(event);
614
            // send straight to gui for certain windows
615
#ifndef DYECMD
616
            if ((quitDialog != nullptr) || TextDialog::isActive())
617
            {
618
                if (guiInput != nullptr)
619
                    guiInput->pushInput(event);
620
                if (gui != nullptr)
621
                    gui->handleInput();
622
                BLOCK_END("InputManager::handleEvent")
623
                return true;
624
            }
625
#endif  // DYECMD
626
627
            break;
628
        }
629
        case SDL_KEYUP:
630
        {
631
#ifdef USE_SDL2
632
            if (keyboard.ignoreKey(event))
633
            {
634
                BLOCK_END("InputManager::handleEvent")
635
                return true;
636
            }
637
#endif  // USE_SDL2
638
639
            keyboard.refreshActiveKeys();
640
            updateConditionMask(false);
641
            keyboard.handleDeActicateKey(event);
642
            break;
643
        }
644
        case SDL_JOYBUTTONDOWN:
645
        {
646
            updateConditionMask(true);
647
//            joystick.handleActicateButton(event);
648
            if (handleAssignKey(event, InputType::JOYSTICK))
649
            {
650
                BLOCK_END("InputManager::handleEvent")
651
                return true;
652
            }
653
            break;
654
        }
655
        case SDL_JOYBUTTONUP:
656
        {
657
            updateConditionMask(false);
658
//            joystick.handleDeActicateButton(event);
659
            break;
660
        }
661
#ifdef USE_SDL2
662
        case SDL_FINGERDOWN:
663
            multiTouchManager.handleFingerDown(event);
664
            break;
665
        case SDL_FINGERUP:
666
            multiTouchManager.handleFingerUp(event);
667
            break;
668
#else  // USE_SDL2
669
#ifdef ANDROID
670
        case SDL_ACCELEROMETER:
671
        {
672
            break;
673
        }
674
#endif  // ANDROID
675
#endif  // USE_SDL2
676
677
        default:
678
            break;
679
    }
680
681
    if (guiInput != nullptr)
682
        guiInput->pushInput(event);
683
    if (gui != nullptr)
684
    {
685
        const bool res = gui->handleInput();
686
        if (res && event.type == SDL_KEYDOWN)
687
        {
688
            BLOCK_END("InputManager::handleEvent")
689
            return true;
690
        }
691
    }
692
693
    switch (event.type)
694
    {
695
        case SDL_KEYDOWN:
696
            if (isActionActive(InputAction::IGNORE_INPUT_1) ||
697
                isActionActive(InputAction::IGNORE_INPUT_2))
698
            {
699
                BLOCK_END("InputManager::handleEvent")
700
                return true;
701
            }
702
            if (triggerAction(keyboard.getActionVector(event)))
703
            {
704
                BLOCK_END("InputManager::handleEvent")
705
                return true;
706
            }
707
            break;
708
709
// disabled temporary
710
//        case SDL_KEYUP:
711
//            if (triggerAction(keyboard.getActionVector(event)))
712
//            {
713
//                BLOCK_END("InputManager::handleEvent")
714
//                return true;
715
//            }
716
//            break;
717
718
        case SDL_JOYBUTTONDOWN:
719
            if ((joystick != nullptr) && joystick->validate())
720
            {
721
                if (triggerAction(joystick->getActionVector(event)))
722
                {
723
                    BLOCK_END("InputManager::handleEvent")
724
                    return true;
725
                }
726
            }
727
            break;
728
#ifdef ANDROID
729
#ifndef USE_SDL2
730
        case SDL_ACCELEROMETER:
731
        {
732
            break;
733
        }
734
#endif  // USE_SDL2
735
#endif  // ANDROID
736
737
        default:
738
            break;
739
    }
740
741
    BLOCK_END("InputManager::handleEvent")
742
    return false;
743
}
744
745
void InputManager::handleRepeat()
746
{
747
    const int time = tick_time;
748
    keyboard.handleRepeat(time);
749
    if (joystick != nullptr)
750
        joystick->handleRepeat(time);
751
}
752
753
void InputManager::updateConditionMask(const bool pressed A_UNUSED) restrict2
754
{
755
    mMask = 1;
756
    if (keyboard.isEnabled())
757
        mMask |= InputCondition::ENABLED;
758
#ifndef DYECMD
759
    if (((chatWindow == nullptr) || !chatWindow->isInputFocused()) &&
760
        !NpcDialog::isAnyInputFocused() &&
761
        !InventoryWindow::isAnyInputFocused() &&
762
        ((tradeWindow == nullptr) || !tradeWindow->isInpupFocused()))
763
    {
764
        if (gui != nullptr)
765
        {
766
            FocusHandler *restrict const focus = gui->getFocusHandler();
767
            if (focus != nullptr)
768
            {
769
                if (dynamic_cast<TextField*>(focus->getFocused()) == nullptr)
770
                    mMask |= InputCondition::NOINPUT;
771
            }
772
            else
773
            {
774
                mMask |= InputCondition::NOINPUT;
775
            }
776
        }
777
        else
778
        {
779
            mMask |= InputCondition::NOINPUT;
780
        }
781
    }
782
783
    if (!BuyDialog::isActive() && !SellDialog::isActive())
784
        mMask |= InputCondition::NOBUYSELL;
785
786
    if (!PlayerInfo::isVending())
787
        mMask |= InputCondition::NOVENDING;
788
    if (!PlayerInfo::isInRoom())
789
        mMask |= InputCondition::NOROOM;
790
791
    const NpcDialog *restrict const dialog = NpcDialog::getActive();
792
    if ((dialog == nullptr) || !dialog->isTextInputFocused())
793
        mMask |= InputCondition::NONPCINPUT;
794
    if ((dialog == nullptr) || (dialog->isCloseState() != 0))
795
    {
796
        mMask |= InputCondition::NONPCDIALOG;
797
        if (!InventoryWindow::isStorageActive())
798
            mMask |= InputCondition::NOTALKING;
799
    }
800
    if ((setupWindow == nullptr) || !setupWindow->isWindowVisible())
801
        mMask |= InputCondition::NOSETUP;
802
803
    if ((Game::instance() != nullptr) && Game::instance()->getValidSpeed())
804
        mMask |= InputCondition::VALIDSPEED;
805
806
    if (Game::instance() != nullptr)
807
        mMask |= InputCondition::INGAME;
808
809
    if (localPlayer != nullptr)
810
    {
811
        if (localPlayer->getFollow().empty())
812
            mMask |= InputCondition::NOFOLLOW;
813
814
        if (!localPlayer->isTrickDead())
815
            mMask |= InputCondition::NOBLOCK;
816
817
        if (localPlayer->isAlive())
818
            mMask |= InputCondition::ALIVE;
819
    }
820
    else
821
    {
822
        mMask |= InputCondition::NOFOLLOW;
823
        mMask |= InputCondition::NOBLOCK;
824
    }
825
#endif  // DYECMD
826
827
    if (!settings.awayMode)
828
        mMask |= InputCondition::NOAWAY;
829
830
    if (gui != nullptr && gui->getFocusHandler()->getModalFocused() == nullptr)
831
        mMask |= InputCondition::NOMODAL;
832
833
    if (!settings.disableGameModifiers)
834
        mMask |= InputCondition::EMODS;
835
836
    if (!isActionActive0(InputAction::STOP_ATTACK)
837
        && !isActionActive0(InputAction::UNTARGET))
838
    {
839
        mMask |= InputCondition::NOTARGET;
840
    }
841
    // enable it temporary
842
    mMask |= InputCondition::KEY_DOWN;
843
//    if (pressed == true)
844
//        mMask |= InputCondition::KEY_DOWN;
845
//    else
846
//        mMask |= InputCondition::KEY_UP;
847
}
848
849
bool InputManager::checkKey(const InputActionData *restrict const key) const
850
                            restrict2
851
{
852
    // logger->log("checkKey mask=%d, condition=%d", mMask, key->condition);
853
    if ((key == nullptr) || (key->condition & mMask) != key->condition)
854
        return false;
855
856
    return key->modKeyIndex == InputAction::NO_VALUE
857
        || isActionActive0(key->modKeyIndex);
858
}
859
860
bool InputManager::invokeKey(const InputActionData *restrict const key,
861
                             const InputActionT keyNum) restrict2
862
{
863
    // no validation to keyNum because it validated in caller
864
865
    if (checkKey(key))
866
    {
867
        InputEvent evt(keyNum, mMask);
868
        ActionFuncPtr func = *(inputActionData[
869
            CAST_SIZE(keyNum)].action);
870
        if ((func != nullptr) && func(evt))
871
            return true;
872
    }
873
    return false;
874
}
875
876
void InputManager::executeAction(const InputActionT keyNum) restrict2
877
{
878
    if (keyNum < InputAction::MOVE_UP || keyNum >= InputAction::TOTAL)
879
        return;
880
881
    ActionFuncPtr func = *(inputActionData[CAST_SIZE(
882
        keyNum)].action);
883
    if (func != nullptr)
884
    {
885
        InputEvent evt(keyNum, mMask);
886
        func(evt);
887
    }
888
}
889
890
bool InputManager::executeChatCommand(const std::string &restrict cmd,
891
                                      const std::string &restrict args,
892
                                      ChatTab *restrict const tab) restrict2
893
{
894
    const StringIntMapCIter it = mChatMap.find(cmd);
895
    if (it != mChatMap.end())
896
    {
897
        ActionFuncPtr func = *(inputActionData[(*it).second].action);
898
        if (func != nullptr)
899
        {
900
            InputEvent evt(args, tab, mMask);
901
            func(evt);
902
            return true;
903
        }
904
    }
905
    else
906
    {
907
        reportAlways("Unknown chat command: /%s %s",
908
            cmd.c_str(),
909
            args.c_str());
910
    }
911
    return false;
912
}
913
914
bool InputManager::executeRemoteChatCommand(const std::string &restrict cmd,
915
                                            const std::string &restrict args,
916
                                            ChatTab *restrict const tab)
917
                                            restrict2
918
{
919
    const StringIntMapCIter it = mChatMap.find(cmd);
920
    if (it != mChatMap.end())
921
    {
922
        const InputActionData &restrict data = inputActionData[(*it).second];
923
        if (data.isProtected == Protected_true)
924
            return false;
925
        ActionFuncPtr func = *(data.action);
926
        if (func != nullptr)
927
        {
928
            InputEvent evt(args, tab, mMask);
929
            func(evt);
930
            return true;
931
        }
932
    }
933
    return false;
934
}
935
936
bool InputManager::executeChatCommand(const InputActionT keyNum,
937
                                      const std::string &restrict args,
938
                                      ChatTab *restrict const tab) restrict2
939
{
940
    if (CAST_S32(keyNum) < 0 || keyNum >= InputAction::TOTAL)
941
        return false;
942
    ActionFuncPtr func = *(inputActionData[CAST_SIZE(
943
        keyNum)].action);
944
    if (func != nullptr)
945
    {
946
        InputEvent evt(args, tab, mMask);
947
        func(evt);
948
        return true;
949
    }
950
    return false;
951
}
952
953
2
void InputManager::updateKeyActionMap(KeyToActionMap &restrict actionMap,
954
                                      KeyToIdMap &restrict idMap,
955
                                      KeyTimeMap &restrict keyTimeMap,
956
                                      const InputTypeT type) const restrict2
957
{
958
2
    actionMap.clear();
959
2
    keyTimeMap.clear();
960
961
1338
    for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i ++)
962
    {
963
1336
        const InputFunction &restrict key = mKey[i];
964
1336
        const InputActionData &restrict kd = inputActionData[i];
965
1336
        if (kd.action != nullptr)
966
        {
967
8596
            for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
968
            {
969
3684
                const InputItem &restrict ki = key.values[i2];
970

3684
                if (ki.type == type && ki.value != -1)
971
                {
972
                    actionMap[ki.value].push_back(
973
                        static_cast<InputActionT>(i));
974
                }
975
            }
976
        }
977

1336
        if (kd.configField != nullptr && (kd.grp & Input::GRP_GUICHAN) != 0)
978
        {
979
574
            for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
980
            {
981
246
                const InputItem &restrict ki = key.values[i2];
982

246
                if (ki.type == type && ki.value != -1)
983
                    idMap[ki.value] = static_cast<InputActionT>(i);
984
            }
985
        }
986

1336
        if (kd.configField != nullptr && (kd.grp & Input::GRP_REPEAT) != 0)
987
        {
988
42
            for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
989
            {
990
18
                const InputItem &restrict ki = key.values[i2];
991

18
                if (ki.type == type && ki.value != -1)
992
                    keyTimeMap[ki.value] = 0;
993
            }
994
        }
995
    }
996
997
2
    inputActionDataSorter.keys = &inputActionData[0];
998
4
    FOR_EACH (KeyToActionMapIter, it, actionMap)
999
    {
1000
        KeysVector *const keys = &it->second;
1001
        if (keys->size() > 1)
1002
            std::sort(keys->begin(), keys->end(), inputActionDataSorter);
1003
    }
1004
2
}
1005
1006
bool InputManager::triggerAction(const KeysVector *restrict const ptrs)
1007
                                 restrict2
1008
{
1009
    if (ptrs == nullptr)
1010
        return false;
1011
1012
//    logger->log("ptrs: %d", (int)ptrs.size());
1013
1014
    FOR_EACHP (KeysVectorCIter, it, ptrs)
1015
    {
1016
        const InputActionT keyNum = *it;
1017
        if (CAST_S32(keyNum) < 0 || keyNum >= InputAction::TOTAL)
1018
            continue;
1019
1020
        if (invokeKey(&inputActionData[CAST_SIZE(keyNum)], keyNum))
1021
            return true;
1022
    }
1023
    return false;
1024
}
1025
1026
InputActionT InputManager::getKeyIndex(const int value,
1027
                                       const int grp,
1028
                                       const InputTypeT type) const restrict2
1029
{
1030
    for (size_t i = 0; i < CAST_SIZE(InputAction::TOTAL); i++)
1031
    {
1032
        const InputFunction &restrict key = mKey[i];
1033
        const InputActionData &restrict kd = inputActionData[i];
1034
        for (size_t i2 = 0; i2 < inputFunctionSize; i2 ++)
1035
        {
1036
            const InputItem &restrict vali2 = key.values[i2];
1037
            if (value == vali2.value &&
1038
                (grp & kd.grp) != 0 && vali2.type == type)
1039
            {
1040
                return static_cast<InputActionT>(i);
1041
            }
1042
        }
1043
    }
1044
    return InputAction::NO_VALUE;
1045
}
1046
1047
InputActionT InputManager::getActionByKey(const SDL_Event &restrict event)
1048
                                          const restrict2
1049
{
1050
    // for now support only keyboard events
1051
    if (event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
1052
    {
1053
        const InputActionT idx = keyboard.getActionId(event);
1054
        if (CAST_S32(idx) >= 0 &&
1055
            checkKey(&inputActionData[CAST_SIZE(idx)]))
1056
        {
1057
            return idx;
1058
        }
1059
    }
1060
    return InputAction::NO_VALUE;
1061
}
1062
1063
InputActionT InputManager::getActionByConfigField(const std::string &field)
1064
                                                  const restrict2
1065
{
1066
    for (int i = 0; i < CAST_S32(InputAction::TOTAL); i ++)
1067
    {
1068
        const std::string cf = inputActionData[i].configField;
1069
        if (field == cf)
1070
            return static_cast<InputActionT>(i);
1071
    }
1072
    return InputAction::NO_VALUE;
1073
}
1074
1075
4
void InputManager::addChatCommands(std::list<std::string> &restrict arr)
1076
                                   restrict
1077
{
1078
4
    const int sz = CAST_S32(InputAction::TOTAL);
1079
2676
    for (int i = 0; i < sz; i++)
1080
    {
1081
2672
        const InputActionData &restrict ad = inputActionData[i];
1082
8016
        std::string cmd = ad.chatCommand;
1083
2672
        if (!cmd.empty())
1084
        {
1085
2552
            StringVect tokens;
1086
1276
            splitToStringVector(tokens, cmd, '|');
1087
8428
            FOR_EACH (StringVectCIter, it, tokens)
1088
            {
1089
12288
                cmd = std::string("/").append(*it);
1090
2048
                if (ad.useArgs == UseArgs_true)
1091
1068
                    cmd.append(" ");
1092
2048
                arr.push_back(cmd);
1093
            }
1094
        }
1095
    }
1096

10
}