~ubuntu-branches/ubuntu/trusty/manaplus/trusty-proposed

« back to all changes in this revision

Viewing changes to src/input/joystick.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-09-17 10:35:51 UTC
  • mfrom: (1.1.10)
  • Revision ID: package-import@ubuntu.com-20130917103551-az7p3nz9jgxwqjfn
Tags: 1.3.9.15-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  The ManaPlus Client
 
3
 *  Copyright (C) 2004-2009  The Mana World Development Team
 
4
 *  Copyright (C) 2009-2010  The Mana Developers
 
5
 *  Copyright (C) 2011-2013  The ManaPlus Developers
 
6
 *
 
7
 *  This file is part of The ManaPlus Client.
 
8
 *
 
9
 *  This program is free software; you can redistribute it and/or modify
 
10
 *  it under the terms of the GNU General Public License as published by
 
11
 *  the Free Software Foundation; either version 2 of the License, or
 
12
 *  any later version.
 
13
 *
 
14
 *  This program is distributed in the hope that it will be useful,
 
15
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 *  GNU General Public License for more details.
 
18
 *
 
19
 *  You should have received a copy of the GNU General Public License
 
20
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
21
 */
 
22
 
 
23
#include "input/joystick.h"
 
24
 
 
25
#include "client.h"
 
26
#include "configuration.h"
 
27
#include "logger.h"
 
28
#include "sdlshared.h"
 
29
 
 
30
#include "input/inputmanager.h"
 
31
 
 
32
#include "debug.h"
 
33
 
 
34
int Joystick::joystickCount = 0;
 
35
bool Joystick::mEnabled = false;
 
36
 
 
37
Joystick::Joystick(const int no):
 
38
    mDirection(0),
 
39
    mJoystick(nullptr),
 
40
    mUpTolerance(0),
 
41
    mDownTolerance(0),
 
42
    mLeftTolerance(0),
 
43
    mRightTolerance(0),
 
44
    mCalibrating(false),
 
45
    mNumber(no >= joystickCount ? joystickCount : no),
 
46
    mCalibrated(false),
 
47
    mButtonsNumber(MAX_BUTTONS),
 
48
    mUseInactive(false),
 
49
    mHaveHats(false),
 
50
    mKeyToAction(),
 
51
    mKeyToId(),
 
52
    mKeyTimeMap()
 
53
{
 
54
    for (int i = 0; i < MAX_BUTTONS; i++)
 
55
        mActiveButtons[i] = false;
 
56
}
 
57
 
 
58
Joystick::~Joystick()
 
59
{
 
60
    close();
 
61
}
 
62
 
 
63
void Joystick::init()
 
64
{
 
65
    SDL_InitSubSystem(SDL_INIT_JOYSTICK);
 
66
    SDL_JoystickEventState(SDL_ENABLE);
 
67
    joystickCount = SDL_NumJoysticks();
 
68
    logger->log("%i joysticks/gamepads found", joystickCount);
 
69
    for (int i = 0; i < joystickCount; i++)
 
70
        logger->log("- %s", SDL_JoystickNameForIndex(i));
 
71
 
 
72
    mEnabled = config.getBoolValue("joystickEnabled");
 
73
 
 
74
    if (joystickCount > 0)
 
75
    {
 
76
        joystick = new Joystick(config.getIntValue("selectedJoystick"));
 
77
        if (mEnabled)
 
78
            joystick->open();
 
79
    }
 
80
}
 
81
 
 
82
bool Joystick::open()
 
83
{
 
84
    if (mNumber >= joystickCount)
 
85
        mNumber = joystickCount - 1;
 
86
    if (mNumber < 0)
 
87
    {
 
88
        logger->log1("error: incorrect joystick selection");
 
89
        return false;
 
90
    }
 
91
    logger->log("open joystick %d", mNumber);
 
92
 
 
93
    mJoystick = SDL_JoystickOpen(mNumber);
 
94
 
 
95
    if (!mJoystick)
 
96
    {
 
97
        logger->log("Couldn't open joystick: %s", SDL_GetError());
 
98
        return false;
 
99
    }
 
100
 
 
101
    mButtonsNumber = SDL_JoystickNumButtons(mJoystick);
 
102
    logger->log("Joystick: %i ", mNumber);
 
103
    logger->log("Axes: %i ", SDL_JoystickNumAxes(mJoystick));
 
104
    logger->log("Balls: %i", SDL_JoystickNumBalls(mJoystick));
 
105
    logger->log("Hats: %i", SDL_JoystickNumHats(mJoystick));
 
106
    logger->log("Buttons: %i", mButtonsNumber);
 
107
 
 
108
    mHaveHats = (SDL_JoystickNumHats(mJoystick) > 0);
 
109
 
 
110
    if (mButtonsNumber > MAX_BUTTONS)
 
111
        mButtonsNumber = MAX_BUTTONS;
 
112
 
 
113
    mCalibrated = config.getValueBool("joystick"
 
114
        + toString(mNumber) + "calibrated", false);
 
115
    mUpTolerance = config.getIntValue("upTolerance" + toString(mNumber));
 
116
    mDownTolerance = config.getIntValue("downTolerance" + toString(mNumber));
 
117
    mLeftTolerance = config.getIntValue("leftTolerance" + toString(mNumber));
 
118
    mRightTolerance = config.getIntValue("rightTolerance" + toString(mNumber));
 
119
    mUseInactive = config.getBoolValue("useInactiveJoystick");
 
120
 
 
121
    return true;
 
122
}
 
123
 
 
124
void Joystick::close()
 
125
{
 
126
    logger->log("close joystick %d", mNumber);
 
127
    if (mJoystick)
 
128
    {
 
129
        SDL_JoystickClose(mJoystick);
 
130
        mJoystick = nullptr;
 
131
    }
 
132
}
 
133
 
 
134
void Joystick::reload()
 
135
{
 
136
    joystickCount = SDL_NumJoysticks();
 
137
    setNumber(mNumber);
 
138
}
 
139
 
 
140
void Joystick::setNumber(const int n)
 
141
{
 
142
    if (mJoystick)
 
143
    {
 
144
        SDL_JoystickClose(mJoystick);
 
145
        mNumber = n;
 
146
        open();
 
147
    }
 
148
    else
 
149
    {
 
150
        mNumber = n;
 
151
    }
 
152
}
 
153
 
 
154
void Joystick::logic()
 
155
{
 
156
    // When calibrating, don't bother the outside with our state
 
157
    if (mCalibrating)
 
158
    {
 
159
        doCalibration();
 
160
        return;
 
161
    };
 
162
 
 
163
    if (!mEnabled || !mCalibrated)
 
164
        return;
 
165
 
 
166
    mDirection = 0;
 
167
 
 
168
    if (mUseInactive || client->getInputFocused())
 
169
    {
 
170
        // X-Axis
 
171
        int position = SDL_JoystickGetAxis(mJoystick, 0);
 
172
        if (position >= mRightTolerance)
 
173
            mDirection |= RIGHT;
 
174
        else if (position <= mLeftTolerance)
 
175
            mDirection |= LEFT;
 
176
 
 
177
        // Y-Axis
 
178
        position = SDL_JoystickGetAxis(mJoystick, 1);
 
179
        if (position <= mUpTolerance)
 
180
            mDirection |= UP;
 
181
        else if (position >= mDownTolerance)
 
182
            mDirection |= DOWN;
 
183
 
 
184
#ifdef DEBUG_JOYSTICK
 
185
        if (SDL_JoystickGetAxis(mJoystick, 2))
 
186
            logger->log("axis 2 pos: %d", SDL_JoystickGetAxis(mJoystick, 2));
 
187
        if (SDL_JoystickGetAxis(mJoystick, 3))
 
188
            logger->log("axis 3 pos: %d", SDL_JoystickGetAxis(mJoystick, 3));
 
189
        if (SDL_JoystickGetAxis(mJoystick, 4))
 
190
            logger->log("axis 4 pos: %d", SDL_JoystickGetAxis(mJoystick, 4));
 
191
#endif
 
192
 
 
193
        if (!mDirection && mHaveHats)
 
194
        {
 
195
            // reading only hat 0
 
196
            const uint8_t hat = SDL_JoystickGetHat(mJoystick, 0);
 
197
            if (hat & SDL_HAT_RIGHT)
 
198
                mDirection |= RIGHT;
 
199
            else if (hat & SDL_HAT_LEFT)
 
200
                mDirection |= LEFT;
 
201
            if (hat & SDL_HAT_UP)
 
202
                mDirection |= UP;
 
203
            else if (hat & SDL_HAT_DOWN)
 
204
                mDirection |= DOWN;
 
205
        }
 
206
 
 
207
        // Buttons
 
208
        for (int i = 0; i < mButtonsNumber; i++)
 
209
        {
 
210
            const bool state = (SDL_JoystickGetButton(mJoystick, i) == 1);
 
211
            mActiveButtons[i] = state;
 
212
            if (!state)
 
213
                resetRepeat(i);
 
214
#ifdef DEBUG_JOYSTICK
 
215
            if (mActiveButtons[i])
 
216
                logger->log("button: %d", i);
 
217
#endif
 
218
        }
 
219
    }
 
220
    else
 
221
    {
 
222
        for (int i = 0; i < mButtonsNumber; i++)
 
223
            mActiveButtons[i] = false;
 
224
    }
 
225
}
 
226
 
 
227
void Joystick::startCalibration()
 
228
{
 
229
    mUpTolerance = 0;
 
230
    mDownTolerance = 0;
 
231
    mLeftTolerance = 0;
 
232
    mRightTolerance = 0;
 
233
    mCalibrating = true;
 
234
}
 
235
 
 
236
void Joystick::doCalibration()
 
237
{
 
238
    // X-Axis
 
239
    int position = SDL_JoystickGetAxis(mJoystick, 0);
 
240
    if (position > mRightTolerance)
 
241
        mRightTolerance = position;
 
242
    else if (position < mLeftTolerance)
 
243
        mLeftTolerance = position;
 
244
 
 
245
    // Y-Axis
 
246
    position = SDL_JoystickGetAxis(mJoystick, 1);
 
247
    if (position > mDownTolerance)
 
248
        mDownTolerance = position;
 
249
    else if (position < mUpTolerance)
 
250
        mUpTolerance = position;
 
251
}
 
252
 
 
253
void Joystick::finishCalibration()
 
254
{
 
255
    mCalibrated = true;
 
256
    mCalibrating = false;
 
257
    config.setValue("joystick" + toString(mNumber) + "calibrated", true);
 
258
    config.setValue("leftTolerance" + toString(mNumber), mLeftTolerance);
 
259
    config.setValue("rightTolerance" + toString(mNumber), mRightTolerance);
 
260
    config.setValue("upTolerance" + toString(mNumber), mUpTolerance);
 
261
    config.setValue("downTolerance" + toString(mNumber), mDownTolerance);
 
262
}
 
263
 
 
264
bool Joystick::buttonPressed(const unsigned char no) const
 
265
{
 
266
    return (mEnabled && no < MAX_BUTTONS) ? mActiveButtons[no] : false;
 
267
}
 
268
 
 
269
void Joystick::getNames(std::vector <std::string> &names)
 
270
{
 
271
    names.clear();
 
272
    for (int i = 0; i < joystickCount; i++)
 
273
        names.push_back(SDL_JoystickNameForIndex(i));
 
274
}
 
275
 
 
276
void Joystick::update()
 
277
{
 
278
    inputManager.updateKeyActionMap(mKeyToAction, mKeyToId,
 
279
        mKeyTimeMap, INPUT_JOYSTICK);
 
280
}
 
281
 
 
282
KeysVector *Joystick::getActionVector(const SDL_Event &event)
 
283
{
 
284
    const int i = getButtonFromEvent(event);
 
285
 
 
286
    if (i < 0 || i >= mButtonsNumber)
 
287
        return nullptr;
 
288
//    logger->log("button triggerAction: %d", i);
 
289
    if (mKeyToAction.find(i) != mKeyToAction.end())
 
290
        return &mKeyToAction[i];
 
291
    return nullptr;
 
292
}
 
293
 
 
294
KeysVector *Joystick::getActionVectorByKey(const int i)
 
295
{
 
296
    if (i < 0 || i >= mButtonsNumber)
 
297
        return nullptr;
 
298
//    logger->log("button triggerAction: %d", i);
 
299
    if (mKeyToAction.find(i) != mKeyToAction.end())
 
300
        return &mKeyToAction[i];
 
301
    return nullptr;
 
302
}
 
303
 
 
304
int Joystick::getButtonFromEvent(const SDL_Event &event) const
 
305
{
 
306
    if (event.jbutton.which != mNumber)
 
307
        return -1;
 
308
    return event.jbutton.button;
 
309
}
 
310
 
 
311
bool Joystick::isActionActive(const int index) const
 
312
{
 
313
    if (!validate())
 
314
        return false;
 
315
 
 
316
    const KeyFunction &key = inputManager.getKey(index);
 
317
    for (size_t i = 0; i < KeyFunctionSize; i ++)
 
318
    {
 
319
        const KeyItem &val = key.values[i];
 
320
        if (val.type != INPUT_JOYSTICK)
 
321
            continue;
 
322
        const int value = val.value;
 
323
        if (value >= 0 && value < mButtonsNumber)
 
324
        {
 
325
            if (mActiveButtons[value])
 
326
                return true;
 
327
        }
 
328
    }
 
329
    return false;
 
330
}
 
331
 
 
332
bool Joystick::validate() const
 
333
{
 
334
    if (mCalibrating || !mEnabled || !mCalibrated)
 
335
        return false;
 
336
 
 
337
    return (mUseInactive || client->getInputFocused());
 
338
}
 
339
 
 
340
void Joystick::handleRepeat(const int time)
 
341
{
 
342
    FOR_EACH (KeyTimeMapIter, it, mKeyTimeMap)
 
343
    {
 
344
        bool repeat(false);
 
345
        const int key = (*it).first;
 
346
        int &keyTime = (*it).second;
 
347
        if (key >= 0 && key < mButtonsNumber)
 
348
        {
 
349
            if (mActiveButtons[key])
 
350
                repeat = true;
 
351
        }
 
352
        if (repeat)
 
353
        {
 
354
            if (time > keyTime && abs(time - keyTime)
 
355
                > SDL_DEFAULT_REPEAT_DELAY * 10)
 
356
            {
 
357
                keyTime = time;
 
358
                inputManager.triggerAction(getActionVectorByKey(key));
 
359
            }
 
360
        }
 
361
    }
 
362
}
 
363
 
 
364
void Joystick::resetRepeat(const int key)
 
365
{
 
366
    const KeyTimeMapIter it = mKeyTimeMap.find(key);
 
367
    if (it != mKeyTimeMap.end())
 
368
        (*it).second = tick_time;
 
369
}