Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/input/KeyBinder.cc @ 2710

Last change on this file since 2710 was 2710, checked in by rgrieder, 15 years ago

Merged buildsystem3 containing buildsystem2 containing Adi's buildsystem branch back to the trunk.
Please update the media directory if you were not using buildsystem3 before.

  • Property svn:eol-style set to native
File size: 18.6 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) 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, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29/**
30 @file
31 @brief Implementation of the different input handlers.
32 */
33
34#include "KeyBinder.h"
35
36#include <fstream>
37#include <string>
38#include <boost/filesystem.hpp>
39
40#include "util/Convert.h"
41#include "util/Debug.h"
42#include "core/ConfigValueIncludes.h"
43#include "core/CoreIncludes.h"
44#include "core/ConfigFileManager.h"
45#include "core/Core.h"
46#include "InputCommands.h"
47#include "InputManager.h"
48
49namespace orxonox
50{
51    /**
52    @brief
53        Constructor that does as little as necessary.
54    */
55    KeyBinder::KeyBinder()
56        : numberOfJoySticks_(0)
57        , deriveTime_(0.0f)
58    {
59        mouseRelative_[0] = 0;
60        mouseRelative_[1] = 0;
61        mousePosition_[0] = 0;
62        mousePosition_[1] = 0;
63
64        RegisterRootObject(KeyBinder);
65
66        // intialise all buttons and half axes to avoid creating everything with 'new'
67        // keys
68        for (unsigned int i = 0; i < KeyCode::numberOfKeys; i++)
69        {
70            std::string keyname = KeyCode::ByString[i];
71            if (!keyname.empty())
72                keys_[i].name_ = std::string("Key") + keyname;
73            else
74                keys_[i].name_ = "";
75            keys_[i].paramCommandBuffer_ = &paramCommandBuffer_;
76            keys_[i].groupName_ = "Keys";
77        }
78        // mouse buttons plus 4 mouse wheel buttons only 'generated' by KeyBinder
79        const char* const mouseWheelNames[] = { "Wheel1Down", "Wheel1Up", "Wheel2Down", "Wheel2Up" };
80        for (unsigned int i = 0; i < numberOfMouseButtons_; i++)
81        {
82            std::string nameSuffix;
83            if (i < MouseButtonCode::numberOfButtons)
84                nameSuffix = MouseButtonCode::ByString[i];
85            else
86                nameSuffix = mouseWheelNames[i - MouseButtonCode::numberOfButtons];
87            mouseButtons_[i].name_ = std::string("Mouse") + nameSuffix;
88            mouseButtons_[i].paramCommandBuffer_ = &paramCommandBuffer_;
89            mouseButtons_[i].groupName_ = "MouseButtons";
90        }
91        // mouse axes
92        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
93        {
94            mouseAxes_[i].name_ = std::string("Mouse") + MouseAxisCode::ByString[i / 2];
95            if (i & 1)
96                mouseAxes_[i].name_ += "Pos";
97            else
98                mouseAxes_[i].name_ += "Neg";
99            mouseAxes_[i].paramCommandBuffer_ = &paramCommandBuffer_;
100            mouseAxes_[i].groupName_ = "MouseAxes";
101        }
102
103        // Get a new ConfigFileType from the ConfigFileManager
104        this->configFile_ = ConfigFileManager::getInstance().getNewConfigFileType();
105
106        // initialise joy sticks separatly to allow for reloading
107        numberOfJoySticks_ = InputManager::getInstance().numberOfJoySticks();
108        initialiseJoyStickBindings();
109
110        // collect all Buttons and HalfAxes
111        compilePointerLists();
112
113        // set them here to use allHalfAxes_
114        setConfigValues();
115    }
116
117    /**
118    @brief
119        Destructor
120    */
121    KeyBinder::~KeyBinder()
122    {
123        // almost no destructors required because most of the arrays are static.
124        clearBindings(); // does some destruction work
125    }
126
127    /**
128    @brief
129        Loader for the key bindings, managed by config values.
130    */
131    void KeyBinder::setConfigValues()
132    {
133        SetConfigValue(analogThreshold_, 0.05f)
134            .description("Threshold for analog axes until which the state is 0.");
135        SetConfigValue(bFilterAnalogNoise_, false)
136            .description("Specifies whether to filter small analog values like joy stick fluctuations.");
137        SetConfigValue(mouseSensitivity_, 1.0f)
138            .description("Mouse sensitivity.");
139        SetConfigValue(bDeriveMouseInput_, false)
140            .description("Whether or not to derive moues movement for the absolute value.");
141        SetConfigValue(derivePeriod_, 0.05f)
142            .description("Accuracy of the mouse input deriver. The higher the more precise, but laggier.");
143        SetConfigValue(mouseSensitivityDerived_, 1.0f)
144            .description("Mouse sensitivity if mouse input is derived.");
145        SetConfigValue(mouseWheelStepSize_, 120)
146            .description("Equals one step of the mousewheel.");
147        SetConfigValue(buttonThreshold_, 0.80f)
148            .description("Threshold for analog axes until which the button is not pressed.")
149            .callback(this, &KeyBinder::buttonThresholdChanged);
150    }
151
152    void KeyBinder::buttonThresholdChanged()
153    {
154        for (unsigned int i = 0; i < allHalfAxes_.size(); i++)
155            if (!allHalfAxes_[i]->bButtonThresholdUser_)
156                allHalfAxes_[i]->buttonThreshold_ = this->buttonThreshold_;
157    }
158
159    void KeyBinder::JoyStickDeviceNumberChanged(unsigned int value)
160    {
161        unsigned int oldValue = numberOfJoySticks_;
162        numberOfJoySticks_ = value;
163
164        // initialise joy stick bindings
165        initialiseJoyStickBindings();
166
167        // collect all Buttons and HalfAxes again
168        compilePointerLists();
169
170        // load the bindings if required
171        if (configFile_ != ConfigFileType::NoType)
172        {
173            for (unsigned int iDev = oldValue; iDev < numberOfJoySticks_; ++iDev)
174            {
175                for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; ++i)
176                    joyStickButtons_[iDev][i].readConfigValue(this->configFile_);
177                for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; ++i)
178                    joyStickAxes_[iDev][i].readConfigValue(this->configFile_);
179            }
180        }
181
182        // Set the button threshold for potential new axes
183        buttonThresholdChanged();
184    }
185
186    void KeyBinder::initialiseJoyStickBindings()
187    {
188        this->joyStickAxes_.resize(numberOfJoySticks_);
189        this->joyStickButtons_.resize(numberOfJoySticks_);
190
191        // reinitialise all joy stick binings (doesn't overwrite the old ones)
192        for (unsigned int iDev = 0; iDev < numberOfJoySticks_; iDev++)
193        {
194            std::string deviceNumber = convertToString(iDev);
195            // joy stick buttons
196            for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; i++)
197            {
198                joyStickButtons_[iDev][i].name_ = std::string("JoyStick") + deviceNumber + JoyStickButtonCode::ByString[i];
199                joyStickButtons_[iDev][i].paramCommandBuffer_ = &paramCommandBuffer_;
200                joyStickButtons_[iDev][i].groupName_ = std::string("JoyStick") + deviceNumber + "Buttons";
201            }
202            // joy stick axes
203            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
204            {
205                joyStickAxes_[iDev][i].name_ = std::string("JoyStick") + deviceNumber + JoyStickAxisCode::ByString[i >> 1];
206                if (i & 1)
207                    joyStickAxes_[iDev][i].name_ += "Pos";
208                else
209                    joyStickAxes_[iDev][i].name_ += "Neg";
210                joyStickAxes_[iDev][i].paramCommandBuffer_ = &paramCommandBuffer_;
211                joyStickAxes_[iDev][i].groupName_ = std::string("JoyStick") + deviceNumber + "Axes";
212            }
213        }
214    }
215
216    void KeyBinder::compilePointerLists()
217    {
218        allButtons_.clear();
219        allHalfAxes_.clear();
220
221        // Note: Don't include the dummy keys which don't actually exist in OIS but have a number
222        for (unsigned int i = 0; i < KeyCode::numberOfKeys; i++)
223            if (!keys_[i].name_.empty())
224                allButtons_[keys_[i].name_] = keys_ + i;
225        for (unsigned int i = 0; i < numberOfMouseButtons_; i++)
226            allButtons_[mouseButtons_[i].name_] = mouseButtons_ + i;
227        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
228        {
229            allButtons_[mouseAxes_[i].name_] = mouseAxes_ + i;
230            allHalfAxes_.push_back(mouseAxes_ + i);
231        }
232        for (unsigned int iDev = 0; iDev < numberOfJoySticks_; iDev++)
233        {
234            for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; i++)
235                allButtons_[joyStickButtons_[iDev][i].name_] = &(joyStickButtons_[iDev][i]);
236            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
237            {
238                allButtons_[joyStickAxes_[iDev][i].name_] = &(joyStickAxes_[iDev][i]);
239                allHalfAxes_.push_back(&(joyStickAxes_[iDev][i]));
240            }
241        }
242    }
243
244    /**
245    @brief
246        Loads the key and button bindings.
247    @return
248        True if loading succeeded.
249    */
250    void KeyBinder::loadBindings(const std::string& filename)
251    {
252        COUT(3) << "KeyBinder: Loading key bindings..." << std::endl;
253
254        if (filename.empty())
255            return;
256
257        ConfigFileManager::getInstance().setFilename(this->configFile_, filename);
258
259        // Parse bindings and create the ConfigValueContainers if necessary
260        clearBindings();
261        for (std::map<std::string, Button*>::const_iterator it = allButtons_.begin(); it != allButtons_.end(); ++it)
262            it->second->readConfigValue(this->configFile_);
263
264        COUT(3) << "KeyBinder: Loading key bindings done." << std::endl;
265    }
266
267    bool KeyBinder::setBinding(const std::string& binding, const std::string& name, bool bTemporary)
268    {
269        std::map<std::string, Button*>::iterator it = allButtons_.find(name);
270        if (it != allButtons_.end())
271        {
272            if (bTemporary)
273                it->second->configContainer_->tset(binding);
274            else
275                it->second->configContainer_->set(binding);
276            it->second->configContainer_->getValue(&(it->second->bindingString_), it->second);
277            return true;
278        }
279        else
280        {
281            COUT(2) << "Could not find key/button/axis with name '" << name << "'." << std::endl;
282            return false;
283        }
284    }
285
286    /**
287    @brief
288        Overwrites all bindings with ""
289    */
290    void KeyBinder::clearBindings()
291    {
292        for (std::map<std::string, Button*>::const_iterator it = allButtons_.begin(); it != allButtons_.end(); ++it)
293            it->second->clear();
294
295        for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
296            delete paramCommandBuffer_[i];
297        paramCommandBuffer_.clear();
298    }
299
300    void KeyBinder::resetJoyStickAxes()
301    {
302        for (unsigned int iDev = 0; iDev < numberOfJoySticks_; ++iDev)
303        {
304            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
305            {
306                joyStickAxes_[iDev][i].absVal_ = 0.0f;
307                joyStickAxes_[iDev][i].relVal_ = 0.0f;
308            }
309        }
310    }
311
312    void KeyBinder::tickMouse(float dt)
313    {
314        if (bDeriveMouseInput_)
315        {
316            // only update when derivation dt has passed
317            if (deriveTime_ > derivePeriod_)
318            {
319                for (int i = 0; i < 2; i++)
320                {
321                    if (mouseRelative_[i] < 0)
322                    {
323                        mouseAxes_[2*i + 0].absVal_
324                            = -mouseRelative_[i] / deriveTime_ * 0.0005 * mouseSensitivityDerived_;
325                        mouseAxes_[2*i + 1].absVal_ = 0.0f;
326                    }
327                    else if (mouseRelative_[i] > 0)
328                    {
329                        mouseAxes_[2*i + 0].absVal_ = 0.0f;
330                        mouseAxes_[2*i + 1].absVal_
331                            =  mouseRelative_[i] / deriveTime_ * 0.0005 * mouseSensitivityDerived_;
332                    }
333                    else
334                    {
335                        mouseAxes_[2*i + 0].absVal_ = 0.0f;
336                        mouseAxes_[2*i + 1].absVal_ = 0.0f;
337                    }
338                    mouseRelative_[i] = 0;
339                    mouseAxes_[2*i + 0].hasChanged_ = true;
340                    mouseAxes_[2*i + 1].hasChanged_ = true;
341                }
342                deriveTime_ = 0.0f;
343            }
344            else
345                deriveTime_ += dt;
346        }
347
348        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
349        {
350            // Why dividing relative value by dt? The reason lies in the simple fact, that when you
351            // press a button that has relative movement, that value has to be multiplied by dt to be
352            // frame rate independent. This can easily (and only) be done in tickInput(float).
353            // Hence we need to divide by dt here for the mouse to compensate, because the relative
354            // move movements have nothing to do with dt.
355            if (dt != 0.0f)
356            {
357                // just ignore if dt == 0.0 because we have multiplied by 0.0 anyway..
358                mouseAxes_[i].relVal_ /= dt;
359            }
360
361            tickHalfAxis(mouseAxes_[i]);
362        }
363    }
364
365    void KeyBinder::tickJoyStick(float dt, unsigned int joyStick)
366    {
367        for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
368        {
369            tickHalfAxis(joyStickAxes_[joyStick][i]);
370        }
371    }
372
373    void KeyBinder::tickHalfAxis(HalfAxis& halfAxis)
374    {
375        // button mode
376        // TODO: optimize out all the half axes that don't act as a button at the moment
377        if (halfAxis.hasChanged_)
378        {
379            if (!halfAxis.pressed_ && halfAxis.absVal_ > halfAxis.buttonThreshold_)
380            {
381                // key pressed event
382                halfAxis.pressed_ = true;
383                if (halfAxis.nCommands_[KeybindMode::OnPress])
384                    halfAxis.execute(KeybindMode::OnPress);
385            }
386            else if (halfAxis.pressed_ && halfAxis.absVal_ < halfAxis.buttonThreshold_)
387            {
388                // key released event
389                halfAxis.pressed_ = false;
390                if (halfAxis.nCommands_[KeybindMode::OnRelease])
391                    halfAxis.execute(KeybindMode::OnRelease);
392            }
393            halfAxis.hasChanged_ = false;
394        }
395
396        if (halfAxis.pressed_)
397        {
398            // key held event
399            if (halfAxis.nCommands_[KeybindMode::OnHold])
400                halfAxis.execute(KeybindMode::OnHold);
401        }
402
403        // these are the actually useful axis bindings for analog input
404        if (!bFilterAnalogNoise_ || halfAxis.relVal_ > analogThreshold_ || halfAxis.absVal_ > analogThreshold_)
405        {
406            halfAxis.execute();
407        }
408    }
409
410    /**
411    @brief
412        Event handler for the mouseMoved Event.
413    @param e
414        Mouse state information
415    */
416    void KeyBinder::mouseMoved(IntVector2 abs_, IntVector2 rel_, IntVector2 clippingSize)
417    {
418        // y axis of mouse input is inverted
419        int rel[] = { rel_.x, -rel_.y };
420
421        if (bDeriveMouseInput_)
422        {
423            mouseRelative_[0] += rel[0];
424            mouseRelative_[1] += rel[1];
425        }
426        else
427        {
428            for (int i = 0; i < 2; i++)
429            {
430                if (rel[i]) // performance opt. for the case that rel[i] == 0
431                {
432                    // write absolute values
433                    mouseAxes_[2*i + 0].hasChanged_ = true;
434                    mouseAxes_[2*i + 1].hasChanged_ = true;
435                    mousePosition_[i] += rel[i];
436
437                    // clip absolute position
438                    if (mousePosition_[i] > mouseClippingSize_)
439                        mousePosition_[i] =  mouseClippingSize_;
440                    if (mousePosition_[i] < -mouseClippingSize_)
441                        mousePosition_[i] = -mouseClippingSize_;
442
443                    if (mousePosition_[i] < 0)
444                    {
445                        mouseAxes_[2*i + 0].absVal_ =  -mousePosition_[i]/(float)mouseClippingSize_ * mouseSensitivity_;
446                        mouseAxes_[2*i + 1].absVal_ =  0.0f;
447                    }
448                    else
449                    {
450                        mouseAxes_[2*i + 0].absVal_ =  0.0f;
451                        mouseAxes_[2*i + 1].absVal_ =   mousePosition_[i]/(float)mouseClippingSize_ * mouseSensitivity_;
452                    }
453                }
454            }
455        }
456
457        // relative
458        for (int i = 0; i < 2; i++)
459        {
460            if (rel[i] < 0)
461                mouseAxes_[0 + 2*i].relVal_ = -((float)rel[i])/(float)mouseClippingSize_ * mouseSensitivity_;
462            else
463                mouseAxes_[1 + 2*i].relVal_ =  ((float)rel[i])/(float)mouseClippingSize_ * mouseSensitivity_;
464        }
465    }
466
467    /**
468    @brief Event handler for the mouseScrolled Event.
469    @param e Mouse state information
470    */
471    void KeyBinder::mouseScrolled(int abs, int rel)
472    {
473        if (rel < 0)
474            for (int i = 0; i < -rel/mouseWheelStepSize_; i++)
475                mouseButtons_[8].execute(KeybindMode::OnPress, ((float)abs)/mouseWheelStepSize_);
476        else
477            for (int i = 0; i < rel/mouseWheelStepSize_; i++)
478                mouseButtons_[9].execute(KeybindMode::OnPress, ((float)abs)/mouseWheelStepSize_);
479    }
480
481    void KeyBinder::joyStickAxisMoved(unsigned int joyStickID, unsigned int axis, float value)
482    {
483        int i = axis * 2;
484        if (value < 0)
485        {
486            joyStickAxes_[joyStickID][i].absVal_ = -value;
487            joyStickAxes_[joyStickID][i].relVal_ = -value;
488            joyStickAxes_[joyStickID][i].hasChanged_ = true;
489            if (joyStickAxes_[joyStickID][i + 1].absVal_ > 0.0f)
490            {
491                joyStickAxes_[joyStickID][i + 1].absVal_ = -0.0f;
492                joyStickAxes_[joyStickID][i + 1].relVal_ = -0.0f;
493                joyStickAxes_[joyStickID][i + 1].hasChanged_ = true;
494            }
495        }
496        else
497        {
498            joyStickAxes_[joyStickID][i + 1].absVal_ = value;
499            joyStickAxes_[joyStickID][i + 1].relVal_ = value;
500            joyStickAxes_[joyStickID][i + 1].hasChanged_ = true;
501            if (joyStickAxes_[joyStickID][i].absVal_ > 0.0f)
502            {
503                joyStickAxes_[joyStickID][i].absVal_ = -0.0f;
504                joyStickAxes_[joyStickID][i].relVal_ = -0.0f;
505                joyStickAxes_[joyStickID][i].hasChanged_ = true;
506            }
507        }
508    }
509}
Note: See TracBrowser for help on using the repository browser.