Changeset 7287
- Timestamp:
- Aug 31, 2010, 11:13:46 AM (14 years ago)
- Location:
- code/trunk/src/libraries/core/command
- Files:
-
- 2 edited
- 4 copied
Legend:
- Unmodified
- Added
- Removed
-
code/trunk/src/libraries/core/command/IOConsole.cc
r7284 r7287 21 21 * 22 22 * Author: 23 * Oliver Scheuss24 23 * Reto Grieder 25 24 * Co-authors: … … 30 29 #include "IOConsole.h" 31 30 32 #include <iomanip> 33 #include <iostream> 34 35 #include "util/Clock.h" 36 #include "util/Math.h" 37 #include "core/Game.h" 38 #include "core/input/InputBuffer.h" 39 40 // ########################## 41 // ### Mutual methods ### 42 // ########################## 43 namespace orxonox 44 { 45 IOConsole* IOConsole::singletonPtr_s = NULL; 46 47 // ############################### 48 // ### ShellListener methods ### 49 // ############################### 50 51 //! Called if all output-lines have to be reprinted 52 void IOConsole::linesChanged() 53 { 54 // Method only gets called upon start to draw all the lines 55 // or when scrolling. But scrolling is disabled and the output 56 // is already in std::cout when we start the IOConsole 57 } 58 59 //! Called if a command is about to be executed 60 void IOConsole::executed() 61 { 62 this->shell_->addOutput(this->promptString_ + this->shell_->getInput() + '\n', Shell::Command); 63 } 64 65 //! Called if the console gets closed 66 void IOConsole::exit() 67 { 68 // Exit is not an option, just do nothing (Shell doesn't really exit too) 69 } 70 } 71 72 #ifdef ORXONOX_PLATFORM_UNIX 73 // ############################### 74 // ### Unix Implementation ### 75 // ############################### 76 77 #include <termios.h> 78 #include <sys/ioctl.h> 79 80 namespace orxonox 81 { 82 namespace EscapeMode 83 { 84 enum Value 85 { 86 None, 87 First, 88 Second 89 }; 90 } 91 92 IOConsole::IOConsole() 93 : shell_(new Shell("IOConsole", false)) 94 , buffer_(shell_->getInputBuffer()) 95 , cout_(std::cout.rdbuf()) 96 , promptString_("orxonox # ") 97 , bStatusPrinted_(false) 98 , originalTerminalSettings_(0) 99 { 100 this->setTerminalMode(); 101 this->shell_->registerListener(this); 102 103 // Manually set the widths of the individual status lines 104 this->statusLineWidths_.push_back(29); 105 this->statusLineMaxWidth_ = 29; 106 107 this->getTerminalSize(); 108 this->lastTerminalWidth_ = this->terminalWidth_; 109 this->lastTerminalHeight_ = this->terminalHeight_; 110 111 // Disable standard std::cout logging 112 OutputHandler::getInstance().disableCout(); 113 // Redirect std::cout to an ostringstream 114 // (Other part is in the initialiser list) 115 std::cout.rdbuf(this->origCout_.rdbuf()); 116 117 // Make sure we make way for the status lines 118 this->preUpdate(Game::getInstance().getGameClock()); 119 } 120 121 IOConsole::~IOConsole() 122 { 123 // Process output written to std::cout in the meantime 124 std::cout.flush(); 125 if (!this->origCout_.str().empty()) 126 this->shell_->addOutput(this->origCout_.str(), Shell::None); 127 // Erase input and status lines 128 this->cout_ << "\033[1G\033[J"; 129 // Move cursor to the bottom 130 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B'; 131 // Scroll terminal to compensate for erased lines 132 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'T'; 133 134 resetTerminalMode(); 135 this->shell_->destroy(); 136 137 // Restore this->cout_ redirection 138 std::cout.rdbuf(this->cout_.rdbuf()); 139 // Enable standard std::cout logging again 140 OutputHandler::getInstance().enableCout(); 141 } 142 143 void IOConsole::preUpdate(const Clock& time) 144 { 145 unsigned char c; 146 std::string escapeSequence; 147 EscapeMode::Value escapeMode = EscapeMode::None; 148 while (std::cin.good()) 149 { 150 c = std::cin.get(); 151 if (!std::cin.good()) 152 break; 153 154 if (escapeMode == EscapeMode::First && (c == '[' || c=='O') ) 155 escapeMode = EscapeMode::Second; 156 // Get Alt+Tab combination when switching applications 157 else if (escapeMode == EscapeMode::First && c == '\t') 158 { 159 this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, '\t', KeyboardModifier::Alt)); 160 escapeMode = EscapeMode::None; 161 } 162 else if (escapeMode == EscapeMode::Second) 163 { 164 escapeSequence += c; 165 escapeMode = EscapeMode::None; 166 if (escapeSequence == "A") 167 this->buffer_->buttonPressed(KeyEvent(KeyCode::Up, 0, 0)); 168 else if (escapeSequence == "B") 169 this->buffer_->buttonPressed(KeyEvent(KeyCode::Down, 0, 0)); 170 else if (escapeSequence == "C") 171 this->buffer_->buttonPressed(KeyEvent(KeyCode::Right, 0, 0)); 172 else if (escapeSequence == "D") 173 this->buffer_->buttonPressed(KeyEvent(KeyCode::Left, 0, 0)); 174 else if (escapeSequence == "1~" || escapeSequence == "H") 175 this->buffer_->buttonPressed(KeyEvent(KeyCode::Home, 0, 0)); 176 else if (escapeSequence == "2~") 177 this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert, 0, 0)); 178 else if (escapeSequence == "3~") 179 this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete, 0, 0)); 180 else if (escapeSequence == "4~" || escapeSequence == "F") 181 this->buffer_->buttonPressed(KeyEvent(KeyCode::End, 0, 0)); 182 else if (escapeSequence == "5~") 183 this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp, 0, 0)); 184 else if (escapeSequence == "6~") 185 this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, 0, 0)); 186 else 187 // Waiting for sequence to complete 188 // If the user presses ESC and then '[' or 'O' while the loop is not 189 // running (for instance while loading), the whole sequence gets dropped 190 escapeMode = EscapeMode::Second; 191 } 192 else // not in an escape sequence OR user might have pressed just ESC 193 { 194 if (escapeMode == EscapeMode::First) 195 { 196 this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, c, 0)); 197 escapeMode = EscapeMode::None; 198 } 199 if (c == '\033') 200 { 201 escapeMode = EscapeMode::First; 202 escapeSequence.clear(); 203 } 204 else 205 { 206 KeyCode::ByEnum code; 207 switch (c) 208 { 209 case '\n' : case '\r': code = KeyCode::Return; break; 210 case '\177': case '\b': code = KeyCode::Back; break; 211 case '\t' : code = KeyCode::Tab; break; 212 default: 213 // We don't encode the key code (would be a very large switch) 214 // because the InputBuffer will only insert the text anyway 215 // Replacement character is simply KeyCode::A 216 code = KeyCode::A; 217 } 218 this->buffer_->buttonPressed(KeyEvent(code, c, 0)); 219 } 220 } 221 } 222 // Reset error flags in std::cin 223 std::cin.clear(); 224 225 // If there is still an escape key pending (escape key ONLY), then 226 // it sure isn't an escape sequence anymore 227 if (escapeMode == EscapeMode::First) 228 this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, '\033', 0)); 229 230 // Determine terminal width and height 231 this->lastTerminalWidth_ = this->terminalWidth_; 232 this->lastTerminalHeight_ = this->terminalHeight_; 233 this->getTerminalSize(); 234 235 int heightDiff = this->terminalHeight_ - this->lastTerminalHeight_; 236 if (this->bStatusPrinted_ && heightDiff < 0) 237 { 238 // Terminal width has shrunk. The cursor will still be on the input line, 239 // but that line might very well be the last 240 int newLines = std::min((int)this->statusLineWidths_.size(), -heightDiff); 241 // Scroll terminal to create new lines 242 this->cout_ << "\033[" << newLines << 'S'; 243 } 244 245 if (!this->bStatusPrinted_ && this->willPrintStatusLines()) 246 { 247 // Scroll console to make way for status lines 248 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'S'; 249 this->bStatusPrinted_ = true; 250 } 251 252 // We always assume that the cursor is on the input line. 253 // But we cannot always be sure about that, esp. if we scroll the console 254 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B'; 255 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'A'; 256 257 // Erase status and input lines 258 this->cout_ << "\033[1G\033[J"; 259 this->printInputLine(); 260 this->printStatusLines(); 261 this->cout_.flush(); 262 263 // Process output written to std::cout 264 std::cout.flush(); 265 if (!this->origCout_.str().empty()) 266 { 267 this->shell_->addOutput(this->origCout_.str(), Shell::None); 268 this->origCout_.str(""); 269 } 270 } 271 272 void IOConsole::printOutputLine(const std::string& text, Shell::LineType type) 273 { 274 /* 275 // Colour line 276 switch (type) 277 { 278 case Shell::None: this->cout_ << "\033[37m"; break; 279 case Shell::Error: this->cout_ << "\033[91m"; break; 280 case Shell::Warning: this->cout_ << "\033[31m"; break; 281 case Shell::Info: this->cout_ << "\033[34m"; break; 282 case Shell::Debug: this->cout_ << "\033[36m"; break; 283 case Shell::Verbose: this->cout_ << "\033[35m"; break; 284 case Shell::Ultra: this->cout_ << "\033[37m"; break; 285 default: break; 286 } 287 */ 288 289 // Print output line 290 this->cout_ << text; 291 292 // Reset colour to white 293 // this->cout_ << "\033[37m"; 294 } 295 296 void IOConsole::printInputLine() 297 { 298 // Set cursor to the beginning of the line and erase the line 299 this->cout_ << "\033[1G\033[K"; 300 // Indicate a command prompt 301 this->cout_ << this->promptString_; 302 // Save cursor position 303 this->cout_ << "\033[s"; 304 // Print command line buffer 305 this->cout_ << this->shell_->getInput(); 306 // Restore cursor position and move it to the right 307 this->cout_ << "\033[u"; 308 if (this->buffer_->getCursorPosition() > 0) 309 this->cout_ << "\033[" << this->buffer_->getCursorPosition() << 'C'; 310 } 311 312 void IOConsole::printStatusLines() 313 { 314 if (this->willPrintStatusLines()) 315 { 316 // Save cursor position 317 this->cout_ << "\033[s"; 318 // Move cursor down (don't create a new line here because the buffer might flush then!) 319 this->cout_ << "\033[1B\033[1G"; 320 this->cout_ << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, "; 321 this->cout_ << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time"; 322 // Restore cursor position 323 this->cout_ << "\033[u"; 324 this->bStatusPrinted_ = true; 325 } 326 else 327 this->bStatusPrinted_ = false; 328 } 329 330 void IOConsole::setTerminalMode() 331 { 332 termios new_settings; 333 this->originalTerminalSettings_ = new termios(); 334 335 tcgetattr(0, this->originalTerminalSettings_); 336 new_settings = *this->originalTerminalSettings_; 337 new_settings.c_lflag &= ~(ICANON | ECHO); 338 //new_settings.c_lflag |= (ISIG | IEXTEN); 339 new_settings.c_cc[VTIME] = 0; 340 new_settings.c_cc[VMIN] = 0; 341 tcsetattr(0, TCSANOW, &new_settings); 342 atexit(&IOConsole::resetTerminalMode); 343 } 344 345 /*static*/ void IOConsole::resetTerminalMode() 346 { 347 if (IOConsole::singletonPtr_s && IOConsole::singletonPtr_s->originalTerminalSettings_) 348 { 349 tcsetattr(0, TCSANOW, IOConsole::singletonPtr_s->originalTerminalSettings_); 350 delete IOConsole::singletonPtr_s->originalTerminalSettings_; 351 IOConsole::singletonPtr_s->originalTerminalSettings_ = 0; 352 } 353 } 354 355 void IOConsole::getTerminalSize() 356 { 357 #ifdef TIOCGSIZE 358 struct ttysize win; 359 if (!ioctl(STDIN_FILENO, TIOCGSIZE, &win)) 360 { 361 this->terminalWidth_ = win.ts_cols; 362 this->terminalHeight_ = win.ts_lines; 363 return; 364 } 365 #elif defined TIOCGWINSZ 366 struct winsize win; 367 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) 368 { 369 this->terminalWidth_ = win.ws_col; 370 this->terminalHeight_ = win.ws_row; 371 return; 372 } 373 #else 374 const char* s = getenv("COLUMNS"); 375 this->terminalWidth_ = s ? strtol(s, NULL, 10) : 80; 376 s = getenv("LINES"); 377 this->terminalHeight_ = s ? strtol(s, NULL, 10) : 24; 378 return; 31 #if defined(ORXONOX_PLATFORM_UNIX) 32 #include "IOConsolePOSIX.cc" 33 #elif defined(ORXONOX_PLATFORM_WINDOWS) 34 #include "IOConsoleWindows.cc" 379 35 #endif 380 this->terminalWidth_ = 80;381 this->terminalHeight_ = 24;382 }383 384 inline bool IOConsole::willPrintStatusLines()385 {386 return !this->statusLineWidths_.empty()387 && this->terminalWidth_ >= this->statusLineMaxWidth_388 && this->terminalHeight_ >= this->minOutputLines_ + (int)this->statusLineWidths_.size();389 }390 391 // ###############################392 // ### ShellListener methods ###393 // ###############################394 395 //! Called if only the last output-line has changed396 void IOConsole::onlyLastLineChanged()397 {398 // Save cursor position and move it to the beginning of the first output line399 this->cout_ << "\033[s\033[1A\033[1G";400 // Erase the line401 this->cout_ << "\033[K";402 // Reprint the last output line403 this->printOutputLine(this->shell_->getNewestLineIterator()->first, this->shell_->getNewestLineIterator()->second);404 // Restore cursor405 this->cout_ << "\033[u";406 this->cout_.flush();407 }408 409 //! Called if a new output-line was added410 void IOConsole::lineAdded()411 {412 int newLines = this->shell_->getNewestLineIterator()->first.size() / this->terminalWidth_ + 1;413 // Create new lines by scrolling the screen414 this->cout_ << "\033[" << newLines << 'S';415 // Move cursor to the beginning of the new (last) output line416 this->cout_ << "\033[" << newLines << "A\033[1G";417 // Erase screen from here418 this->cout_ << "\033[J";419 // Print the new output lines420 for (int i = 0; i < newLines; ++i)421 {422 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();423 this->printOutputLine(it->first.substr(i*this->terminalWidth_, this->terminalWidth_), it->second);424 }425 // Move cursor down426 this->cout_ << "\033[1B\033[1G";427 // Print status and input lines428 this->printInputLine();429 this->printStatusLines();430 this->cout_.flush();431 }432 433 //! Called if the text in the input-line has changed434 void IOConsole::inputChanged()435 {436 this->printInputLine();437 this->cout_.flush();438 }439 440 //! Called if the position of the cursor in the input-line has changed441 void IOConsole::cursorChanged()442 {443 this->printInputLine();444 this->cout_.flush();445 }446 }447 448 #elif defined(ORXONOX_PLATFORM_WINDOWS)449 // ##################################450 // ### Windows Implementation ###451 // ##################################452 453 #include <windows.h>454 455 namespace orxonox456 {457 //! Redirects std::cout, creates the corresponding Shell and changes the terminal mode458 IOConsole::IOConsole()459 : shell_(new Shell("IOConsole", false))460 , buffer_(shell_->getInputBuffer())461 , cout_(std::cout.rdbuf())462 , promptString_("orxonox # ")463 , inputLineHeight_(1)464 , statusLines_(1)465 , lastOutputLineHeight_(0)466 {467 // Disable standard this->cout_ logging468 OutputHandler::getInstance().disableCout();469 // Redirect std::cout to an ostringstream470 // (Other part is in the initialiser list)471 std::cout.rdbuf(this->origCout_.rdbuf());472 473 this->setTerminalMode();474 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;475 GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);476 this->terminalWidth_ = screenBufferInfo.dwSize.X;477 this->terminalHeight_ = screenBufferInfo.dwSize.Y;478 // Determines where we are in respect to output already written with std::cout479 this->inputLineRow_ = screenBufferInfo.dwCursorPosition.Y;480 /*481 this->lastTerminalWidth_ = this->terminalWidth_;482 this->lastTerminalHeight_ = this->terminalHeight_;483 */484 485 // Cursor already at the end of the screen buffer?486 // (assuming the current input line height is 1)487 if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)488 SetConsoleCursorPosition(this->stdOutHandle_, makeCOORD(0, this->terminalHeight_ - this->statusLines_));489 490 // Prevent input line from overflowing491 int maxInputLength = (this->terminalHeight_ - this->statusLines_) * this->terminalWidth_ - 1 - this->promptString_.size();492 // Consider that the echo of a command might include the command plus some other characters (assumed max 80)493 // Also put a minimum so the config file parser is not overwhelmed with the command history494 this->buffer_->setMaxLength(std::min(8192, (maxInputLength - 80) / 2));495 496 // Print input and status line and position cursor497 this->inputChanged();498 this->cursorChanged();499 this->lastRefreshTime_ = Game::getInstance().getGameClock().getRealMicroseconds();500 this->preUpdate(Game::getInstance().getGameClock());501 502 this->shell_->registerListener(this);503 }504 505 //! Resets std::cout redirection and restores the terminal mode506 IOConsole::~IOConsole()507 {508 // Process output written to std::cout in the meantime509 std::cout.flush();510 if (!this->origCout_.str().empty())511 this->shell_->addOutput(this->origCout_.str(), Shell::None);512 513 this->shell_->unregisterListener(this);514 515 // Erase input and status lines516 COORD pos = {0, this->inputLineRow_};517 this->writeText(std::string((this->inputLineHeight_ + this->statusLines_) * this->terminalWidth_, ' '), pos);518 // Move cursor to the beginning of the line519 SetConsoleCursorPosition(stdOutHandle_, pos);520 521 // Restore this->cout_ redirection522 std::cout.rdbuf(this->cout_.rdbuf());523 // Enable standard this->cout_ logging again524 OutputHandler::getInstance().enableCout();525 526 resetTerminalMode();527 this->shell_->destroy();528 }529 530 //! Processes the pending input key strokes, refreshes the status lines and handles std::cout (redirected)531 void IOConsole::preUpdate(const Clock& time)532 {533 // Process input534 while (true)535 {536 DWORD count;537 INPUT_RECORD inrec;538 PeekConsoleInput(this->stdInHandle_, &inrec, 1, &count);539 if (count == 0)540 break;541 ReadConsoleInput(this->stdInHandle_, &inrec, 1, &count);542 if (inrec.EventType == KEY_EVENT && inrec.Event.KeyEvent.bKeyDown)543 {544 // Process keyboard modifiers (Ctrl, Alt and Shift)545 DWORD modifiersIn = inrec.Event.KeyEvent.dwControlKeyState;546 int modifiersOut = 0;547 if ((modifiersIn & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0)548 modifiersOut |= KeyboardModifier::Alt;549 if ((modifiersIn & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)550 modifiersOut |= KeyboardModifier::Ctrl;551 if ((modifiersIn & SHIFT_PRESSED) != 0)552 modifiersOut |= KeyboardModifier::Shift;553 554 // ASCII character (0 for special keys)555 char asciiChar = inrec.Event.KeyEvent.uChar.AsciiChar;556 557 // Process special keys and if not found, use Key::A as dummy (InputBuffer uses the ASCII text anyway)558 switch (inrec.Event.KeyEvent.wVirtualKeyCode)559 {560 case VK_BACK: this->buffer_->buttonPressed(KeyEvent(KeyCode::Back, asciiChar, modifiersOut)); break;561 case VK_TAB: this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, asciiChar, modifiersOut)); break;562 case VK_RETURN: this->buffer_->buttonPressed(KeyEvent(KeyCode::Return, asciiChar, modifiersOut)); break;563 case VK_PAUSE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Pause, asciiChar, modifiersOut)); break;564 case VK_ESCAPE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, asciiChar, modifiersOut)); break;565 case VK_SPACE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Space, asciiChar, modifiersOut)); break;566 case VK_PRIOR: this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp, asciiChar, modifiersOut)); break;567 case VK_NEXT: this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, asciiChar, modifiersOut)); break;568 case VK_END: this->buffer_->buttonPressed(KeyEvent(KeyCode::End, asciiChar, modifiersOut)); break;569 case VK_HOME: this->buffer_->buttonPressed(KeyEvent(KeyCode::Home, asciiChar, modifiersOut)); break;570 case VK_LEFT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Left, asciiChar, modifiersOut)); break;571 case VK_UP: this->buffer_->buttonPressed(KeyEvent(KeyCode::Up, asciiChar, modifiersOut)); break;572 case VK_RIGHT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Right, asciiChar, modifiersOut)); break;573 case VK_DOWN: this->buffer_->buttonPressed(KeyEvent(KeyCode::Down, asciiChar, modifiersOut)); break;574 case VK_INSERT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert, asciiChar, modifiersOut)); break;575 case VK_DELETE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete, asciiChar, modifiersOut)); break;576 default: this->buffer_->buttonPressed(KeyEvent(KeyCode::A, asciiChar, modifiersOut));577 }578 }579 }580 581 // TODO: Respect screen buffer size changes582 /*583 // The user can manually adjust the screen buffer size on Windows584 // And we don't want to screw the console because of that585 this->lastTerminalWidth_ = this->terminalWidth_;586 this->lastTerminalHeight_ = this->terminalHeight_;587 this->getTerminalSize(); // Also sets this->inputLineRow_ according to the cursor position588 // Is there still enough space below the cursor for the status line(s)?589 if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)590 this->moveCursor(0, -this->inputLineRow_ + this->terminalHeight_ - this->statusLines_ - 1);591 */592 593 // Refresh status line 5 times per second594 if (time.getMicroseconds() > this->lastRefreshTime_ + 1000000)595 {596 this->printStatusLines();597 this->lastRefreshTime_ = time.getMicroseconds();598 }599 600 // Process output written to std::cout601 std::cout.flush();602 if (!this->origCout_.str().empty())603 {604 this->shell_->addOutput(this->origCout_.str(), Shell::None);605 this->origCout_.str("");606 }607 }608 609 //! Prints output text. Similar to writeText, but sets the colour according to the output level610 void IOConsole::printOutputLine(const std::string& text, Shell::LineType type, const COORD& pos)611 {612 // Colour line613 WORD colour = 0;614 switch (type)615 {616 case Shell::Error: colour = FOREGROUND_INTENSITY | FOREGROUND_RED; break;617 case Shell::Warning: colour = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED; break;618 case Shell::Info:619 case Shell::Debug:620 case Shell::Verbose:621 case Shell::Ultra: colour = FOREGROUND_INTENSITY ; break;622 case Shell::Command: colour = FOREGROUND_GREEN | FOREGROUND_BLUE; break;623 case Shell::Hint: colour = FOREGROUND_GREEN | FOREGROUND_RED ; break;624 default: colour = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; break;625 }626 627 // Print output line628 this->writeText(text, pos, colour);629 }630 631 //! Prints all status lines with current content632 void IOConsole::printStatusLines()633 {634 // Prepare text to be written635 std::ostringstream oss;636 oss << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, ";637 oss << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";638 // Clear rest of the line by inserting spaces639 oss << std::string(this->terminalWidth_ - oss.str().size(), ' ');640 this->writeText(oss.str(), makeCOORD(0, this->inputLineRow_ + this->inputLineHeight_), FOREGROUND_GREEN);641 }642 643 //! Changes the console parameters for unbuffered input644 void IOConsole::setTerminalMode()645 {646 // Set the console mode to no-echo, raw input, and no window or mouse events647 this->stdOutHandle_ = GetStdHandle(STD_OUTPUT_HANDLE);648 this->stdInHandle_ = GetStdHandle(STD_INPUT_HANDLE);649 if (this->stdInHandle_ == INVALID_HANDLE_VALUE650 || !GetConsoleMode(this->stdInHandle_, &this->originalTerminalSettings_)651 || !SetConsoleMode(this->stdInHandle_, 0))652 {653 COUT(1) << "Error: Could not set Windows console settings" << std::endl;654 return;655 }656 FlushConsoleInputBuffer(this->stdInHandle_);657 }658 659 //! Restores the console parameters660 void IOConsole::resetTerminalMode()661 {662 SetConsoleMode(this->stdInHandle_, this->originalTerminalSettings_);663 }664 665 //! Sets this->terminalWidth_ and this->terminalHeight_666 void IOConsole::getTerminalSize()667 {668 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;669 GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);670 this->terminalWidth_ = screenBufferInfo.dwSize.X;671 this->terminalHeight_ = screenBufferInfo.dwSize.Y;672 }673 674 //! Writes arbitrary text to the console with a certain colour and screen buffer position675 void IOConsole::writeText(const std::string& text, const COORD& coord, WORD attributes)676 {677 DWORD count;678 WriteConsoleOutputCharacter(stdOutHandle_, text.c_str(), text.size(), coord, &count);679 FillConsoleOutputAttribute(stdOutHandle_, attributes, text.size(), coord, &count);680 }681 682 /** Scrolls the console screen buffer to create empty lines above the input line.683 @details684 If the input and status lines are already at the bottom of the screen buffer685 the whole output gets scrolled up. In the other case the input and status686 lines get scrolled down.687 In any case the status and input lines get scrolled down as far as possible.688 @param lines689 Number of lines to be inserted. Behavior for negative values is undefined.690 */691 void IOConsole::createNewOutputLines(int lines)692 {693 CHAR_INFO fillChar = {{' '}, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};694 // Lines to scroll input/status down (if possible)695 int linesDown = clamp(terminalHeight_ - inputLineRow_ - inputLineHeight_ - statusLines_, 0, lines);696 if (linesDown > 0)697 {698 // Scroll input and status lines down699 SMALL_RECT oldRect = {0, this->inputLineRow_,700 this->terminalWidth_ - 1, this->inputLineRow_ + this->inputLineHeight_ + this->statusLines_ - 1};701 this->inputLineRow_ += linesDown;702 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, this->inputLineRow_), &fillChar);703 // Move cursor down to the new bottom so the user can see the status lines704 COORD pos = {0, this->inputLineRow_ + this->inputLineHeight_ - 1 + this->statusLines_};705 SetConsoleCursorPosition(stdOutHandle_, pos);706 // Get cursor back to the right position707 this->cursorChanged();708 }709 // Check how many lines we still have to scroll up the output710 if (lines - linesDown > 0)711 {712 // Scroll output up713 SMALL_RECT oldRect = {0, lines - linesDown, this->terminalWidth_ - 1, this->inputLineRow_ - 1};714 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, 0), &fillChar);715 }716 }717 718 // ###############################719 // ### ShellListener methods ###720 // ###############################721 722 //! Called if the text in the input line has changed723 void IOConsole::inputChanged()724 {725 int newInputLineLength = this->promptString_.size() + this->shell_->getInput().size();726 int newInputLineHeight = 1 + newInputLineLength / this->terminalWidth_;727 int newLines = newInputLineHeight - this->inputLineHeight_;728 if (newLines > 0)729 {730 // Abuse this function to scroll the console731 this->createNewOutputLines(newLines);732 // Either Compensate for side effects (input/status lines scrolled down)733 // or we have to do this anyway (output scrolled up)734 this->inputLineRow_ -= newLines;735 }736 else if (newLines < 0)737 {738 // Scroll status lines up739 int statusLineRow = this->inputLineRow_ + this->inputLineHeight_;740 SMALL_RECT oldRect = {0, statusLineRow, this->terminalWidth_ - 1, statusLineRow + this->statusLines_};741 CHAR_INFO fillChar = {{' '}, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};742 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, statusLineRow + newLines), &fillChar);743 // Clear potential leftovers744 if (-newLines - this->statusLines_ > 0)745 {746 COORD pos = {0, this->inputLineRow_ + newInputLineHeight + this->statusLines_};747 this->writeText(std::string((-newLines - this->statusLines_) * this->terminalWidth_, ' '), pos);748 }749 }750 this->inputLineHeight_ = newInputLineHeight;751 752 // Print the whole line, including spaces that erase leftovers753 std::string inputLine = this->promptString_ + this->shell_->getInput();754 inputLine += std::string(this->terminalWidth_ - newInputLineLength % this->terminalWidth_, ' ');755 this->writeText(inputLine, makeCOORD(0, this->inputLineRow_), FOREGROUND_GREEN | FOREGROUND_INTENSITY);756 // If necessary, move cursor757 if (newLines != 0)758 this->cursorChanged();759 }760 761 //! Called if the position of the cursor in the input-line has changed762 void IOConsole::cursorChanged()763 {764 int rawCursorPos = this->promptString_.size() + this->buffer_->getCursorPosition();765 // Compensate for cursor further to the right than the terminal width766 COORD pos;767 pos.X = rawCursorPos % this->terminalWidth_;768 pos.Y = this->inputLineRow_ + rawCursorPos / this->terminalWidth_;769 SetConsoleCursorPosition(stdOutHandle_, pos);770 }771 772 //! Called if only the last output-line has changed773 void IOConsole::onlyLastLineChanged()774 {775 int newLineHeight = 1 + this->shell_->getNewestLineIterator()->first.size() / this->terminalWidth_;776 // Compute the number of new lines needed777 int newLines = newLineHeight - this->lastOutputLineHeight_;778 this->lastOutputLineHeight_ = newLineHeight;779 // Scroll console if necessary780 if (newLines > 0) // newLines < 0 is assumed impossible781 this->createNewOutputLines(newLines);782 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();783 this->printOutputLine(it->first, it->second, makeCOORD(0, this->inputLineRow_ - newLineHeight));784 }785 786 //! Called if a new output line was added787 void IOConsole::lineAdded()788 {789 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();790 // Scroll console791 this->lastOutputLineHeight_ = 1 + it->first.size() / this->terminalWidth_;792 this->createNewOutputLines(this->lastOutputLineHeight_);793 // Write the text794 COORD pos = {0, this->inputLineRow_ - this->lastOutputLineHeight_};795 this->printOutputLine(it->first, it->second, pos);796 }797 }798 799 #endif /* ORXONOX_PLATFORM_UNIX */ -
code/trunk/src/libraries/core/command/IOConsole.h
r7284 r7287 21 21 * 22 22 * Author: 23 * Oliver Scheuss24 23 * Reto Grieder 25 24 * Co-authors: … … 28 27 */ 29 28 30 #ifndef _IOConsole_H__ 31 #define _IOConsole_H__ 29 #include "OrxonoxConfig.h" 32 30 33 #include "core/CorePrereqs.h" 34 35 #include <sstream> 36 #include <string> 37 #include <vector> 38 #include "util/Singleton.h" 39 #include "Shell.h" 40 41 #ifdef ORXONOX_PLATFORM_UNIX 42 struct termios; 31 #if defined(ORXONOX_PLATFORM_UNIX) 32 #include "IOConsolePOSIX.h" 43 33 #elif defined(ORXONOX_PLATFORM_WINDOWS) 44 #define WIN32_LEAN_AND_MEAN 45 #ifndef NOMINMAX 46 #define NOMINMAX 34 #include "IOConsoleWindows.h" 47 35 #endif 48 #include <windows.h>49 #endif50 51 namespace orxonox52 {53 class _CoreExport IOConsole : public Singleton<IOConsole>, public ShellListener54 {55 friend class Singleton<IOConsole>;56 57 public:58 IOConsole();59 ~IOConsole();60 61 void preUpdate(const Clock& time);62 63 private:64 void setTerminalMode();65 void getTerminalSize();66 void printStatusLines();67 static int extractLogLevel(std::string* text);68 69 // Methods from ShellListener70 void linesChanged();71 void onlyLastLineChanged();72 void lineAdded();73 void inputChanged();74 void cursorChanged();75 void executed();76 void exit();77 78 Shell* shell_;79 InputBuffer* buffer_;80 std::ostream cout_;81 std::ostringstream origCout_;82 int terminalWidth_;83 int terminalHeight_;84 int lastTerminalWidth_;85 int lastTerminalHeight_;86 const std::string promptString_;87 88 #ifdef ORXONOX_PLATFORM_UNIX89 bool willPrintStatusLines();90 void printInputLine();91 void printOutputLine(const std::string& line, Shell::LineType type);92 static void resetTerminalMode();93 94 bool bPrintStatusLine_;95 bool bStatusPrinted_;96 std::vector<int> statusLineWidths_;97 int statusLineMaxWidth_;98 static const int minOutputLines_ = 3;99 termios* originalTerminalSettings_;100 101 #elif defined(ORXONOX_PLATFORM_WINDOWS)102 void resetTerminalMode();103 void moveCursor(int dx, int dy);104 void writeText(const std::string& text, const COORD& pos, WORD attributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);105 void createNewOutputLines(int lines);106 void printOutputLine(const std::string& line, Shell::LineType type, const COORD& pos);107 108 static inline COORD makeCOORD(int x, int y)109 {110 COORD val = {x, y};111 return val;112 }113 114 DWORD originalTerminalSettings_;115 HANDLE stdInHandle_;116 HANDLE stdOutHandle_;117 int inputLineRow_;118 int inputLineHeight_;119 const int statusLines_;120 int lastOutputLineHeight_;121 uint64_t lastRefreshTime_;122 #endif123 124 static IOConsole* singletonPtr_s;125 };126 }127 128 #endif /* _IOConsole_H__ */ -
code/trunk/src/libraries/core/command/IOConsolePOSIX.cc
r7265 r7287 32 32 #include <iomanip> 33 33 #include <iostream> 34 #include <termios.h> 35 #include <sys/ioctl.h> 34 36 35 37 #include "util/Clock.h" 36 38 #include "util/Math.h" 37 #include "Game.h" 38 #include "input/InputBuffer.h" 39 40 // ########################## 41 // ### Mutual methods ### 42 // ########################## 39 #include "core/Game.h" 40 #include "core/input/InputBuffer.h" 41 43 42 namespace orxonox 44 43 { 45 44 IOConsole* IOConsole::singletonPtr_s = NULL; 46 45 47 // ###############################48 // ### ShellListener methods ###49 // ###############################50 51 //! Called if all output-lines have to be reprinted52 void IOConsole::linesChanged()53 {54 // Method only gets called upon start to draw all the lines55 // or when scrolling. But scrolling is disabled and the output56 // is already in std::cout when we start the IOConsole57 }58 59 //! Called if a command is about to be executed60 void IOConsole::executed()61 {62 this->shell_->addOutput(this->promptString_ + this->shell_->getInput() + '\n', Shell::Command);63 }64 65 //! Called if the console gets closed66 void IOConsole::exit()67 {68 // Exit is not an option, just do nothing (Shell doesn't really exit too)69 }70 }71 72 #ifdef ORXONOX_PLATFORM_UNIX73 // ###############################74 // ### Unix Implementation ###75 // ###############################76 77 #include <termios.h>78 #include <sys/ioctl.h>79 80 namespace orxonox81 {82 46 namespace EscapeMode 83 47 { … … 393 357 // ############################### 394 358 359 //! Called if all output-lines have to be reprinted 360 void IOConsole::linesChanged() 361 { 362 // Method only gets called upon start to draw all the lines 363 // or when scrolling. But scrolling is disabled and the output 364 // is already in std::cout when we start the IOConsole 365 } 366 367 //! Called if a command is about to be executed 368 void IOConsole::executed() 369 { 370 this->shell_->addOutput(this->promptString_ + this->shell_->getInput() + '\n', Shell::Command); 371 } 372 373 //! Called if the console gets closed 374 void IOConsole::exit() 375 { 376 // Exit is not an option, just do nothing (Shell doesn't really exit too) 377 } 378 395 379 //! Called if only the last output-line has changed 396 380 void IOConsole::onlyLastLineChanged() … … 445 429 } 446 430 } 447 448 #elif defined(ORXONOX_PLATFORM_WINDOWS)449 // ##################################450 // ### Windows Implementation ###451 // ##################################452 453 #include <windows.h>454 455 namespace orxonox456 {457 //! Redirects std::cout, creates the corresponding Shell and changes the terminal mode458 IOConsole::IOConsole()459 : shell_(new Shell("IOConsole", false))460 , buffer_(shell_->getInputBuffer())461 , cout_(std::cout.rdbuf())462 , promptString_("orxonox # ")463 , inputLineHeight_(1)464 , statusLines_(1)465 , lastOutputLineHeight_(0)466 {467 // Disable standard this->cout_ logging468 OutputHandler::getInstance().disableCout();469 // Redirect std::cout to an ostringstream470 // (Other part is in the initialiser list)471 std::cout.rdbuf(this->origCout_.rdbuf());472 473 this->setTerminalMode();474 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;475 GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);476 this->terminalWidth_ = screenBufferInfo.dwSize.X;477 this->terminalHeight_ = screenBufferInfo.dwSize.Y;478 // Determines where we are in respect to output already written with std::cout479 this->inputLineRow_ = screenBufferInfo.dwCursorPosition.Y;480 /*481 this->lastTerminalWidth_ = this->terminalWidth_;482 this->lastTerminalHeight_ = this->terminalHeight_;483 */484 485 // Cursor already at the end of the screen buffer?486 // (assuming the current input line height is 1)487 if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)488 SetConsoleCursorPosition(this->stdOutHandle_, makeCOORD(0, this->terminalHeight_ - this->statusLines_));489 490 // Prevent input line from overflowing491 int maxInputLength = (this->terminalHeight_ - this->statusLines_) * this->terminalWidth_ - 1 - this->promptString_.size();492 // Consider that the echo of a command might include the command plus some other characters (assumed max 80)493 // Also put a minimum so the config file parser is not overwhelmed with the command history494 this->buffer_->setMaxLength(std::min(8192, (maxInputLength - 80) / 2));495 496 // Print input and status line and position cursor497 this->inputChanged();498 this->cursorChanged();499 this->lastRefreshTime_ = Game::getInstance().getGameClock().getRealMicroseconds();500 this->preUpdate(Game::getInstance().getGameClock());501 502 this->shell_->registerListener(this);503 }504 505 //! Resets std::cout redirection and restores the terminal mode506 IOConsole::~IOConsole()507 {508 // Process output written to std::cout in the meantime509 std::cout.flush();510 if (!this->origCout_.str().empty())511 this->shell_->addOutput(this->origCout_.str(), Shell::None);512 513 this->shell_->unregisterListener(this);514 515 // Erase input and status lines516 COORD pos = {0, this->inputLineRow_};517 this->writeText(std::string((this->inputLineHeight_ + this->statusLines_) * this->terminalWidth_, ' '), pos);518 // Move cursor to the beginning of the line519 SetConsoleCursorPosition(stdOutHandle_, pos);520 521 // Restore this->cout_ redirection522 std::cout.rdbuf(this->cout_.rdbuf());523 // Enable standard this->cout_ logging again524 OutputHandler::getInstance().enableCout();525 526 resetTerminalMode();527 this->shell_->destroy();528 }529 530 //! Processes the pending input key strokes, refreshes the status lines and handles std::cout (redirected)531 void IOConsole::preUpdate(const Clock& time)532 {533 // Process input534 while (true)535 {536 DWORD count;537 INPUT_RECORD inrec;538 PeekConsoleInput(this->stdInHandle_, &inrec, 1, &count);539 if (count == 0)540 break;541 ReadConsoleInput(this->stdInHandle_, &inrec, 1, &count);542 if (inrec.EventType == KEY_EVENT && inrec.Event.KeyEvent.bKeyDown)543 {544 // Process keyboard modifiers (Ctrl, Alt and Shift)545 DWORD modifiersIn = inrec.Event.KeyEvent.dwControlKeyState;546 int modifiersOut = 0;547 if ((modifiersIn & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) != 0)548 modifiersOut |= KeyboardModifier::Alt;549 if ((modifiersIn & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)550 modifiersOut |= KeyboardModifier::Ctrl;551 if ((modifiersIn & SHIFT_PRESSED) != 0)552 modifiersOut |= KeyboardModifier::Shift;553 554 // ASCII character (0 for special keys)555 char asciiChar = inrec.Event.KeyEvent.uChar.AsciiChar;556 557 // Process special keys and if not found, use Key::A as dummy (InputBuffer uses the ASCII text anyway)558 switch (inrec.Event.KeyEvent.wVirtualKeyCode)559 {560 case VK_BACK: this->buffer_->buttonPressed(KeyEvent(KeyCode::Back, asciiChar, modifiersOut)); break;561 case VK_TAB: this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, asciiChar, modifiersOut)); break;562 case VK_RETURN: this->buffer_->buttonPressed(KeyEvent(KeyCode::Return, asciiChar, modifiersOut)); break;563 case VK_PAUSE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Pause, asciiChar, modifiersOut)); break;564 case VK_ESCAPE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, asciiChar, modifiersOut)); break;565 case VK_SPACE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Space, asciiChar, modifiersOut)); break;566 case VK_PRIOR: this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp, asciiChar, modifiersOut)); break;567 case VK_NEXT: this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, asciiChar, modifiersOut)); break;568 case VK_END: this->buffer_->buttonPressed(KeyEvent(KeyCode::End, asciiChar, modifiersOut)); break;569 case VK_HOME: this->buffer_->buttonPressed(KeyEvent(KeyCode::Home, asciiChar, modifiersOut)); break;570 case VK_LEFT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Left, asciiChar, modifiersOut)); break;571 case VK_UP: this->buffer_->buttonPressed(KeyEvent(KeyCode::Up, asciiChar, modifiersOut)); break;572 case VK_RIGHT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Right, asciiChar, modifiersOut)); break;573 case VK_DOWN: this->buffer_->buttonPressed(KeyEvent(KeyCode::Down, asciiChar, modifiersOut)); break;574 case VK_INSERT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert, asciiChar, modifiersOut)); break;575 case VK_DELETE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete, asciiChar, modifiersOut)); break;576 default: this->buffer_->buttonPressed(KeyEvent(KeyCode::A, asciiChar, modifiersOut));577 }578 }579 }580 581 // TODO: Respect screen buffer size changes582 /*583 // The user can manually adjust the screen buffer size on Windows584 // And we don't want to screw the console because of that585 this->lastTerminalWidth_ = this->terminalWidth_;586 this->lastTerminalHeight_ = this->terminalHeight_;587 this->getTerminalSize(); // Also sets this->inputLineRow_ according to the cursor position588 // Is there still enough space below the cursor for the status line(s)?589 if (this->inputLineRow_ >= this->terminalHeight_ - this->statusLines_)590 this->moveCursor(0, -this->inputLineRow_ + this->terminalHeight_ - this->statusLines_ - 1);591 */592 593 // Refresh status line 5 times per second594 if (time.getMicroseconds() > this->lastRefreshTime_ + 1000000)595 {596 this->printStatusLines();597 this->lastRefreshTime_ = time.getMicroseconds();598 }599 600 // Process output written to std::cout601 std::cout.flush();602 if (!this->origCout_.str().empty())603 {604 this->shell_->addOutput(this->origCout_.str(), Shell::None);605 this->origCout_.str("");606 }607 }608 609 //! Prints output text. Similar to writeText, but sets the colour according to the output level610 void IOConsole::printOutputLine(const std::string& text, Shell::LineType type, const COORD& pos)611 {612 // Colour line613 WORD colour = 0;614 switch (type)615 {616 case Shell::Error: colour = FOREGROUND_INTENSITY | FOREGROUND_RED; break;617 case Shell::Warning: colour = FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED; break;618 case Shell::Info:619 case Shell::Debug:620 case Shell::Verbose:621 case Shell::Ultra: colour = FOREGROUND_INTENSITY ; break;622 case Shell::Command: colour = FOREGROUND_GREEN | FOREGROUND_BLUE; break;623 case Shell::Hint: colour = FOREGROUND_GREEN | FOREGROUND_RED ; break;624 default: colour = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE; break;625 }626 627 // Print output line628 this->writeText(text, pos, colour);629 }630 631 //! Prints all status lines with current content632 void IOConsole::printStatusLines()633 {634 // Prepare text to be written635 std::ostringstream oss;636 oss << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, ";637 oss << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";638 // Clear rest of the line by inserting spaces639 oss << std::string(this->terminalWidth_ - oss.str().size(), ' ');640 this->writeText(oss.str(), makeCOORD(0, this->inputLineRow_ + this->inputLineHeight_), FOREGROUND_GREEN);641 }642 643 //! Changes the console parameters for unbuffered input644 void IOConsole::setTerminalMode()645 {646 // Set the console mode to no-echo, raw input, and no window or mouse events647 this->stdOutHandle_ = GetStdHandle(STD_OUTPUT_HANDLE);648 this->stdInHandle_ = GetStdHandle(STD_INPUT_HANDLE);649 if (this->stdInHandle_ == INVALID_HANDLE_VALUE650 || !GetConsoleMode(this->stdInHandle_, &this->originalTerminalSettings_)651 || !SetConsoleMode(this->stdInHandle_, 0))652 {653 COUT(1) << "Error: Could not set Windows console settings" << std::endl;654 return;655 }656 FlushConsoleInputBuffer(this->stdInHandle_);657 }658 659 //! Restores the console parameters660 void IOConsole::resetTerminalMode()661 {662 SetConsoleMode(this->stdInHandle_, this->originalTerminalSettings_);663 }664 665 //! Sets this->terminalWidth_ and this->terminalHeight_666 void IOConsole::getTerminalSize()667 {668 CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;669 GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);670 this->terminalWidth_ = screenBufferInfo.dwSize.X;671 this->terminalHeight_ = screenBufferInfo.dwSize.Y;672 }673 674 //! Writes arbitrary text to the console with a certain colour and screen buffer position675 void IOConsole::writeText(const std::string& text, const COORD& coord, WORD attributes)676 {677 DWORD count;678 WriteConsoleOutputCharacter(stdOutHandle_, text.c_str(), text.size(), coord, &count);679 FillConsoleOutputAttribute(stdOutHandle_, attributes, text.size(), coord, &count);680 }681 682 /** Scrolls the console screen buffer to create empty lines above the input line.683 @details684 If the input and status lines are already at the bottom of the screen buffer685 the whole output gets scrolled up. In the other case the input and status686 lines get scrolled down.687 In any case the status and input lines get scrolled down as far as possible.688 @param lines689 Number of lines to be inserted. Behavior for negative values is undefined.690 */691 void IOConsole::createNewOutputLines(int lines)692 {693 CHAR_INFO fillChar = {{' '}, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};694 // Lines to scroll input/status down (if possible)695 int linesDown = clamp(terminalHeight_ - inputLineRow_ - inputLineHeight_ - statusLines_, 0, lines);696 if (linesDown > 0)697 {698 // Scroll input and status lines down699 SMALL_RECT oldRect = {0, this->inputLineRow_,700 this->terminalWidth_ - 1, this->inputLineRow_ + this->inputLineHeight_ + this->statusLines_ - 1};701 this->inputLineRow_ += linesDown;702 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, this->inputLineRow_), &fillChar);703 // Move cursor down to the new bottom so the user can see the status lines704 COORD pos = {0, this->inputLineRow_ + this->inputLineHeight_ - 1 + this->statusLines_};705 SetConsoleCursorPosition(stdOutHandle_, pos);706 // Get cursor back to the right position707 this->cursorChanged();708 }709 // Check how many lines we still have to scroll up the output710 if (lines - linesDown > 0)711 {712 // Scroll output up713 SMALL_RECT oldRect = {0, lines - linesDown, this->terminalWidth_ - 1, this->inputLineRow_ - 1};714 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, 0), &fillChar);715 }716 }717 718 // ###############################719 // ### ShellListener methods ###720 // ###############################721 722 //! Called if the text in the input line has changed723 void IOConsole::inputChanged()724 {725 int newInputLineLength = this->promptString_.size() + this->shell_->getInput().size();726 int newInputLineHeight = 1 + newInputLineLength / this->terminalWidth_;727 int newLines = newInputLineHeight - this->inputLineHeight_;728 if (newLines > 0)729 {730 // Abuse this function to scroll the console731 this->createNewOutputLines(newLines);732 // Either Compensate for side effects (input/status lines scrolled down)733 // or we have to do this anyway (output scrolled up)734 this->inputLineRow_ -= newLines;735 }736 else if (newLines < 0)737 {738 // Scroll status lines up739 int statusLineRow = this->inputLineRow_ + this->inputLineHeight_;740 SMALL_RECT oldRect = {0, statusLineRow, this->terminalWidth_ - 1, statusLineRow + this->statusLines_};741 CHAR_INFO fillChar = {{' '}, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED};742 ScrollConsoleScreenBuffer(stdOutHandle_, &oldRect, NULL, makeCOORD(0, statusLineRow + newLines), &fillChar);743 // Clear potential leftovers744 if (-newLines - this->statusLines_ > 0)745 {746 COORD pos = {0, this->inputLineRow_ + newInputLineHeight + this->statusLines_};747 this->writeText(std::string((-newLines - this->statusLines_) * this->terminalWidth_, ' '), pos);748 }749 }750 this->inputLineHeight_ = newInputLineHeight;751 752 // Print the whole line, including spaces that erase leftovers753 std::string inputLine = this->promptString_ + this->shell_->getInput();754 inputLine += std::string(this->terminalWidth_ - newInputLineLength % this->terminalWidth_, ' ');755 this->writeText(inputLine, makeCOORD(0, this->inputLineRow_), FOREGROUND_GREEN | FOREGROUND_INTENSITY);756 // If necessary, move cursor757 if (newLines != 0)758 this->cursorChanged();759 }760 761 //! Called if the position of the cursor in the input-line has changed762 void IOConsole::cursorChanged()763 {764 int rawCursorPos = this->promptString_.size() + this->buffer_->getCursorPosition();765 // Compensate for cursor further to the right than the terminal width766 COORD pos;767 pos.X = rawCursorPos % this->terminalWidth_;768 pos.Y = this->inputLineRow_ + rawCursorPos / this->terminalWidth_;769 SetConsoleCursorPosition(stdOutHandle_, pos);770 }771 772 //! Called if only the last output-line has changed773 void IOConsole::onlyLastLineChanged()774 {775 int newLineHeight = 1 + this->shell_->getNewestLineIterator()->first.size() / this->terminalWidth_;776 // Compute the number of new lines needed777 int newLines = newLineHeight - this->lastOutputLineHeight_;778 this->lastOutputLineHeight_ = newLineHeight;779 // Scroll console if necessary780 if (newLines > 0) // newLines < 0 is assumed impossible781 this->createNewOutputLines(newLines);782 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();783 this->printOutputLine(it->first, it->second, makeCOORD(0, this->inputLineRow_ - newLineHeight));784 }785 786 //! Called if a new output line was added787 void IOConsole::lineAdded()788 {789 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();790 // Scroll console791 this->lastOutputLineHeight_ = 1 + it->first.size() / this->terminalWidth_;792 this->createNewOutputLines(this->lastOutputLineHeight_);793 // Write the text794 COORD pos = {0, this->inputLineRow_ - this->lastOutputLineHeight_};795 this->printOutputLine(it->first, it->second, pos);796 }797 }798 799 #endif /* ORXONOX_PLATFORM_UNIX */ -
code/trunk/src/libraries/core/command/IOConsolePOSIX.h
r7265 r7287 31 31 #define _IOConsole_H__ 32 32 33 #include " CorePrereqs.h"33 #include "core/CorePrereqs.h" 34 34 35 35 #include <sstream> … … 39 39 #include "Shell.h" 40 40 41 #ifdef ORXONOX_PLATFORM_UNIX42 41 struct termios; 43 #elif defined(ORXONOX_PLATFORM_WINDOWS)44 #define WIN32_LEAN_AND_MEAN45 #ifndef NOMINMAX46 #define NOMINMAX47 #endif48 #include <windows.h>49 #endif50 42 51 43 namespace orxonox … … 76 68 void exit(); 77 69 70 bool willPrintStatusLines(); 71 void printInputLine(); 72 void printOutputLine(const std::string& line, Shell::LineType type); 73 static void resetTerminalMode(); 74 78 75 Shell* shell_; 79 76 InputBuffer* buffer_; … … 86 83 const std::string promptString_; 87 84 88 #ifdef ORXONOX_PLATFORM_UNIX89 bool willPrintStatusLines();90 void printInputLine();91 void printOutputLine(const std::string& line, Shell::LineType type);92 static void resetTerminalMode();93 94 85 bool bPrintStatusLine_; 95 86 bool bStatusPrinted_; … … 99 90 termios* originalTerminalSettings_; 100 91 101 #elif defined(ORXONOX_PLATFORM_WINDOWS)102 void resetTerminalMode();103 void moveCursor(int dx, int dy);104 void writeText(const std::string& text, const COORD& pos, WORD attributes = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);105 void createNewOutputLines(int lines);106 void printOutputLine(const std::string& line, Shell::LineType type, const COORD& pos);107 108 static inline COORD makeCOORD(int x, int y)109 {110 COORD val = {x, y};111 return val;112 }113 114 DWORD originalTerminalSettings_;115 HANDLE stdInHandle_;116 HANDLE stdOutHandle_;117 int inputLineRow_;118 int inputLineHeight_;119 const int statusLines_;120 int lastOutputLineHeight_;121 uint64_t lastRefreshTime_;122 #endif123 124 92 static IOConsole* singletonPtr_s; 125 93 }; -
code/trunk/src/libraries/core/command/IOConsoleWindows.cc
r7265 r7287 21 21 * 22 22 * Author: 23 * Oliver Scheuss24 23 * Reto Grieder 25 24 * Co-authors: … … 35 34 #include "util/Clock.h" 36 35 #include "util/Math.h" 37 #include "Game.h" 38 #include "input/InputBuffer.h" 39 40 // ########################## 41 // ### Mutual methods ### 42 // ########################## 36 #include "core/Game.h" 37 #include "core/input/InputBuffer.h" 38 43 39 namespace orxonox 44 40 { 45 41 IOConsole* IOConsole::singletonPtr_s = NULL; 46 42 47 // ###############################48 // ### ShellListener methods ###49 // ###############################50 51 //! Called if all output-lines have to be reprinted52 void IOConsole::linesChanged()53 {54 // Method only gets called upon start to draw all the lines55 // or when scrolling. But scrolling is disabled and the output56 // is already in std::cout when we start the IOConsole57 }58 59 //! Called if a command is about to be executed60 void IOConsole::executed()61 {62 this->shell_->addOutput(this->promptString_ + this->shell_->getInput() + '\n', Shell::Command);63 }64 65 //! Called if the console gets closed66 void IOConsole::exit()67 {68 // Exit is not an option, just do nothing (Shell doesn't really exit too)69 }70 }71 72 #ifdef ORXONOX_PLATFORM_UNIX73 // ###############################74 // ### Unix Implementation ###75 // ###############################76 77 #include <termios.h>78 #include <sys/ioctl.h>79 80 namespace orxonox81 {82 namespace EscapeMode83 {84 enum Value85 {86 None,87 First,88 Second89 };90 }91 92 IOConsole::IOConsole()93 : shell_(new Shell("IOConsole", false))94 , buffer_(shell_->getInputBuffer())95 , cout_(std::cout.rdbuf())96 , promptString_("orxonox # ")97 , bStatusPrinted_(false)98 , originalTerminalSettings_(0)99 {100 this->setTerminalMode();101 this->shell_->registerListener(this);102 103 // Manually set the widths of the individual status lines104 this->statusLineWidths_.push_back(29);105 this->statusLineMaxWidth_ = 29;106 107 this->getTerminalSize();108 this->lastTerminalWidth_ = this->terminalWidth_;109 this->lastTerminalHeight_ = this->terminalHeight_;110 111 // Disable standard std::cout logging112 OutputHandler::getInstance().disableCout();113 // Redirect std::cout to an ostringstream114 // (Other part is in the initialiser list)115 std::cout.rdbuf(this->origCout_.rdbuf());116 117 // Make sure we make way for the status lines118 this->preUpdate(Game::getInstance().getGameClock());119 }120 121 IOConsole::~IOConsole()122 {123 // Process output written to std::cout in the meantime124 std::cout.flush();125 if (!this->origCout_.str().empty())126 this->shell_->addOutput(this->origCout_.str(), Shell::None);127 // Erase input and status lines128 this->cout_ << "\033[1G\033[J";129 // Move cursor to the bottom130 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B';131 // Scroll terminal to compensate for erased lines132 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'T';133 134 resetTerminalMode();135 this->shell_->destroy();136 137 // Restore this->cout_ redirection138 std::cout.rdbuf(this->cout_.rdbuf());139 // Enable standard std::cout logging again140 OutputHandler::getInstance().enableCout();141 }142 143 void IOConsole::preUpdate(const Clock& time)144 {145 unsigned char c;146 std::string escapeSequence;147 EscapeMode::Value escapeMode = EscapeMode::None;148 while (std::cin.good())149 {150 c = std::cin.get();151 if (!std::cin.good())152 break;153 154 if (escapeMode == EscapeMode::First && (c == '[' || c=='O') )155 escapeMode = EscapeMode::Second;156 // Get Alt+Tab combination when switching applications157 else if (escapeMode == EscapeMode::First && c == '\t')158 {159 this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, '\t', KeyboardModifier::Alt));160 escapeMode = EscapeMode::None;161 }162 else if (escapeMode == EscapeMode::Second)163 {164 escapeSequence += c;165 escapeMode = EscapeMode::None;166 if (escapeSequence == "A")167 this->buffer_->buttonPressed(KeyEvent(KeyCode::Up, 0, 0));168 else if (escapeSequence == "B")169 this->buffer_->buttonPressed(KeyEvent(KeyCode::Down, 0, 0));170 else if (escapeSequence == "C")171 this->buffer_->buttonPressed(KeyEvent(KeyCode::Right, 0, 0));172 else if (escapeSequence == "D")173 this->buffer_->buttonPressed(KeyEvent(KeyCode::Left, 0, 0));174 else if (escapeSequence == "1~" || escapeSequence == "H")175 this->buffer_->buttonPressed(KeyEvent(KeyCode::Home, 0, 0));176 else if (escapeSequence == "2~")177 this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert, 0, 0));178 else if (escapeSequence == "3~")179 this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete, 0, 0));180 else if (escapeSequence == "4~" || escapeSequence == "F")181 this->buffer_->buttonPressed(KeyEvent(KeyCode::End, 0, 0));182 else if (escapeSequence == "5~")183 this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp, 0, 0));184 else if (escapeSequence == "6~")185 this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, 0, 0));186 else187 // Waiting for sequence to complete188 // If the user presses ESC and then '[' or 'O' while the loop is not189 // running (for instance while loading), the whole sequence gets dropped190 escapeMode = EscapeMode::Second;191 }192 else // not in an escape sequence OR user might have pressed just ESC193 {194 if (escapeMode == EscapeMode::First)195 {196 this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, c, 0));197 escapeMode = EscapeMode::None;198 }199 if (c == '\033')200 {201 escapeMode = EscapeMode::First;202 escapeSequence.clear();203 }204 else205 {206 KeyCode::ByEnum code;207 switch (c)208 {209 case '\n' : case '\r': code = KeyCode::Return; break;210 case '\177': case '\b': code = KeyCode::Back; break;211 case '\t' : code = KeyCode::Tab; break;212 default:213 // We don't encode the key code (would be a very large switch)214 // because the InputBuffer will only insert the text anyway215 // Replacement character is simply KeyCode::A216 code = KeyCode::A;217 }218 this->buffer_->buttonPressed(KeyEvent(code, c, 0));219 }220 }221 }222 // Reset error flags in std::cin223 std::cin.clear();224 225 // If there is still an escape key pending (escape key ONLY), then226 // it sure isn't an escape sequence anymore227 if (escapeMode == EscapeMode::First)228 this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, '\033', 0));229 230 // Determine terminal width and height231 this->lastTerminalWidth_ = this->terminalWidth_;232 this->lastTerminalHeight_ = this->terminalHeight_;233 this->getTerminalSize();234 235 int heightDiff = this->terminalHeight_ - this->lastTerminalHeight_;236 if (this->bStatusPrinted_ && heightDiff < 0)237 {238 // Terminal width has shrunk. The cursor will still be on the input line,239 // but that line might very well be the last240 int newLines = std::min((int)this->statusLineWidths_.size(), -heightDiff);241 // Scroll terminal to create new lines242 this->cout_ << "\033[" << newLines << 'S';243 }244 245 if (!this->bStatusPrinted_ && this->willPrintStatusLines())246 {247 // Scroll console to make way for status lines248 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'S';249 this->bStatusPrinted_ = true;250 }251 252 // We always assume that the cursor is on the input line.253 // But we cannot always be sure about that, esp. if we scroll the console254 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B';255 this->cout_ << "\033[" << this->statusLineWidths_.size() << 'A';256 257 // Erase status and input lines258 this->cout_ << "\033[1G\033[J";259 this->printInputLine();260 this->printStatusLines();261 this->cout_.flush();262 263 // Process output written to std::cout264 std::cout.flush();265 if (!this->origCout_.str().empty())266 {267 this->shell_->addOutput(this->origCout_.str(), Shell::None);268 this->origCout_.str("");269 }270 }271 272 void IOConsole::printOutputLine(const std::string& text, Shell::LineType type)273 {274 /*275 // Colour line276 switch (type)277 {278 case Shell::None: this->cout_ << "\033[37m"; break;279 case Shell::Error: this->cout_ << "\033[91m"; break;280 case Shell::Warning: this->cout_ << "\033[31m"; break;281 case Shell::Info: this->cout_ << "\033[34m"; break;282 case Shell::Debug: this->cout_ << "\033[36m"; break;283 case Shell::Verbose: this->cout_ << "\033[35m"; break;284 case Shell::Ultra: this->cout_ << "\033[37m"; break;285 default: break;286 }287 */288 289 // Print output line290 this->cout_ << text;291 292 // Reset colour to white293 // this->cout_ << "\033[37m";294 }295 296 void IOConsole::printInputLine()297 {298 // Set cursor to the beginning of the line and erase the line299 this->cout_ << "\033[1G\033[K";300 // Indicate a command prompt301 this->cout_ << this->promptString_;302 // Save cursor position303 this->cout_ << "\033[s";304 // Print command line buffer305 this->cout_ << this->shell_->getInput();306 // Restore cursor position and move it to the right307 this->cout_ << "\033[u";308 if (this->buffer_->getCursorPosition() > 0)309 this->cout_ << "\033[" << this->buffer_->getCursorPosition() << 'C';310 }311 312 void IOConsole::printStatusLines()313 {314 if (this->willPrintStatusLines())315 {316 // Save cursor position317 this->cout_ << "\033[s";318 // Move cursor down (don't create a new line here because the buffer might flush then!)319 this->cout_ << "\033[1B\033[1G";320 this->cout_ << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, ";321 this->cout_ << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";322 // Restore cursor position323 this->cout_ << "\033[u";324 this->bStatusPrinted_ = true;325 }326 else327 this->bStatusPrinted_ = false;328 }329 330 void IOConsole::setTerminalMode()331 {332 termios new_settings;333 this->originalTerminalSettings_ = new termios();334 335 tcgetattr(0, this->originalTerminalSettings_);336 new_settings = *this->originalTerminalSettings_;337 new_settings.c_lflag &= ~(ICANON | ECHO);338 //new_settings.c_lflag |= (ISIG | IEXTEN);339 new_settings.c_cc[VTIME] = 0;340 new_settings.c_cc[VMIN] = 0;341 tcsetattr(0, TCSANOW, &new_settings);342 atexit(&IOConsole::resetTerminalMode);343 }344 345 /*static*/ void IOConsole::resetTerminalMode()346 {347 if (IOConsole::singletonPtr_s && IOConsole::singletonPtr_s->originalTerminalSettings_)348 {349 tcsetattr(0, TCSANOW, IOConsole::singletonPtr_s->originalTerminalSettings_);350 delete IOConsole::singletonPtr_s->originalTerminalSettings_;351 IOConsole::singletonPtr_s->originalTerminalSettings_ = 0;352 }353 }354 355 void IOConsole::getTerminalSize()356 {357 #ifdef TIOCGSIZE358 struct ttysize win;359 if (!ioctl(STDIN_FILENO, TIOCGSIZE, &win))360 {361 this->terminalWidth_ = win.ts_cols;362 this->terminalHeight_ = win.ts_lines;363 return;364 }365 #elif defined TIOCGWINSZ366 struct winsize win;367 if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &win))368 {369 this->terminalWidth_ = win.ws_col;370 this->terminalHeight_ = win.ws_row;371 return;372 }373 #else374 const char* s = getenv("COLUMNS");375 this->terminalWidth_ = s ? strtol(s, NULL, 10) : 80;376 s = getenv("LINES");377 this->terminalHeight_ = s ? strtol(s, NULL, 10) : 24;378 return;379 #endif380 this->terminalWidth_ = 80;381 this->terminalHeight_ = 24;382 }383 384 inline bool IOConsole::willPrintStatusLines()385 {386 return !this->statusLineWidths_.empty()387 && this->terminalWidth_ >= this->statusLineMaxWidth_388 && this->terminalHeight_ >= this->minOutputLines_ + (int)this->statusLineWidths_.size();389 }390 391 // ###############################392 // ### ShellListener methods ###393 // ###############################394 395 //! Called if only the last output-line has changed396 void IOConsole::onlyLastLineChanged()397 {398 // Save cursor position and move it to the beginning of the first output line399 this->cout_ << "\033[s\033[1A\033[1G";400 // Erase the line401 this->cout_ << "\033[K";402 // Reprint the last output line403 this->printOutputLine(this->shell_->getNewestLineIterator()->first, this->shell_->getNewestLineIterator()->second);404 // Restore cursor405 this->cout_ << "\033[u";406 this->cout_.flush();407 }408 409 //! Called if a new output-line was added410 void IOConsole::lineAdded()411 {412 int newLines = this->shell_->getNewestLineIterator()->first.size() / this->terminalWidth_ + 1;413 // Create new lines by scrolling the screen414 this->cout_ << "\033[" << newLines << 'S';415 // Move cursor to the beginning of the new (last) output line416 this->cout_ << "\033[" << newLines << "A\033[1G";417 // Erase screen from here418 this->cout_ << "\033[J";419 // Print the new output lines420 for (int i = 0; i < newLines; ++i)421 {422 Shell::LineList::const_iterator it = this->shell_->getNewestLineIterator();423 this->printOutputLine(it->first.substr(i*this->terminalWidth_, this->terminalWidth_), it->second);424 }425 // Move cursor down426 this->cout_ << "\033[1B\033[1G";427 // Print status and input lines428 this->printInputLine();429 this->printStatusLines();430 this->cout_.flush();431 }432 433 //! Called if the text in the input-line has changed434 void IOConsole::inputChanged()435 {436 this->printInputLine();437 this->cout_.flush();438 }439 440 //! Called if the position of the cursor in the input-line has changed441 void IOConsole::cursorChanged()442 {443 this->printInputLine();444 this->cout_.flush();445 }446 }447 448 #elif defined(ORXONOX_PLATFORM_WINDOWS)449 // ##################################450 // ### Windows Implementation ###451 // ##################################452 453 #include <windows.h>454 455 namespace orxonox456 {457 43 //! Redirects std::cout, creates the corresponding Shell and changes the terminal mode 458 44 IOConsole::IOConsole() … … 720 306 // ############################### 721 307 308 //! Called if all output-lines have to be reprinted 309 void IOConsole::linesChanged() 310 { 311 // Method only gets called upon start to draw all the lines 312 // or when scrolling. But scrolling is disabled and the output 313 // is already in std::cout when we start the IOConsole 314 } 315 316 //! Called if a command is about to be executed 317 void IOConsole::executed() 318 { 319 this->shell_->addOutput(this->promptString_ + this->shell_->getInput() + '\n', Shell::Command); 320 } 321 322 //! Called if the console gets closed 323 void IOConsole::exit() 324 { 325 // Exit is not an option, just do nothing (Shell doesn't really exit too) 326 } 327 722 328 //! Called if the text in the input line has changed 723 329 void IOConsole::inputChanged() … … 796 402 } 797 403 } 798 799 #endif /* ORXONOX_PLATFORM_UNIX */ -
code/trunk/src/libraries/core/command/IOConsoleWindows.h
r7265 r7287 21 21 * 22 22 * Author: 23 * Oliver Scheuss24 23 * Reto Grieder 25 24 * Co-authors: … … 31 30 #define _IOConsole_H__ 32 31 33 #include " CorePrereqs.h"32 #include "core/CorePrereqs.h" 34 33 35 34 #include <sstream> … … 39 38 #include "Shell.h" 40 39 41 #ifdef ORXONOX_PLATFORM_UNIX42 struct termios;43 #elif defined(ORXONOX_PLATFORM_WINDOWS)44 40 #define WIN32_LEAN_AND_MEAN 45 41 #ifndef NOMINMAX … … 47 43 #endif 48 44 #include <windows.h> 49 #endif50 45 51 46 namespace orxonox … … 76 71 void exit(); 77 72 78 Shell* shell_;79 InputBuffer* buffer_;80 std::ostream cout_;81 std::ostringstream origCout_;82 int terminalWidth_;83 int terminalHeight_;84 int lastTerminalWidth_;85 int lastTerminalHeight_;86 const std::string promptString_;87 88 #ifdef ORXONOX_PLATFORM_UNIX89 bool willPrintStatusLines();90 void printInputLine();91 void printOutputLine(const std::string& line, Shell::LineType type);92 static void resetTerminalMode();93 94 bool bPrintStatusLine_;95 bool bStatusPrinted_;96 std::vector<int> statusLineWidths_;97 int statusLineMaxWidth_;98 static const int minOutputLines_ = 3;99 termios* originalTerminalSettings_;100 101 #elif defined(ORXONOX_PLATFORM_WINDOWS)102 73 void resetTerminalMode(); 103 74 void moveCursor(int dx, int dy); … … 112 83 } 113 84 85 Shell* shell_; 86 InputBuffer* buffer_; 87 std::ostream cout_; 88 std::ostringstream origCout_; 89 int terminalWidth_; 90 int terminalHeight_; 91 int lastTerminalWidth_; 92 int lastTerminalHeight_; 93 const std::string promptString_; 94 114 95 DWORD originalTerminalSettings_; 115 96 HANDLE stdInHandle_; … … 120 101 int lastOutputLineHeight_; 121 102 uint64_t lastRefreshTime_; 122 #endif123 103 124 104 static IOConsole* singletonPtr_s;
Note: See TracChangeset
for help on using the changeset viewer.