Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Nov 25, 2009, 12:09:02 AM (15 years ago)
Author:
rgrieder
Message:

Extended IOConsole to a Windows implementation. It doesn't yet work entirely as I wish, but it's not too bad either.
If you don't like the colors, I agree

Location:
code/branches/presentation2/src/libraries/core
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • code/branches/presentation2/src/libraries/core/IOConsole.cc

    r6122 r6140  
    3232#include <iomanip>
    3333#include <iostream>
     34
     35#include "util/Math.h"
    3436#include "core/Game.h"
    3537#include "core/input/InputBuffer.h"
     
    456458// ##################################
    457459
     460#include <windows.h>
     461
    458462namespace orxonox
    459463{
     
    465469        , promptString_("orxonox # ")
    466470    {
    467 /*
    468471        this->setTerminalMode();
    469472        this->shell_->registerListener(this);
     
    479482        // Disable standard this->cout_ logging
    480483        OutputHandler::getInstance().disableCout();
    481 */
     484        // Redirect std::cout to an ostringstream
     485        // (Other part is in the initialiser list)
     486        std::cout.rdbuf(this->origCout_.rdbuf());
     487
     488        // Make sure we make way for the status lines
     489        this->update(Game::getInstance().getGameClock());
    482490    }
    483491
    484492    IOConsole::~IOConsole()
    485493    {
    486 //        resetTerminalMode();
     494        // Empty all buffers
     495        this->update(Game::getInstance().getGameClock());
     496
     497        resetTerminalMode();
    487498        this->shell_->destroy();
    488499
    489 /*
     500        // Restore this->cout_ redirection
     501        std::cout.rdbuf(this->cout_.rdbuf());
    490502        // Enable standard this->cout_ logging again
    491503        OutputHandler::getInstance().enableCout();
    492 */
    493504    }
    494505
    495506    void IOConsole::update(const Clock& time)
    496507    {
    497 /*
    498         unsigned char c = 0;
    499         while (std::cin.good())
    500         {
    501             c = std::cin.get();
    502             if (std::cin.bad())
     508        while (true)
     509        {
     510            DWORD count;
     511            INPUT_RECORD inrec;
     512            PeekConsoleInput(this->stdInHandle_, &inrec, 1, &count);
     513            if (count == 0)
    503514                break;
    504         }
    505         // Reset error flags in std::cin
    506         std::cin.clear();
    507 
    508         // Determine terminal width and height
    509         this->lastTerminalWidth_ = this->terminalWidth_;
    510         this->lastTerminalHeight_ = this->terminalHeight_;
     515            ReadConsoleInput(this->stdInHandle_, &inrec, 1, &count);
     516            if (inrec.EventType == KEY_EVENT && inrec.Event.KeyEvent.bKeyDown)
     517            {
     518                // Process keyboard modifiers (Ctrl, Alt and Shift)
     519                DWORD modifiersIn = inrec.Event.KeyEvent.dwControlKeyState;
     520                int modifiersOut = 0;
     521                if ((modifiersIn & (LEFT_ALT_PRESSED  | RIGHT_ALT_PRESSED))  != 0)
     522                    modifiersOut |= KeyboardModifier::Alt;
     523                if ((modifiersIn & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) != 0)
     524                    modifiersOut |= KeyboardModifier::Ctrl;
     525                if ((modifiersIn & SHIFT_PRESSED) != 0)
     526                    modifiersOut |= KeyboardModifier::Shift;
     527
     528                // ASCII character (0 for special keys)
     529                char asciiChar = inrec.Event.KeyEvent.uChar.AsciiChar;
     530
     531                // Process special keys and if not found, use Key::A as dummy (InputBuffer uses the ASCII text anyway)
     532                switch (inrec.Event.KeyEvent.wVirtualKeyCode)
     533                {
     534                case VK_BACK:   this->buffer_->buttonPressed(KeyEvent(KeyCode::Back,     asciiChar, modifiersOut)); break;
     535                case VK_TAB:    this->buffer_->buttonPressed(KeyEvent(KeyCode::Back,     asciiChar, modifiersOut)); break;
     536                case VK_RETURN: this->buffer_->buttonPressed(KeyEvent(KeyCode::Back,     asciiChar, modifiersOut)); break;
     537                case VK_PAUSE:  this->buffer_->buttonPressed(KeyEvent(KeyCode::Pause,    asciiChar, modifiersOut)); break;
     538                case VK_ESCAPE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape,   asciiChar, modifiersOut)); break;
     539                case VK_SPACE:  this->buffer_->buttonPressed(KeyEvent(KeyCode::Space,    asciiChar, modifiersOut)); break;
     540                case VK_PRIOR:  this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp,   asciiChar, modifiersOut)); break;
     541                case VK_NEXT:   this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, asciiChar, modifiersOut)); break;
     542                case VK_END:    this->buffer_->buttonPressed(KeyEvent(KeyCode::End,      asciiChar, modifiersOut)); break;
     543                case VK_HOME:   this->buffer_->buttonPressed(KeyEvent(KeyCode::Home,     asciiChar, modifiersOut)); break;
     544                case VK_LEFT:   this->buffer_->buttonPressed(KeyEvent(KeyCode::Left,     asciiChar, modifiersOut)); break;
     545                case VK_UP:     this->buffer_->buttonPressed(KeyEvent(KeyCode::Up,       asciiChar, modifiersOut)); break;
     546                case VK_RIGHT:  this->buffer_->buttonPressed(KeyEvent(KeyCode::Right,    asciiChar, modifiersOut)); break;
     547                case VK_DOWN:   this->buffer_->buttonPressed(KeyEvent(KeyCode::Down,     asciiChar, modifiersOut)); break;
     548                case VK_INSERT: this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert,   asciiChar, modifiersOut)); break;
     549                case VK_DELETE: this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete,   asciiChar, modifiersOut)); break;
     550                default:        this->buffer_->buttonPressed(KeyEvent(KeyCode::A,        asciiChar, modifiersOut));
     551                }
     552            }
     553        }
     554
     555        // Get info about cursor and terminal size
    511556        this->getTerminalSize();
    512 */
     557
     558        // Refresh status line
     559        this->printStatusLines();
     560
     561        // Process output written to std::cout
     562        if (!this->origCout_.str().empty())
     563        {
     564            this->shell_->addOutputLine(this->origCout_.str());
     565            this->origCout_.str("");
     566        }
     567        this->cout_.flush();
    513568    }
    514569
    515570    void IOConsole::printLogText(const std::string& text)
    516571    {
     572        std::string output = text;
     573        int level = this->extractLogLevel(&output);
     574
     575        // Colour line
     576        switch (level)
     577        {
     578        case  1: SetConsoleTextAttribute(stdOutHandle_, FOREGROUND_RED | FOREGROUND_INTENSITY); break;
     579        case  2: SetConsoleTextAttribute(stdOutHandle_, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY); break;
     580        case  3: SetConsoleTextAttribute(stdOutHandle_, FOREGROUND_BLUE | FOREGROUND_INTENSITY); break;
     581        case  4: SetConsoleTextAttribute(stdOutHandle_, FOREGROUND_GREEN); break;
     582        default: break;
     583        }
     584
     585        // Print output line
     586        this->cout_ << output;
     587
     588        // Reset colour to white
     589        SetConsoleTextAttribute(stdOutHandle_, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_GREEN);
    517590    }
    518591
    519592    void IOConsole::printInputLine()
    520593    {
     594        this->moveCursorYAndHome(0);
     595        this->clearCurrentLine();
     596        this->cout_ << this->promptString_ << this->shell_->getInput();
     597        this->moveCursorYAndHome(0);
     598        this->moveCursor(this->promptString_.size() + this->buffer_->getCursorPosition(), 0);
    521599    }
    522600
    523601    void IOConsole::printStatusLines()
    524602    {
    525 /*
    526603        if (this->willPrintStatusLines())
    527604        {
    528605            this->bStatusPrinted_ = true;
     606            // Put cursor on home position, one line down the input line
     607            this->moveCursorYAndHome(1);
     608            this->cout_ << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, ";
     609            this->cout_ <<               std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";
     610            // Clear rest of the line
     611            CONSOLE_SCREEN_BUFFER_INFO info;
     612            GetConsoleScreenBufferInfo(this->stdOutHandle_, &info);
     613            this->cout_ << std::string(info.dwSize.X - info.dwCursorPosition.X - 1, ' ');
     614            // Restore cursor position
     615            this->moveCursorYAndHome(-1);
     616            this->moveCursor(this->promptString_.size() + this->buffer_->getCursorPosition(), 0);
    529617        }
    530618        else
    531619            this->bStatusPrinted_ = false;
    532 */
    533620    }
    534621
    535622    void IOConsole::setTerminalMode()
    536623    {
     624        // Set the console mode to no-echo, raw input, and no window or mouse events
     625        this->stdOutHandle_ = GetStdHandle(STD_OUTPUT_HANDLE);
     626        this->stdInHandle_  = GetStdHandle(STD_INPUT_HANDLE);
     627        if (this->stdInHandle_ == INVALID_HANDLE_VALUE
     628            || !GetConsoleMode(this->stdInHandle_, &this->originalTerminalSettings_)
     629            || !SetConsoleMode(this->stdInHandle_, 0))
     630        {
     631            COUT(1) << "Error: Could not set Windows console settings" << std::endl;
     632            return;
     633        }
     634        FlushConsoleInputBuffer(this->stdInHandle_);
    537635    }
    538636
    539637    void IOConsole::resetTerminalMode()
    540638    {
     639        SetConsoleMode(this->stdInHandle_, this->originalTerminalSettings_);
     640    }
     641
     642    //! Moves the console cursor around and inserts new lines when reaching the end.
     643    //! Moving out on the right is just clamped though.
     644    void IOConsole::moveCursor(int dx, int dy)
     645    {
     646        CONSOLE_SCREEN_BUFFER_INFO info;
     647        GetConsoleScreenBufferInfo(this->stdOutHandle_, &info);
     648        SHORT& x = info.dwCursorPosition.X;
     649        x = clamp(x + dx, 0, info.dwSize.X - 1);
     650        SHORT& y = info.dwCursorPosition.Y;
     651        if (y + dy >= info.dwSize.Y)
     652        {
     653            // Insert new lines
     654            this->cout_ << std::string(y + dy - info.dwSize.Y + 1, 'n');
     655            y = info.dwSize.Y - 1;
     656        }
     657        else if (y < 0)
     658            y = 0;
     659        else
     660            y += dy;
     661        SetConsoleCursorPosition(this->stdOutHandle_, info.dwCursorPosition);
     662    }
     663
     664    void IOConsole::moveCursorYAndHome(int dy)
     665    {
     666        CONSOLE_SCREEN_BUFFER_INFO info;
     667        GetConsoleScreenBufferInfo(this->stdOutHandle_, &info);
     668        this->moveCursor(-info.dwCursorPosition.X, dy);
     669    }
     670
     671    void IOConsole::clearCurrentLine()
     672    {
     673        CONSOLE_SCREEN_BUFFER_INFO info;
     674        GetConsoleScreenBufferInfo(this->stdOutHandle_, &info);
     675        info.dwCursorPosition.X = 0;
     676        DWORD count;
     677        FillConsoleOutputCharacter(this->stdOutHandle_, ' ', info.dwSize.X, info.dwCursorPosition, &count);;
    541678    }
    542679
    543680    void IOConsole::getTerminalSize()
    544681    {
     682        CONSOLE_SCREEN_BUFFER_INFO screenBufferInfo;
     683        GetConsoleScreenBufferInfo(this->stdOutHandle_, &screenBufferInfo);
     684        // dwSize is the maximum size. If you resize you will simply see scroll bars.
     685        // And if you want to write outside these boundaries, you can't.
     686        this->terminalWidth_  = screenBufferInfo.dwSize.X;
     687        this->terminalHeight_ = screenBufferInfo.dwSize.Y;
    545688    }
    546689
     
    552695    void IOConsole::onlyLastLineChanged()
    553696    {
     697        this->moveCursorYAndHome(-1);
     698        this->clearCurrentLine();
     699        this->printLogText(*(this->shell_->getNewestLineIterator()));
     700        this->moveCursorYAndHome(1);
     701        this->moveCursor(this->promptString_.size() + this->shell_->getInput().size(), 0);
     702        this->cout_.flush();
    554703    }
    555704
     
    557706    void IOConsole::lineAdded()
    558707    {
     708        // Move cursor to the beginning of the new (last) output line
     709        this->moveCursorYAndHome(0);
     710        // Print the new output lines
     711        this->printLogText(*(this->shell_->getNewestLineIterator()));
     712        // Move cursor down
     713        this->moveCursorYAndHome(1);
     714        // Print status and input lines
     715        this->printInputLine();
     716        this->printStatusLines();
     717        this->cout_.flush();
    559718    }
    560719}
  • code/branches/presentation2/src/libraries/core/IOConsole.h

    r6105 r6140  
    4141#ifdef ORXONOX_PLATFORM_UNIX
    4242struct termios;
     43#elif defined(ORXONOX_PLATFORM_WINDOWS)
     44#define WIN32_LEAN_AND_MEAN
     45#include <windows.h>
    4346#endif
    4447
     
    9194#ifdef ORXONOX_PLATFORM_UNIX
    9295        termios*                originalTerminalSettings_;
     96#elif defined(ORXONOX_PLATFORM_WINDOWS)
     97        void moveCursor(int dx, int dy);
     98        void moveCursorYAndHome(int dy);
     99        void clearCurrentLine();
     100
     101        DWORD                   originalTerminalSettings_;
     102        HANDLE                  stdInHandle_;
     103        HANDLE                  stdOutHandle_;
    93104#endif
    94105
Note: See TracChangeset for help on using the changeset viewer.