readKey function

KeyStroke readKey()

Read key stroke from stdin.

Implementation

KeyStroke readKey() {
  KeyStroke keyStroke;
  int charCode;
  var codeUnit = 0;

  while (codeUnit <= 0) {
    codeUnit = stdin.readByteSync();
  }

  if (codeUnit >= 0x01 && codeUnit <= 0x1a) {
    // Ctrl+A thru Ctrl+Z are mapped to the 1st-26th entries in the
    // enum, so it's easy to convert them across
    keyStroke = KeyStroke.control(ControlCharacter.values[codeUnit]);
  } else if (codeUnit == 0x1b) {
    // escape sequence (e.g. \x1b[A for up arrow)
    keyStroke = KeyStroke.control(ControlCharacter.escape);

    final escapeSequence = <String>[];

    charCode = stdin.readByteSync();
    if (charCode == -1) return keyStroke;

    escapeSequence.add(String.fromCharCode(charCode));

    if (charCode == 127) {
      keyStroke = KeyStroke.control(ControlCharacter.wordBackspace);
    } else if (escapeSequence[0] == '[') {
      charCode = stdin.readByteSync();
      if (charCode == -1) return keyStroke;

      escapeSequence.add(String.fromCharCode(charCode));

      switch (escapeSequence[1]) {
        case 'A':
          keyStroke = KeyStroke.control(ControlCharacter.arrowUp);
        case 'B':
          keyStroke = KeyStroke.control(ControlCharacter.arrowDown);
        case 'C':
          keyStroke = KeyStroke.control(ControlCharacter.arrowRight);
        case 'D':
          keyStroke = KeyStroke.control(ControlCharacter.arrowLeft);
        case 'H':
          keyStroke = KeyStroke.control(ControlCharacter.home);
        case 'F':
          keyStroke = KeyStroke.control(ControlCharacter.end);
        default:
          if (escapeSequence[1].codeUnits[0] > '0'.codeUnits[0] &&
              escapeSequence[1].codeUnits[0] < '9'.codeUnits[0]) {
            charCode = stdin.readByteSync();
            if (charCode == -1) return keyStroke;

            escapeSequence.add(String.fromCharCode(charCode));
            if (escapeSequence[2] != '~') {
              keyStroke = KeyStroke.control(
                ControlCharacter.unknown,
              );
            } else {
              switch (escapeSequence[1]) {
                case '1':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.home,
                  );
                case '3':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.delete,
                  );
                case '4':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.end,
                  );
                case '5':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.pageUp,
                  );
                case '6':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.pageDown,
                  );
                case '7':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.home,
                  );
                case '8':
                  keyStroke = KeyStroke.control(
                    ControlCharacter.end,
                  );
                default:
                  keyStroke = KeyStroke.control(
                    ControlCharacter.unknown,
                  );
              }
            }
          } else {
            keyStroke = KeyStroke.control(ControlCharacter.unknown);
          }
      }
    } else if (escapeSequence[0] == 'O') {
      charCode = stdin.readByteSync();
      if (charCode == -1) return keyStroke;
      escapeSequence.add(String.fromCharCode(charCode));
      assert(
        escapeSequence.length == 2,
        'escape sequence consist of 2 characters',
      );
      switch (escapeSequence[1]) {
        case 'H':
          keyStroke = KeyStroke.control(ControlCharacter.home);
        case 'F':
          keyStroke = KeyStroke.control(ControlCharacter.end);
        case 'P':
          keyStroke = KeyStroke.control(ControlCharacter.F1);
        case 'Q':
          keyStroke = KeyStroke.control(ControlCharacter.F2);
        case 'R':
          keyStroke = KeyStroke.control(ControlCharacter.F3);
        case 'S':
          keyStroke = KeyStroke.control(ControlCharacter.F4);
        default:
      }
    } else if (escapeSequence[0] == 'b') {
      keyStroke = KeyStroke.control(ControlCharacter.wordLeft);
    } else if (escapeSequence[0] == 'f') {
      keyStroke = KeyStroke.control(ControlCharacter.wordRight);
    } else {
      keyStroke = KeyStroke.control(ControlCharacter.unknown);
    }
  } else if (codeUnit == 0x7f) {
    keyStroke = KeyStroke.control(ControlCharacter.backspace);
  } else if (codeUnit == 0x00 || (codeUnit >= 0x1c && codeUnit <= 0x1f)) {
    keyStroke = KeyStroke.control(ControlCharacter.unknown);
  } else {
    // assume other characters are printable
    keyStroke = KeyStroke.char(String.fromCharCode(codeUnit));
  }
  return keyStroke;
}