Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 8222 was 8079, checked in by landauf, 14 years ago

merged usability branch back to trunk

incomplete summary of the changes in this branch:

  • enhanced keyboard navigation in GUIs
  • implemented new graphics menu and changeable window size at runtime
  • added developer mode
  • HUD shows if game is paused, game pauses if ingame menu is opened
  • removed a few obsolete commands and hid some that are more for internal use
  • numpad works in console and gui
  • faster loading of level info
  • enhanced usage of compositors (Shader class)
  • improved camera handling, configurable FOV and aspect ratio
  • Property svn:eol-style set to native
File size: 25.2 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#include "KeyBinder.h"
30
31#include <algorithm>
32#include <sstream>
33#include "util/Convert.h"
34#include "util/Debug.h"
35#include "util/Exception.h"
36#include "core/ConfigValueIncludes.h"
37#include "core/CoreIncludes.h"
38#include "core/ConfigFileManager.h"
39#include "core/PathConfig.h"
40#include "InputCommands.h"
41#include "JoyStick.h"
42
43namespace orxonox
44{
45    /**
46    @brief
47        Constructor that does as little as necessary.
48    */
49    KeyBinder::KeyBinder(const std::string& filename)
50        : deriveTime_(0.0f)
51        , filename_(filename)
52        , configFile_(NULL)
53        , fallbackConfigFile_(NULL)
54    {
55        mouseRelative_[0] = 0;
56        mouseRelative_[1] = 0;
57        mousePosition_[0] = 0.0;
58        mousePosition_[1] = 0.0;
59
60        RegisterRootObject(KeyBinder);
61
62        // initialise all buttons and half axes to avoid creating everything with 'new'
63        // keys
64        for (unsigned int i = 0; i < KeyCode::numberOfKeys; i++)
65        {
66            const std::string& keyname = KeyCode::ByString[i];
67            if (!keyname.empty())
68                keys_[i].name_ = std::string("Key") + keyname;
69            else
70                keys_[i].name_.clear();
71            keys_[i].paramCommandBuffer_ = &paramCommandBuffer_;
72            keys_[i].groupName_ = "Keys";
73        }
74        // mouse buttons plus 4 mouse wheel buttons only 'generated' by KeyBinder
75        const char* const mouseWheelNames[] = { "Wheel1Down", "Wheel1Up", "Wheel2Down", "Wheel2Up" };
76        for (unsigned int i = 0; i < numberOfMouseButtons_; i++)
77        {
78            std::string nameSuffix;
79            if (i < MouseButtonCode::numberOfButtons)
80                nameSuffix = MouseButtonCode::ByString[i];
81            else
82                nameSuffix = mouseWheelNames[i - MouseButtonCode::numberOfButtons];
83            mouseButtons_[i].name_ = nameSuffix;
84            mouseButtons_[i].paramCommandBuffer_ = &paramCommandBuffer_;
85            mouseButtons_[i].groupName_ = "MouseButtons";
86        }
87        // mouse axes
88        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
89        {
90            mouseAxes_[i].name_ = MouseAxisCode::ByString[i / 2];
91            if (i & 1)
92                mouseAxes_[i].name_ += "Pos";
93            else
94                mouseAxes_[i].name_ += "Neg";
95            mouseAxes_[i].paramCommandBuffer_ = &paramCommandBuffer_;
96            mouseAxes_[i].groupName_ = "MouseAxes";
97        }
98
99        // initialise joy sticks separatly to allow for reloading
100        this->JoyStickQuantityChanged(this->getJoyStickList());
101
102        // set them here to use allHalfAxes_
103        setConfigValues();
104
105        // Load the bindings if filename was given
106        if (!this->filename_.empty())
107            this->loadBindings();
108    }
109
110    /**
111    @brief
112        Destructor
113    */
114    KeyBinder::~KeyBinder()
115    {
116        // almost no destructors required because most of the arrays are static.
117        clearBindings(); // does some destruction work
118        if (this->configFile_)
119            delete this->configFile_;
120        if (this->fallbackConfigFile_)
121            delete this->fallbackConfigFile_;
122    }
123
124    /**
125    @brief
126        Loader for the key bindings, managed by config values.
127    */
128    void KeyBinder::setConfigValues()
129    {
130        SetConfigValue(analogThreshold_, 0.05f)
131            .description("Threshold for analog axes until which the state is 0.");
132        SetConfigValue(bFilterAnalogNoise_, false)
133            .description("Specifies whether to filter small analog values like joy stick fluctuations.");
134        SetConfigValue(mouseSensitivity_, 3.0f)
135            .description("Mouse sensitivity.");
136        this->totalMouseSensitivity_ = this->mouseSensitivity_ / this->mouseClippingSize_;
137        SetConfigValue(bDeriveMouseInput_, false)
138            .description("Whether or not to derive moues movement for the absolute value.");
139        SetConfigValue(derivePeriod_, 0.05f)
140            .description("Accuracy of the mouse input deriver. The higher the more precise, but laggier.");
141        SetConfigValue(mouseSensitivityDerived_, 1.0f)
142            .description("Mouse sensitivity if mouse input is derived.");
143        SetConfigValue(mouseWheelStepSize_, 120)
144            .description("Equals one step of the mousewheel.");
145        SetConfigValue(buttonThreshold_, 0.80f)
146            .description("Threshold for analog axes until which the button is not pressed.")
147            .callback(this, &KeyBinder::buttonThresholdChanged);
148    }
149
150    void KeyBinder::buttonThresholdChanged()
151    {
152        for (unsigned int i = 0; i < allHalfAxes_.size(); i++)
153            if (!allHalfAxes_[i]->bButtonThresholdUser_)
154                allHalfAxes_[i]->buttonThreshold_ = this->buttonThreshold_;
155    }
156
157    void KeyBinder::JoyStickQuantityChanged(const std::vector<JoyStick*>& joyStickList)
158    {
159        unsigned int oldValue = joySticks_.size();
160        joySticks_ = joyStickList;
161
162        // initialise joy stick bindings
163        initialiseJoyStickBindings();
164
165        // collect all Buttons and HalfAxes again
166        compilePointerLists();
167
168        // load the bindings if required
169        if (configFile_ != NULL)
170        {
171            for (unsigned int iDev = oldValue; iDev < joySticks_.size(); ++iDev)
172            {
173                for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; ++i)
174                    (*joyStickButtons_[iDev])[i].readBinding(this->configFile_, this->fallbackConfigFile_);
175                for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; ++i)
176                    (*joyStickAxes_[iDev])[i].readBinding(this->configFile_, this->fallbackConfigFile_);
177            }
178        }
179
180        // Set the button threshold for potential new axes
181        buttonThresholdChanged();
182    }
183
184    void KeyBinder::initialiseJoyStickBindings()
185    {
186        while (joyStickAxes_.size() < joySticks_.size())
187            joyStickAxes_.push_back(shared_ptr<JoyStickAxisVector>(new JoyStickAxisVector()));
188        while (joyStickButtons_.size() < joySticks_.size())
189            joyStickButtons_.push_back(shared_ptr<JoyStickButtonVector>(new JoyStickButtonVector()));
190        // For the case the new size is smaller
191        this->joyStickAxes_.resize(joySticks_.size());
192        this->joyStickButtons_.resize(joySticks_.size());
193
194        // reinitialise all joy stick bindings (doesn't overwrite the old ones)
195        for (unsigned int iDev = 0; iDev < joySticks_.size(); iDev++)
196        {
197            const std::string& deviceName = joySticks_[iDev]->getDeviceName();
198            // joy stick buttons
199            for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; i++)
200            {
201                (*joyStickButtons_[iDev])[i].name_ = JoyStickButtonCode::ByString[i];
202                (*joyStickButtons_[iDev])[i].paramCommandBuffer_ = &paramCommandBuffer_;
203                (*joyStickButtons_[iDev])[i].groupName_ = "JoyStickButtons_" + deviceName;
204            }
205            // joy stick axes
206            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
207            {
208                (*joyStickAxes_[iDev])[i].name_ = JoyStickAxisCode::ByString[i / 2];
209                if (i & 1)
210                    (*joyStickAxes_[iDev])[i].name_ += "Pos";
211                else
212                    (*joyStickAxes_[iDev])[i].name_ += "Neg";
213                (*joyStickAxes_[iDev])[i].paramCommandBuffer_ = &paramCommandBuffer_;
214                (*joyStickAxes_[iDev])[i].groupName_ = "JoyStickAxes_" + deviceName;
215            }
216        }
217    }
218
219    void KeyBinder::compilePointerLists()
220    {
221        allButtons_.clear();
222        allHalfAxes_.clear();
223
224        // Note: Don't include the dummy keys which don't actually exist in OIS but have a number
225        for (unsigned int i = 0; i < KeyCode::numberOfKeys; i++)
226            if (!keys_[i].name_.empty())
227                allButtons_[keys_[i].groupName_ + '.' + keys_[i].name_] = keys_ + i;
228        for (unsigned int i = 0; i < numberOfMouseButtons_; i++)
229            allButtons_[mouseButtons_[i].groupName_ + '.' + mouseButtons_[i].name_] = mouseButtons_ + i;
230        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
231        {
232            allButtons_[mouseAxes_[i].groupName_ + '.' + mouseAxes_[i].name_] = mouseAxes_ + i;
233            allHalfAxes_.push_back(mouseAxes_ + i);
234        }
235        for (unsigned int iDev = 0; iDev < joySticks_.size(); iDev++)
236        {
237            for (unsigned int i = 0; i < JoyStickButtonCode::numberOfButtons; i++)
238                allButtons_[(*joyStickButtons_[iDev])[i].groupName_ + '.' + (*joyStickButtons_[iDev])[i].name_] = &((*joyStickButtons_[iDev])[i]);
239            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
240            {
241                allButtons_[(*joyStickAxes_[iDev])[i].groupName_ + '.' + (*joyStickAxes_[iDev])[i].name_] = &((*joyStickAxes_[iDev])[i]);
242                allHalfAxes_.push_back(&((*joyStickAxes_[iDev])[i]));
243            }
244        }
245    }
246
247    /**
248    @brief
249        Loads the key and button bindings.
250    */
251    void KeyBinder::loadBindings()
252    {
253        COUT(3) << "KeyBinder: Loading key bindings..." << std::endl;
254
255        this->configFile_ = new ConfigFile(this->filename_, !PathConfig::isDevelopmentRun());
256        this->configFile_->load();
257
258        if (PathConfig::isDevelopmentRun())
259        {
260            // Dev users should have combined key bindings files
261            std::string defaultFilepath(PathConfig::getDataPathString() + ConfigFile::DEFAULT_CONFIG_FOLDER + '/' + this->filename_);
262            std::ifstream file(defaultFilepath.c_str());
263            if (file.is_open())
264            {
265                file.close();
266                // Open the default file for later use (use absolute path!)
267                this->fallbackConfigFile_ = new ConfigFile(defaultFilepath, false);
268                this->fallbackConfigFile_->load();
269            }
270        }
271
272        // Parse bindings and create the ConfigValueContainers if necessary
273        for (std::map<std::string, Button*>::const_iterator it = allButtons_.begin(); it != allButtons_.end(); ++it)
274        {
275            it->second->readBinding(this->configFile_, this->fallbackConfigFile_);
276            addButtonToCommand(it->second->bindingString_, it->second);
277        }
278
279        COUT(3) << "KeyBinder: Loading key bindings done." << std::endl;
280    }
281
282    bool KeyBinder::setBinding(const std::string& binding, const std::string& name, bool bTemporary)
283    {
284        std::map<std::string, Button*>::iterator it = allButtons_.find(name);
285        if (it != allButtons_.end())
286        {
287            addButtonToCommand(binding, it->second);
288            std::string str = binding;
289            if (PathConfig::isDevelopmentRun() && binding.empty())
290                str = "NoBinding";
291            it->second->setBinding(this->configFile_, this->fallbackConfigFile_, binding, bTemporary);
292            return true;
293        }
294        else
295        {
296            COUT(2) << "Could not find key/button/axis with name '" << name << "'." << std::endl;
297            return false;
298        }
299    }
300
301     void KeyBinder::addButtonToCommand(const std::string& command, Button* button)
302     {
303        std::ostringstream stream;
304        stream << button->groupName_  << '.' << button->name_;
305
306        std::vector<std::string>& oldKeynames = this->allCommands_[button->bindingString_];
307        std::vector<std::string>::iterator it = std::find(oldKeynames.begin(), oldKeynames.end(), stream.str());
308        if (it != oldKeynames.end())
309            oldKeynames.erase(it);
310
311        if (!command.empty())
312        {
313            std::vector<std::string>& keynames = this->allCommands_[command];
314            if (std::find(keynames.begin(), keynames.end(), stream.str()) == keynames.end())
315                this->allCommands_[command].push_back(stream.str());
316        }
317     }
318
319    /**
320    @brief
321        Return the first key name for a specific command
322    */
323    const std::string& KeyBinder::getBinding(const std::string& commandName)
324    {
325        if (this->allCommands_.find(commandName) != this->allCommands_.end())
326        {
327            std::vector<std::string>& keynames = this->allCommands_[commandName];
328            return keynames.front();
329        }
330
331        return BLANKSTRING;
332    }
333
334    /**
335    @brief
336        Return the key name for a specific command at a given index.
337    @param commandName
338        The command name the key name is returned for.
339    @param index
340        The index at which the key name is returned for.
341    */
342    const std::string& KeyBinder::getBinding(const std::string& commandName, unsigned int index)
343    {
344        if (this->allCommands_.find(commandName) != this->allCommands_.end())
345        {
346            std::vector<std::string>& keynames = this->allCommands_[commandName];
347            if (index < keynames.size())
348                return keynames[index];
349
350            return BLANKSTRING;
351        }
352
353        return BLANKSTRING;
354    }
355
356    /**
357    @brief
358        Get the number of different key bindings of a specific command.
359    @param commandName
360        The command.
361    */
362    unsigned int KeyBinder::getNumberOfBindings(const std::string& commandName)
363    {
364        if (this->allCommands_.find(commandName) != this->allCommands_.end())
365        {
366            std::vector<std::string>& keynames = this->allCommands_[commandName];
367            return keynames.size();
368        }
369
370        return 0;
371    }
372
373    /**
374    @brief
375        Overwrites all bindings with ""
376    */
377    void KeyBinder::clearBindings()
378    {
379        for (std::map<std::string, Button*>::const_iterator it = allButtons_.begin(); it != allButtons_.end(); ++it)
380            it->second->clear();
381
382        for (unsigned int i = 0; i < paramCommandBuffer_.size(); i++)
383            delete paramCommandBuffer_[i];
384        paramCommandBuffer_.clear();
385    }
386
387    /**
388        @brief Changes the keybind mode of a given console command.
389    */
390    void KeyBinder::changeMode(ConsoleCommand* command, KeybindMode::Value new_mode)
391    {
392        // iterate over all buttons
393        for (std::map<std::string, Button*>::iterator it = this->allButtons_.begin(); it != this->allButtons_.end(); ++it)
394        {
395            Button* button = it->second;
396
397            // iterate over all modes
398            for (size_t mode_index = 0; mode_index < 3; ++mode_index)
399            {
400                if (mode_index == (unsigned int)new_mode) // skip commands that are already in the desired mode
401                    continue;
402
403                // iterate over all commands of the given mode at the given button
404                for (size_t command_index = 0; command_index < button->nCommands_[mode_index]; ++command_index)
405                {
406                    if (button->commands_[mode_index][command_index]->hasFixedKeybindMode())
407                        continue;
408
409                    CommandEvaluation* evaluation = button->commands_[mode_index][command_index]->getEvaluation();
410
411                    // compare the command
412                    if (evaluation && evaluation->getConsoleCommand() == command)
413                    {
414                        // increase array of new mode
415                        BaseCommand** array_new_mode = new BaseCommand*[button->nCommands_[new_mode] + 1];
416                        // copy array content
417                        for (size_t c = 0; c < button->nCommands_[new_mode]; ++c)
418                            array_new_mode[c] = button->commands_[new_mode][c];
419                        // insert changed command at the end
420                        array_new_mode[button->nCommands_[new_mode]] = button->commands_[mode_index][command_index];
421                        // delete old array
422                        delete[] button->commands_[new_mode];
423                        // assign new array
424                        button->commands_[new_mode] = array_new_mode;
425                        // increase counter
426                        button->nCommands_[new_mode]++;
427
428                        // erase command from old array
429                        for (size_t c = command_index; c < button->nCommands_[mode_index] - 1; ++c)
430                            button->commands_[mode_index][c] = button->commands_[mode_index][c + 1];
431                        // decrease counter
432                        button->nCommands_[mode_index]--;
433                        // old array would not get deleted if nCommands_ is now 0
434                        // otherwise: nobody cares about an array that is one element too large - nCommands_ defines the size
435                        if (button->nCommands_[mode_index] == 0)
436                        {
437                            delete[] button->commands_[mode_index];
438                            button->commands_[mode_index] = 0;
439                        }
440
441                        // decrement the index since we shifted the array and continue searching for more occurrences of the command
442                        command_index--;
443                    }
444                }
445            }
446        }
447    }
448
449    void KeyBinder::resetJoyStickAxes()
450    {
451        for (unsigned int iDev = 0; iDev < joySticks_.size(); ++iDev)
452            for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
453                (*joyStickAxes_[iDev])[i].reset();
454    }
455
456    /**
457        @brief Sets the position of the mouse back to 0/0.
458    */
459    void KeyBinder::resetMouseAxes()
460    {
461        this->mousePosition_[0] = 0.0f;
462        this->mousePosition_[1] = 0.0f;
463
464        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
465            mouseAxes_[i].reset();
466    }
467
468    void KeyBinder::mouseUpdated(float dt)
469    {
470        if (bDeriveMouseInput_)
471        {
472            // only update when derivation dt has passed
473            if (deriveTime_ > derivePeriod_)
474            {
475                for (int i = 0; i < 2; i++)
476                {
477                    if (mouseRelative_[i] < 0)
478                    {
479                        mouseAxes_[2*i + 0].absVal_
480                            = -mouseRelative_[i] / deriveTime_ * 0.0005f * mouseSensitivityDerived_;
481                        mouseAxes_[2*i + 1].absVal_ = 0.0f;
482                    }
483                    else if (mouseRelative_[i] > 0)
484                    {
485                        mouseAxes_[2*i + 0].absVal_ = 0.0f;
486                        mouseAxes_[2*i + 1].absVal_
487                            =  mouseRelative_[i] / deriveTime_ * 0.0005f * mouseSensitivityDerived_;
488                    }
489                    else
490                    {
491                        mouseAxes_[2*i + 0].absVal_ = 0.0f;
492                        mouseAxes_[2*i + 1].absVal_ = 0.0f;
493                    }
494                    mouseRelative_[i] = 0;
495                    mouseAxes_[2*i + 0].hasChanged_ = true;
496                    mouseAxes_[2*i + 1].hasChanged_ = true;
497                }
498                deriveTime_ = 0.0f;
499            }
500            else
501                deriveTime_ += dt;
502        }
503
504        for (unsigned int i = 0; i < MouseAxisCode::numberOfAxes * 2; i++)
505        {
506            // Why dividing relative value by dt? The reason lies in the simple fact, that when you
507            // press a button that has relative movement, that value has to be multiplied by dt to be
508            // frame rate independent. This can easily (and only) be done in updateInput(float).
509            // Hence we need to divide by dt here for the mouse to compensate, because the relative
510            // move movements have nothing to do with dt.
511            if (dt != 0.0f)
512            {
513                // just ignore if dt == 0.0 because we have multiplied by 0.0 anyway..
514                mouseAxes_[i].relVal_ /= dt;
515            }
516
517            tickHalfAxis(mouseAxes_[i]);
518        }
519    }
520
521    void KeyBinder::joyStickUpdated(unsigned int joyStick, float dt)
522    {
523        for (unsigned int i = 0; i < JoyStickAxisCode::numberOfAxes * 2; i++)
524        {
525            tickHalfAxis((*joyStickAxes_[joyStick])[i]);
526        }
527    }
528
529    void KeyBinder::tickHalfAxis(HalfAxis& halfAxis)
530    {
531        // button mode
532        // TODO: optimize out all the half axes that don't act as a button at the moment
533        if (halfAxis.hasChanged_)
534        {
535            if (!halfAxis.pressed_ && halfAxis.absVal_ > halfAxis.buttonThreshold_)
536            {
537                // key pressed event
538                halfAxis.pressed_ = true;
539                if (halfAxis.nCommands_[KeybindMode::OnPress])
540                    halfAxis.execute(KeybindMode::OnPress);
541            }
542            else if (halfAxis.pressed_ && halfAxis.absVal_ < halfAxis.buttonThreshold_)
543            {
544                // key released event
545                halfAxis.pressed_ = false;
546                if (halfAxis.nCommands_[KeybindMode::OnRelease])
547                    halfAxis.execute(KeybindMode::OnRelease);
548            }
549            halfAxis.hasChanged_ = false;
550        }
551
552        if (halfAxis.pressed_)
553        {
554            // key held event
555            if (halfAxis.nCommands_[KeybindMode::OnHold])
556                halfAxis.execute(KeybindMode::OnHold);
557        }
558
559        // these are the actually useful axis bindings for analog input
560        halfAxis.execute();
561    }
562
563    /**
564    @brief
565        Event handler for the mouseMoved Event.
566    @param abs_
567        The absolute position of the mouse
568    @param rel_
569        The relative movement of the mouse
570    @param clippingSize
571        Mouse screen area in pixels (usually 1024x1024)
572    */
573    void KeyBinder::mouseMoved(IntVector2 abs_, IntVector2 rel_, IntVector2 clippingSize)
574    {
575        // y axis of mouse input is inverted
576        int rel[] = { rel_.x, -rel_.y };
577
578        if (bDeriveMouseInput_)
579        {
580            mouseRelative_[0] += rel[0];
581            mouseRelative_[1] += rel[1];
582        }
583        else
584        {
585            for (int i = 0; i < 2; i++)
586            {
587                if (rel[i]) // performance opt. for the case that rel[i] == 0
588                {
589                    // write absolute values
590                    mouseAxes_[2*i + 0].hasChanged_ = true;
591                    mouseAxes_[2*i + 1].hasChanged_ = true;
592                    mousePosition_[i] += rel[i] * totalMouseSensitivity_;
593
594                    // clip absolute position
595                    if (mousePosition_[i] > 1.0)
596                        mousePosition_[i] =  1.0;
597                    if (mousePosition_[i] < -1.0)
598                        mousePosition_[i] = -1.0;
599
600                    if (mousePosition_[i] < 0.0)
601                    {
602                        mouseAxes_[2*i + 0].absVal_ = -mousePosition_[i];
603                        mouseAxes_[2*i + 1].absVal_ = 0.0f;
604                    }
605                    else
606                    {
607                        mouseAxes_[2*i + 0].absVal_ = 0.0f;
608                        mouseAxes_[2*i + 1].absVal_ =  mousePosition_[i];
609                    }
610                }
611            }
612        }
613
614        // relative
615        for (int i = 0; i < 2; i++)
616        {
617            if (rel[i] < 0)
618                mouseAxes_[0 + 2*i].relVal_ = -rel[i] * totalMouseSensitivity_;
619            else
620                mouseAxes_[1 + 2*i].relVal_ =  rel[i] * totalMouseSensitivity_;
621        }
622    }
623
624    /**
625    @brief Event handler for the mouseScrolled Event.
626    @param abs The absolute position of the scroll wheel
627    @param rel The relative movement of the scroll wheel
628    */
629    void KeyBinder::mouseScrolled(int abs, int rel)
630    {
631        if (rel < 0)
632            for (int i = 0; i < -rel/mouseWheelStepSize_; i++)
633                mouseButtons_[8].execute(KeybindMode::OnPress, static_cast<float>(abs)/mouseWheelStepSize_);
634        else
635            for (int i = 0; i < rel/mouseWheelStepSize_; i++)
636                mouseButtons_[9].execute(KeybindMode::OnPress, static_cast<float>(abs)/mouseWheelStepSize_);
637    }
638
639    void KeyBinder::axisMoved(unsigned int device, unsigned int axisID, float value)
640    {
641        // Filter analog noise
642        if (this->bFilterAnalogNoise_ && std::abs(value) < this->analogThreshold_)
643            value = 0.0;
644        int i = axisID * 2;
645        JoyStickAxisVector& axis = *joyStickAxes_[device];
646        if (value < 0)
647        {
648            axis[i].absVal_ = -value;
649            axis[i].relVal_ = -value;
650            axis[i].hasChanged_ = true;
651            if (axis[i + 1].absVal_ > 0.0f)
652            {
653                axis[i + 1].absVal_ = -0.0f;
654                axis[i + 1].relVal_ = -0.0f;
655                axis[i + 1].hasChanged_ = true;
656            }
657        }
658        else
659        {
660            axis[i + 1].absVal_ = value;
661            axis[i + 1].relVal_ = value;
662            axis[i + 1].hasChanged_ = true;
663            if (axis[i].absVal_ > 0.0f)
664            {
665                axis[i].absVal_ = -0.0f;
666                axis[i].relVal_ = -0.0f;
667                axis[i].hasChanged_ = true;
668            }
669        }
670    }
671}
Note: See TracBrowser for help on using the repository browser.