Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/consolecommands/src/libraries/core/input/Button.cc @ 6518

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

Merged core5 branch back to the trunk.
Key features include clean level unloading and an extended XML event system.

Two important notes:
Delete your keybindings.ini files! * or you will still get parser errors when loading the key bindings.
Delete build_dir/lib/modules/libgamestates.module! * or orxonox won't start.
Best thing to do is to delete the build folder ;)

  • Property svn:eol-style set to native
File size: 8.9 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
32    Implementation of the different input handlers.
33*/
34
35#include "Button.h"
36
37#include "util/Convert.h"
38#include "util/SubString.h"
39#include "util/StringUtils.h"
40#include "util/Debug.h"
41#include "core/ConsoleCommand.h"
42#include "core/CommandEvaluation.h"
43#include "core/CommandExecutor.h"
44#include "core/ConfigValueContainer.h"
45
46namespace orxonox
47{
48    /**
49    @note
50        bButtonThresholdUser_: We set it to true so that setConfigValues in KeyBinder sets the value
51        correctly the first time. It is then set to false first and changed later in Button::parse().
52    */
53    Button::Button()
54        : configContainer_(0)
55        , bButtonThresholdUser_(false)
56        , paramCommandBuffer_(0)
57    {
58        nCommands_[0]=0;
59        nCommands_[1]=0;
60        nCommands_[2]=0;
61    }
62
63    Button::~Button()
64    {
65        this->clear();
66
67        if (this->configContainer_)
68            delete this->configContainer_;
69    }
70
71    void Button::clear()
72    {
73        for (unsigned int j = 0; j < 3; j++)
74        {
75            if (nCommands_[j])
76            {
77                // delete all commands and the command pointer array
78                for (unsigned int i = 0; i < nCommands_[j]; i++)
79                    delete commands_[j][i];
80                delete[] commands_[j];
81                commands_[j] = 0;
82                nCommands_[j] = 0;
83            }
84        }
85    }
86
87    void Button::readConfigValue(ConfigFileType configFile)
88    {
89        // create/get ConfigValueContainer
90        if (!configContainer_)
91        {
92            configContainer_ = new ConfigValueContainer(configFile, 0, groupName_, name_, "", name_);
93            configContainer_->callback(this, &Button::parse);
94        }
95        configContainer_->getValue(&bindingString_, this);
96    }
97
98    void Button::parse()
99    {
100        // delete all commands
101        clear();
102
103        if (isEmpty(bindingString_))
104            return;
105
106        // reset this to false first when parsing (was true before when parsing for the first time)
107        bButtonThresholdUser_ = false;
108
109        // use std::vector for a temporary dynamic array
110        std::vector<BaseCommand*> commands[3];
111
112        // separate the commands
113        SubString commandStrings(bindingString_, "|", SubString::WhiteSpaces, false,
114            '\\', false, '"', false, '(', ')', false, '\0');
115
116        for (unsigned int iCommand = 0; iCommand < commandStrings.size(); iCommand++)
117        {
118            if (commandStrings[iCommand] != "")
119            {
120                SubString tokens(commandStrings[iCommand], " ", SubString::WhiteSpaces, false,
121                    '\\', false, '"', false, '(', ')', false, '\0');
122
123                KeybindMode::Value mode = KeybindMode::None;
124                float paramModifier = 1.0f;
125                std::string commandStr = "";
126
127                for (unsigned int iToken = 0; iToken < tokens.size(); ++iToken)
128                {
129                    std::string token = getLowercase(tokens[iToken]);
130
131                    if (token == "onpress")
132                        mode = KeybindMode::OnPress;
133                    else if (token == "onrelease")
134                        mode = KeybindMode::OnRelease;
135                    else if (token == "onhold")
136                        mode = KeybindMode::OnHold;
137                    else if (token == "buttonthreshold")
138                    {
139                        // for real axes, we can feed a ButtonThreshold argument
140                        ++iToken;
141                        if (iToken == tokens.size())
142                            continue;
143                        // may fail, but doesn't matter (default value already set)
144                        if (!convertValue(&buttonThreshold_, tokens[iToken + 1]))
145                            parseError("Could not parse 'ButtonThreshold' argument. \
146                                Switching to default value.", true);
147                        else
148                            this->bButtonThresholdUser_ = true;
149                    }
150                    else if (token == "scale")
151                    {
152                        ++iToken;
153                        if (iToken == tokens.size() || !convertValue(&paramModifier, tokens[iToken]))
154                            parseError("Could not parse 'scale' argument. Switching to default value.", true);
155                    }
156                    else
157                    {
158                        // no input related argument
159                        // we interpret everything from here as a command string
160                        while (iToken != tokens.size())
161                            commandStr += tokens[iToken++] + " ";
162                    }
163                }
164
165                if (commandStr == "")
166                {
167                    parseError("No command string given.", false);
168                    continue;
169                }
170
171                // evaluate the command
172                const CommandEvaluation& eval = CommandExecutor::evaluate(commandStr);
173                if (!eval.isValid())
174                {
175                    parseError("Command evaluation of \"" + commandStr + "\"failed.", true);
176                    continue;
177                }
178
179                // check for param command
180                int paramIndex = eval.getConsoleCommand()->getInputConfiguredParam_();
181                if (paramIndex >= 0)
182                {
183                    // parameter supported command
184                    ParamCommand* cmd = new ParamCommand();
185                    cmd->scale_ = paramModifier;
186
187                    // add command to the buffer if not yet existing
188                    for (unsigned int iParamCmd = 0; iParamCmd < paramCommandBuffer_->size(); iParamCmd++)
189                    {
190                        if ((*paramCommandBuffer_)[iParamCmd]->evaluation_.getConsoleCommand()
191                            == eval.getConsoleCommand())
192                        {
193                            // already in list
194                            cmd->paramCommand_ = (*paramCommandBuffer_)[iParamCmd];
195                            break;
196                        }
197                    }
198                    if (cmd->paramCommand_ == 0)
199                    {
200                        cmd->paramCommand_ = new BufferedParamCommand();
201                        paramCommandBuffer_->push_back(cmd->paramCommand_);
202                        cmd->paramCommand_->evaluation_ = eval;
203                        cmd->paramCommand_->paramIndex_ = paramIndex;
204                    }
205
206
207                    // we don't know whether this is an actual axis or just a button
208                    if (mode == KeybindMode::None)
209                    {
210                        if (!addParamCommand(cmd))
211                        {
212                            mode = eval.getConsoleCommand()->getKeybindMode();
213                            commands[mode].push_back(cmd);
214                        }
215                    }
216                }
217                else
218                {
219                    SimpleCommand* cmd = new SimpleCommand();
220                    cmd->evaluation_ = eval;
221
222                    if (mode == KeybindMode::None)
223                        mode = eval.getConsoleCommand()->getKeybindMode();
224
225                    commands[mode].push_back(cmd);
226                }
227            }
228        }
229
230        for (unsigned int j = 0; j < 3; j++)
231        {
232            nCommands_[j] = commands[j].size();
233            if (nCommands_[j])
234            {
235                commands_[j] = new BaseCommand*[nCommands_[j]];
236                for (unsigned int i = 0; i < commands[j].size(); i++)
237                    commands_[j][i] = commands[j][i];
238            }
239            else
240                commands_[j] = 0;
241        }
242    }
243
244    inline void Button::parseError(std::string message, bool serious)
245    {
246        if (serious)
247        {
248            COUT(2) << "Error while parsing binding for button/axis " << this->name_ << ". "
249                << message << std::endl;
250        }
251        else
252        {
253            COUT(3) << "Warning while parsing binding for button/axis " << this->name_ << ". "
254                << message << std::endl;
255        }
256    }
257}
Note: See TracBrowser for help on using the repository browser.