docs: public synchronized KeyStroke getNextCharacter(boolean blockingIO) throws IOException {
  
          KeyStroke bestMatch = null;
          int bestLen = 0;
          int curLen = 0;
  
          while(true) {
  
              if ( curLen < currentMatching.size() ) {
                  // (re-)consume characters previously read:
                  curLen++;
              }
              else {
                  // If we already have a bestMatch but a chance for a longer match
                  //   then we poll for the configured number of timeout units:
                  // It would be much better, if we could just read with a timeout,
                  //   but lacking that, we wait 1/4s units and check for readiness.
                  if (bestMatch != null) {
                      int timeout = getTimeoutUnits();
                      while (timeout > 0 && ! source.ready() ) {
                          try {
                              timeout--; Thread.sleep(250);
                          } catch (InterruptedException e) { timeout = 0; }
                      }
                  }
                  // if input is available, we can just read a char without waiting,
                  // otherwise, for readInput() with no bestMatch found yet,
                  //  we have to wait blocking for more input:
                  if ( source.ready() || ( blockingIO && bestMatch == null ) ) {
                      int readChar = source.read();
                      if (readChar == -1) {
                          seenEOF = true;
                          if(currentMatching.isEmpty()) {
                              return new KeyStroke(KeyType.EOF);
                          }
                          break;
                      }
                      currentMatching.add( (char)readChar );
                      curLen++;
                  } else { // no more available input at this time.
                      // already found something:
                      if (bestMatch != null) {
                          break; // it's something...
                      }
                      // otherwise: no KeyStroke yet
                      return null;
                  }
              }
  
              List<Character> curSub = currentMatching.subList(0, curLen);
              Matching matching = getBestMatch( curSub );
  
              // fullMatch found...
              if (matching.fullMatch != null) {
                  bestMatch = matching.fullMatch;
                  bestLen = curLen;
  
                  if (! matching.partialMatch) {
                      // that match and no more
                      break;
                  } else {
                      // that match, but maybe more
  
                      //noinspection UnnecessaryContinue
                      continue;
                  }
              }
              // No match found yet, but there's still potential...
              else if ( matching.partialMatch ) {
                  //noinspection UnnecessaryContinue
                  continue;
              }
              // no longer match possible at this point:
              else {
                  if (bestMatch != null ) {
                      // there was already a previous full-match, use it:
                      break;
                  } else { // invalid input!
                      // remove the whole fail and re-try finding a KeyStroke...
                      curSub.clear(); // or just 1 char?  currentMatching.remove(0);
                      curLen = 0;
                      //noinspection UnnecessaryContinue
                      continue;
                  }
              }
          }
  
          //Did we find anything? Otherwise return null
          if(bestMatch == null) {
              if(seenEOF) {
                  currentMatching.clear();
                  return new KeyStroke(KeyType.EOF);
              }
              return null;
          }
  
          List<Character> bestSub = currentMatching.subList(0, bestLen );
          bestSub.clear(); // remove matched characters from input
          return bestMatch;
      }