Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/console/src/libraries/core/IOConsole.cc @ 5974

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

Fixed low fps problem when the console is running (removed timeout that previously idled the second thread)

  • Property svn:eol-style set to native
File size: 9.3 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 *      Oliver Scheuss
24 *      Reto Grieder
25 *   Co-authors:
26 *      ...
27 *
28 */
29
30#include "IOConsole.h"
31
32#include <cstring>
33#include <iomanip>
34#include <iostream>
35
36#include "util/Clock.h"
37#include "util/Debug.h"
38#include "util/Sleep.h"
39#include "core/CommandExecutor.h"
40#include "core/Game.h"
41#include "core/GameMode.h"
42#include "core/Shell.h"
43#include "core/input/InputBuffer.h"
44
45#ifdef ORXONOX_PLATFORM_UNIX
46#include <termios.h>
47#endif
48
49namespace orxonox
50{
51    IOConsole* IOConsole::singletonPtr_s = NULL;
52
53#ifdef ORXONOX_PLATFORM_UNIX
54
55    termios* IOConsole::originalTerminalSettings_;
56
57    IOConsole::IOConsole()
58        : shell_(Shell::getInstance())
59        , bEscapeMode_(false)
60        , buffer_(Shell::getInstance().getInputBuffer())
61    {
62        this->originalTerminalSettings_ = new termios;
63        this->setTerminalMode();
64    }
65
66    IOConsole::~IOConsole()
67    {
68        std::cout << "\033[0G\033[K";
69        std::cout.flush();
70        resetTerminalMode();
71        delete this->originalTerminalSettings_;
72        COUT(0) << "Press enter to end the game..." << std::endl;
73    }
74
75    void IOConsole::setTerminalMode()
76    {
77        termios new_settings;
78
79        tcgetattr(0, this->originalTerminalSettings_);
80        new_settings = *this->originalTerminalSettings_;
81        new_settings.c_lflag &= ~(ICANON | ECHO);
82        //         new_settings.c_lflag |= ( ISIG | IEXTEN );
83        new_settings.c_cc[VTIME] = 0;
84        new_settings.c_cc[VMIN]  = 0;
85        tcsetattr(0, TCSANOW, &new_settings);
86        COUT(0) << endl;
87        //       atexit(&IOConsole::resetTerminalMode);
88    }
89
90    void IOConsole::resetTerminalMode()
91    {
92        tcsetattr(0, TCSANOW, IOConsole::originalTerminalSettings_);
93    }
94
95    void IOConsole::update(const Clock& time)
96    {
97        unsigned char c;
98        while (read(STDIN_FILENO, &c, 1) == 1)
99        {
100            if (this->bEscapeMode_)
101            {
102                this->escapeSequence_ += c;
103                bool endOfSeq = true;
104                if      (this->escapeSequence_ == "[A")
105                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Up,       0, 0));
106                else if (this->escapeSequence_ == "[B")
107                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Down,     0, 0));
108                else if (this->escapeSequence_ == "[C")
109                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Right,    0, 0));
110                else if (this->escapeSequence_ == "[D")
111                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Left,     0, 0));
112                else if (this->escapeSequence_ == "[1~")
113                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Home,     0, 0));
114                else if (this->escapeSequence_ == "[2~")
115                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert,   0, 0));
116                else if (this->escapeSequence_ == "[3~")
117                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete,   0, 0));
118                else if (this->escapeSequence_ == "[4~")
119                    this->buffer_->buttonPressed(KeyEvent(KeyCode::End,      0, 0));
120                else if (this->escapeSequence_ == "[5~")
121                    this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp,   0, 0));
122                else if (this->escapeSequence_ == "[6~")
123                    this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, 0, 0));
124                // Get Alt+Tab combination when switching applications
125                else if (this->escapeSequence_ == "\t")
126                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, '\t', KeyboardModifier::Alt));
127                else if (this->escapeSequence_.size() > 4)
128                    endOfSeq = true; // Something went wrong, start over
129                else
130                    endOfSeq = false;
131
132                //this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape,   0, 0));
133
134                if (endOfSeq)
135                    this->bEscapeMode_ = false;
136            }
137            else // not in an escape sequence
138            {
139                if (c == '\033')
140                                {
141                    this->bEscapeMode_ = true;
142                                        this->escapeSequence_.clear();
143                                }
144                else
145                {
146                    KeyCode::ByEnum code;
147                    switch (c)
148                    {
149                    case '\n': code = KeyCode::Return; break;
150                    case '\r': code = KeyCode::Return; break;
151                    case  127: code = KeyCode::Back;   break; 
152                    case '\b': code = KeyCode::Back;   break;
153                    case '\t': code = KeyCode::Tab;    break;
154                    default:
155                        // We don't encode the key code (would be a very large switch)
156                        // because the InputBuffer will only insert the text anyway
157                        // Replacement character is simply KeyCode::A
158                        code = KeyCode::A;
159                    }
160                    this->buffer_->buttonPressed(KeyEvent(code, c, 0));
161                }
162            }
163        }
164
165                // Print input line
166                this->printInputLine();
167    }
168
169    void IOConsole::printOutputLine(const std::string& line)
170    {
171                COUT(0) << "print output" << std::endl;
172        // Save cursor position
173        std::cout << "\033[s";
174
175        std::string output;
176
177        // Handle line colouring by inspecting the first letter
178        char level = 0;
179        if (!line.empty())
180            level = line[0];
181        if (level >= -1 && level <= 6)
182            output = line.substr(1);
183        else
184            output = line;
185
186        // Colour line
187        switch (level)
188        {
189        case -1: std::cout << "\033[30m"; break;
190        case  1: std::cout << "\033[91m"; break;
191        case  2: std::cout << "\033[31m"; break;
192        case  3: std::cout << "\033[34m"; break;
193        case  4: std::cout << "\033[36m"; break;
194        case  5: std::cout << "\033[35m"; break;
195        case  6: std::cout << "\033[37m"; break;
196        default: break;
197        }
198
199        // Print output line
200        std::cout << output << std::endl;
201
202        // Reset colour to black
203        std::cout << "\033[30m";
204        // Restore cursor position
205        std::cout << "\033[u";
206        std::cout.flush();
207
208                this->printInputLine();
209    }
210
211    void IOConsole::printInputLine()
212    {
213        // set cursor to the beginning of the line and erase the line
214        std::cout << "\033[0G\033[K";
215        // print status line
216        //std::cout << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, " << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms avg ticktime # ";
217                // Show an arrow to indicate a command prompt
218                std::cout << ">";
219        // save cursor position
220        std::cout << "\033[s";
221        // print commandLine buffer
222        std::cout << this->shell_.getInput();
223        // restore cursor position and move it to the right
224        std::cout << "\033[u";
225        if (this->buffer_->getCursorPosition() > 0)
226            std::cout << "\033[" << this->buffer_->getCursorPosition() << "C";
227        std::cout.flush();
228    }
229
230#endif /* ORXONOX_PLATFORM_UNIX */
231
232    // ###############################
233    // ###  ShellListener methods  ###
234    // ###############################
235
236    /**
237    @brief
238        Called if all output-lines have to be redrawn.
239    */
240    void IOConsole::linesChanged()
241    {
242        // Method only gets called upon start to draw all the lines
243        // But we are using std::cout anyway, so do nothing here
244    }
245
246    /**
247    @brief
248        Called if only the last output-line has changed.
249    */
250    void IOConsole::onlyLastLineChanged()
251    {
252        // We cannot do anything here because printed lines are fixed
253        COUT(2) << "Warning: Trying to edit last console lines, which is impossible!" << std::endl;
254    }
255
256    /**
257    @brief
258        Called if a new output-line was added.
259    */
260    void IOConsole::lineAdded()
261    {
262        this->printOutputLine(*(this->shell_.getNewestLineIterator()));
263    }
264
265    /**
266    @brief
267        Called if the text in the input-line has changed.
268    */
269    void IOConsole::inputChanged()
270    {
271        this->printInputLine();
272    }
273
274    /**
275    @brief
276        Called if the position of the cursor in the input-line has changed.
277    */
278    void IOConsole::cursorChanged()
279    {
280        this->printInputLine();
281    }
282
283    /**
284    @brief
285        Called if the console gets closed.
286    */
287    void IOConsole::exit()
288    {
289        // Exit is not an option, IOConsole always exists
290    }
291
292}
Note: See TracBrowser for help on using the repository browser.