public function readInput($inputStream = STDIN)
    {
        $output = new ConsoleOutput();

        $sttyMode = shell_exec('stty -g');

        // Disable icanon (so we can fread each keypress) and echo (we'll do echoing here instead)
        shell_exec('stty -icanon -echo intr undef');

        $this->userInput = '';
        $this->cursorPosition = 0;

        // Make sure the array cursor of the history is at the last element.
        if (($commands = $this->history->getCommands()) != []) {
            end($commands);
            $this->history->setCommands($commands);
        }

        // Reset the counter for the up arrow.
        $this->countUpPressed = 0;

        // Read a keypress
        while (!feof($inputStream)) {
            $c = fread($inputStream, 1);

            // Backspace Character
            if ("\177" === $c) {
                $this->onBackspacePressed();
            } elseif (ord($c) == 1) { // ctrl+a has been pressed
                $this->moveCursorToBeginOfInputLine();
            } elseif (ord($c) == 3) { // ctrl+c has been pressed
                // todo: exit the shell.
            } elseif (ord($c) == 5) { // ctrl+e has been pressed
                $this->moveCursorToEndOfLine();
            } elseif (ord($c) == 11) { // ctrl+k has been pressed
                $this->removeInputRightFromCursor();
            } elseif ("\033" === $c) {
                // Did we read an escape sequence?
                $c .= fread($inputStream, 2);

                // A = Up Arrow. B = Down Arrow
                if (isset($c[2]) && ('A' === $c[2] || 'B' === $c[2])) {
                    // Clear the current line.
                    $this->clearLine();

                    if ('A' === $c[2]) {
                        $this->onUpArrowPressed();
                    } elseif ('B' === $c[2]) {
                        $this->onDownArrowPressed();
                    }

                } elseif (isset($c[2]) && ('D' === $c[2])) {
                    $this->onLeftArrowPressed();
                } elseif (isset($c[2]) && ('C' === $c[2])) {
                    $this->onRightArrowPressed();
                }
                // Enter key pressed.
            } elseif (ord($c) < 32) {
                if ("\t" === $c || "\n" === $c) {
                    if ("\n" === $c) {
                        $this->onEnterPressed();
                        break;
                    }
                }

                continue;
            } else {
                $this->userInput =
                    substr($this->userInput, 0, $this->cursorPosition) . $c .
                    substr($this->userInput, $this->cursorPosition);

                $this->cursorPosition++;
            }

            $this->printCurrentUserInput();
        }

        // Reset stty so it behaves normally again
        shell_exec(sprintf('stty %s', $sttyMode));

        $userInput = trim($this->userInput);

        return $userInput;
    }