protected function runLoop()
    {
        while ($this->isListening) {
            $this->stream->select();

            // special key sequence has started
            if (true === $this->charSequenceEnabled && null !== $this->escapePressedAt) {
                if ($this->escapeKeyHasExpired()) {
                    $this->disableKeySequence();

                    $this->setCurrentKey($this->matcher->getKey($this->matcher->getEscapeKey()));

                    // run key listeners, if one of the key callbacks returns true
                    // break the loop and restore default terminal functionality
                    $this->dispatchKeyPressEvents($this->getCurrentKey());
                }
            }

            // proceed if the stream isn't empty
            if ($this->stream->isAvailable()) {
                $char = $this->stream->getChar();

                // start of the special key sequence
                // mark the sequence start and setup the timer for the escape key
                if ($this->matcher->getEscapeKey() === $char) {
                    $this->enableKeySequence();
                    $this->setCurrentKey($char);
                } else {
                    $this->escapePressedAt = null;

                    if ($this->charSequenceEnabled) {
                        // if special key was pressed, concatenate the current
                        // escape character with the next characters that come
                        // in through the stream
                        $this->concatCurrentKey($char);

                        $mapped = $this->matcher->getKey($this->getCurrentKey());
                        // check and get which arrow key was pressed
                        if ($mapped) {
                            $this->setCurrentKey($mapped);
                            $this->disableKeySequence();
                        } else {
                            // we skip this iteration because the sequence isn't
                            // finished yet and we don't need to run the key
                            // listeners
                            continue;
                        }
                    } else {
                        // something out of basic latin charset so we ignore it
                        if ($this->matcher->isBasicLatin($char)) {
                            continue;
                        } else {
                            // normal keyboard key was pressed
                            $this->setCurrentKey($this->matcher->getKey($char) ?: $char);
                        }
                    }

                    // run key listeners, if one of the key callbacks returns true
                    // break the loop and restore default terminal functionality
                    $this->dispatchKeyPressEvents($this->getCurrentKey());
                }
            }
        }

        return $this;
    }