Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/input/src/core/Shell.cc @ 1637

Last change on this file since 1637 was 1637, checked in by rgrieder, 16 years ago

Finally! The InputManager is now working like I imagined it to. And it's even easier to use it as well.
A little explanation: Every time you change something about the input distribution, it is a change of 'state' represented by the class 'InputState'.
That can be for instance: "console", "game", "gui", etc. Every state has a name and a priority which describes who comes first. Now if one state doesn't handle mouse input or instance, then the one with the next lower priority gets it. To prevent that, you can add the 'EmptyHandler' to the state with setMouseHandler.
InputState is just an abstract base class. There are two classes implementing it: SimpleInputState and ExtendedInputState. The latter allows for multiple input handlers for one single device.

Basically, what you need to know is what you see in Orxonox.cc, InGameConsole.cc and Shell.cc.

  • Property svn:eol-style set to native
File size: 11.4 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 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "Shell.h"
30#include "CommandExecutor.h"
31#include "CoreIncludes.h"
32#include "ConfigValueIncludes.h"
33#include "Core.h"
34#include "ConsoleCommand.h"
35#include "input/InputInterfaces.h"
36#include "input/SimpleInputState.h"
37#include "input/InputManager.h"
38
39#define SHELL_UPDATE_LISTENERS(function) \
40    for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ) \
41        (*(it++))->function()
42
43namespace orxonox
44{
45    SetConsoleCommand(Shell, clearShell, true);
46    SetConsoleCommand(Shell, history, true);
47
48    Shell::Shell()
49    {
50        RegisterRootObject(Shell);
51
52        this->scrollPosition_ = 0;
53        this->maxHistoryLength_ = 100;
54        this->historyPosition_ = 0;
55        this->historyOffset_ = 0;
56        this->finishedLastLine_ = true;
57        this->bAddOutputLevel_ = false;
58
59        this->clearLines();
60
61        this->inputBuffer_ = new InputBuffer();
62        this->configureInputBuffer();
63        InputManager::createSimpleInputState("console", 40)->setKeyHandler(this->inputBuffer_);
64
65        this->outputBuffer_.registerListener(this);
66
67        this->setConfigValues();
68    }
69
70    Shell::~Shell()
71    {
72        SimpleInputState * inputState = dynamic_cast<SimpleInputState*>(InputManager::getState("console"));
73        if (inputState)
74        {
75            inputState->removeAndDestroyAllHandlers();
76            InputManager::destroyState("console");
77        }
78    }
79
80    Shell& Shell::createShell()
81    {
82        int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell);
83        Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
84        static Shell instance;
85        Core::setSoftDebugLevel(OutputHandler::LD_Shell, level);
86        return instance;
87    }
88
89    Shell& Shell::getInstance()
90    {
91        static Shell& instance = createShell();
92        return instance;
93    }
94
95    void Shell::setConfigValues()
96    {
97        SetConfigValue(maxHistoryLength_, 100);
98        SetConfigValue(historyOffset_, 0);
99        SetConfigValueVector(commandHistory_, std::vector<std::string>());
100
101        if (this->historyOffset_ >= this->maxHistoryLength_)
102            this->historyOffset_ = 0;
103
104        while (this->commandHistory_.size() > this->maxHistoryLength_)
105        {
106            unsigned int index = this->commandHistory_.size() - 1;
107            this->commandHistory_.erase(this->commandHistory_.begin() + index);
108            ModifyConfigValue(commandHistory_, remove, index);
109        }
110    }
111
112    void Shell::configureInputBuffer()
113    {
114        this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
115        this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
116        this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
117        this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
118        this->inputBuffer_->registerListener(this, &Shell::deletechar, KeyCode::Delete);
119        this->inputBuffer_->registerListener(this, &Shell::exit, (char)27, true);
120        this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
121        this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
122        this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
123        this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
124        this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
125        this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
126        this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
127        this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
128    }
129
130    void Shell::clearShell()
131    {
132        Shell::getInstance().clearLines();
133    }
134
135    void Shell::history()
136    {
137        Shell& instance = Shell::getInstance();
138
139        for (int i = instance.historyOffset_; i < (int)instance.commandHistory_.size(); ++i)
140            instance.addLine(instance.commandHistory_[i], -1);
141        for (int i =  0; i < (int)instance.historyOffset_; ++i)
142            instance.addLine(instance.commandHistory_[i], -1);
143    }
144
145    void Shell::registerListener(ShellListener* listener)
146    {
147        this->listeners_.insert(this->listeners_.end(), listener);
148    }
149
150    void Shell::unregisterListener(ShellListener* listener)
151    {
152        for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); )
153        {
154            if ((*it) == listener)
155                this->listeners_.erase(it++);
156            else
157                ++it;
158        }
159    }
160
161    void Shell::setCursorPosition(unsigned int cursor)
162    {
163        this->inputBuffer_->setCursorPosition(cursor);
164        SHELL_UPDATE_LISTENERS(cursorChanged);
165    }
166
167    void Shell::setInput(const std::string& input)
168    {
169        this->inputBuffer_->set(input);
170        this->inputChanged();
171    }
172
173    void Shell::addLine(const std::string& line, int level)
174    {
175        int original_level = OutputHandler::getOutStream().getOutputLevel();
176        OutputHandler::getOutStream().setOutputLevel(level);
177
178        if (!this->finishedLastLine_)
179            this->outputBuffer_ << std::endl;
180
181        this->outputBuffer_ << line << std::endl;
182        OutputHandler::getOutStream().setOutputLevel(original_level);
183    }
184
185    void Shell::clearLines()
186    {
187        this->lines_.clear();
188        this->scrollIterator_ = this->lines_.begin();
189
190        this->scrollPosition_ = 0;
191        this->finishedLastLine_ = true;
192
193        SHELL_UPDATE_LISTENERS(linesChanged);
194    }
195
196    std::list<std::string>::const_iterator Shell::getNewestLineIterator() const
197    {
198        if (this->scrollPosition_)
199            return this->scrollIterator_;
200        else
201            return this->lines_.begin();
202    }
203
204    std::list<std::string>::const_iterator Shell::getEndIterator() const
205    {
206        return this->lines_.end();
207    }
208
209    void Shell::addToHistory(const std::string& command)
210    {
211        ModifyConfigValue(commandHistory_, set, this->historyOffset_, command);
212        this->historyPosition_ = 0;
213        ModifyConfigValue(historyOffset_, set, (this->historyOffset_ + 1) % this->maxHistoryLength_);
214    }
215
216    std::string Shell::getFromHistory() const
217    {
218        unsigned int index = mod(((int)this->historyOffset_) - ((int)this->historyPosition_), this->maxHistoryLength_);
219        if (index < this->commandHistory_.size() && this->historyPosition_ != 0)
220            return this->commandHistory_[index];
221        else
222            return "";
223    }
224
225    void Shell::outputChanged()
226    {
227        std::string output;
228        bool newline;
229        do
230        {
231            newline = this->outputBuffer_.getLine(&output);
232
233            if (!newline && output == "")
234                break;
235
236            if (this->finishedLastLine_)
237            {
238                if (this->bAddOutputLevel_)
239                    output.insert(0, 1, (char)OutputHandler::getOutStream().getOutputLevel());
240
241                this->lines_.insert(this->lines_.begin(), output);
242
243                if (this->scrollPosition_)
244                    this->scrollPosition_++;
245                else
246                    this->scrollIterator_ = this->lines_.begin();
247
248                this->finishedLastLine_ = newline;
249
250                if (!this->scrollPosition_)
251                {
252                    SHELL_UPDATE_LISTENERS(lineAdded);
253                }
254            }
255            else
256            {
257                (*this->lines_.begin()) += output;
258                this->finishedLastLine_ = newline;
259                SHELL_UPDATE_LISTENERS(onlyLastLineChanged);
260            }
261
262        } while (newline);
263    }
264
265    void Shell::inputChanged()
266    {
267        SHELL_UPDATE_LISTENERS(inputChanged);
268        SHELL_UPDATE_LISTENERS(cursorChanged);
269    }
270
271    void Shell::execute()
272    {
273        this->addToHistory(this->inputBuffer_->get());
274        this->addLine(this->inputBuffer_->get(), 0);
275
276        if (!CommandExecutor::execute(this->inputBuffer_->get()))
277            this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
278
279        this->clear();
280    }
281
282    void Shell::hintandcomplete()
283    {
284        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
285        this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
286
287        this->inputChanged();
288    }
289
290    void Shell::backspace()
291    {
292        this->inputBuffer_->removeBehindCursor();
293        SHELL_UPDATE_LISTENERS(inputChanged);
294        SHELL_UPDATE_LISTENERS(cursorChanged);
295    }
296
297    void Shell::deletechar()
298    {
299        this->inputBuffer_->removeAtCursor();
300        SHELL_UPDATE_LISTENERS(inputChanged);
301    }
302
303    void Shell::clear()
304    {
305        this->inputBuffer_->clear();
306        this->historyPosition_ = 0;
307        SHELL_UPDATE_LISTENERS(inputChanged);
308        SHELL_UPDATE_LISTENERS(cursorChanged);
309    }
310
311    void Shell::cursor_right()
312    {
313        this->inputBuffer_->increaseCursor();
314        SHELL_UPDATE_LISTENERS(cursorChanged);
315    }
316
317    void Shell::cursor_left()
318    {
319        this->inputBuffer_->decreaseCursor();
320        SHELL_UPDATE_LISTENERS(cursorChanged);
321    }
322
323    void Shell::cursor_end()
324    {
325        this->inputBuffer_->setCursorToEnd();
326        SHELL_UPDATE_LISTENERS(cursorChanged);
327    }
328
329    void Shell::cursor_home()
330    {
331        this->inputBuffer_->setCursorToBegin();
332        SHELL_UPDATE_LISTENERS(cursorChanged);
333    }
334
335    void Shell::history_up()
336    {
337        if (this->historyPosition_ < this->commandHistory_.size())
338        {
339            this->historyPosition_++;
340            this->inputBuffer_->set(this->getFromHistory());
341        }
342    }
343
344    void Shell::history_down()
345    {
346        if (this->historyPosition_ > 0)
347        {
348            this->historyPosition_--;
349            this->inputBuffer_->set(this->getFromHistory());
350        }
351    }
352
353    void Shell::scroll_up()
354    {
355        if (this->scrollIterator_ != this->lines_.end())
356        {
357            ++this->scrollIterator_;
358            ++this->scrollPosition_;
359
360            SHELL_UPDATE_LISTENERS(linesChanged);
361        }
362    }
363
364    void Shell::scroll_down()
365    {
366        if (this->scrollIterator_ != this->lines_.begin())
367        {
368            --this->scrollIterator_;
369            --this->scrollPosition_;
370
371            SHELL_UPDATE_LISTENERS(linesChanged);
372        }
373    }
374
375    void Shell::exit()
376    {
377        if (this->inputBuffer_->getSize() > 0)
378        {
379            this->clear();
380            return;
381        }
382
383        this->clear();
384        this->scrollPosition_ = 0;
385        this->scrollIterator_ = this->lines_.begin();
386
387        SHELL_UPDATE_LISTENERS(exit);
388    }
389}
Note: See TracBrowser for help on using the repository browser.