decode method

(int, Event?) decode(
  1. List<int> buf, {
  2. bool allowIncompleteEsc = false,
})

Decode the first event in buf.

Returns (bytesConsumed, event) where event may be null if more data is needed.

Implementation

(int, Event?) decode(List<int> buf, {bool allowIncompleteEsc = false}) {
  if (buf.isEmpty) return (0, null);

  final b0 = buf[0];
  // 8-bit control sequence introducers (C1).
  switch (b0) {
    case 0x9b: // CSI
      final (n, ev) = _parseCsi(
        _to7Bit(buf, 0x5b),
        allowIncompleteEsc: allowIncompleteEsc,
      );
      return (n == 0 ? 0 : n - 1, ev);
    case 0x8f: // SS3
      final (n, ev) = _parseSs3(
        _to7Bit(buf, 0x4f),
        allowIncompleteEsc: allowIncompleteEsc,
      );
      return (n == 0 ? 0 : n - 1, ev);
    case 0x9d: // OSC
      return _parseOsc(buf, allowIncompleteEsc: allowIncompleteEsc);
    case 0x90: // DCS
      return _parseDcs(buf, allowIncompleteEsc: allowIncompleteEsc);
    case 0x9f: // APC
      return _parseApc(buf, allowIncompleteEsc: allowIncompleteEsc);
    case 0x9e: // PM
      return _parseStTerminated(
        intro8: 0x9e,
        intro7: 0x5e, // '^'
        kind: 'pm',
        makeUnknown: (s) => UnknownPmEvent(s),
        buf: buf,
        allowIncompleteEsc: allowIncompleteEsc,
      );
    case 0x98: // SOS
      return _parseStTerminated(
        intro8: 0x98,
        intro7: 0x58, // 'X'
        kind: 'sos',
        makeUnknown: (s) => UnknownSosEvent(s),
        buf: buf,
        allowIncompleteEsc: allowIncompleteEsc,
      );
  }

  if (b0 == 0x1b) {
    // ESC
    if (buf.length == 1) {
      return (1, KeyPressEvent(Key(code: keyEscape)));
    }

    // ESC ESC => a literal Escape key followed by another sequence.
    if (buf[1] == 0x1b) {
      return (1, KeyPressEvent(Key(code: keyEscape)));
    }

    // Broken escape-sequence introducers should be treated as Alt-modified keys.
    if (buf.length == 2) {
      final intro = buf[1];
      final shortcut = _brokenEscIntroducerAsKey(intro);
      if (shortcut != null) return (2, shortcut);
    }

    final b1 = buf[1];
    switch (b1) {
      case 0x4f: // 'O' SS3
        return _parseSs3(buf, allowIncompleteEsc: allowIncompleteEsc);
      case 0x50: // 'P' DCS
        return _parseDcs(buf, allowIncompleteEsc: allowIncompleteEsc);
      case 0x5b: // '[' CSI
        return _parseCsi(buf, allowIncompleteEsc: allowIncompleteEsc);
      case 0x5d: // ']' OSC
        return _parseOsc(buf, allowIncompleteEsc: allowIncompleteEsc);
      case 0x5f: // '_' APC
        return _parseApc(buf, allowIncompleteEsc: allowIncompleteEsc);
      case 0x5e: // '^' PM
        return _parseStTerminated(
          intro8: 0x9e,
          intro7: 0x5e,
          kind: 'pm',
          makeUnknown: (s) => UnknownPmEvent(s),
          buf: buf,
          allowIncompleteEsc: allowIncompleteEsc,
        );
      case 0x58: // 'X' SOS
        return _parseStTerminated(
          intro8: 0x98,
          intro7: 0x58,
          kind: 'sos',
          makeUnknown: (s) => UnknownSosEvent(s),
          buf: buf,
          allowIncompleteEsc: allowIncompleteEsc,
        );
      default:
        // Alt-modified sequences: ESC + <utf8/control>
        final (n, ev) = parseUtf8(buf.sublist(1));
        if (n == 0) {
          return allowIncompleteEsc
              ? (1, KeyPressEvent(Key(code: keyEscape)))
              : (0, null);
        }
        if (ev is KeyPressEvent) {
          final k = ev.key();
          return (
            1 + n,
            KeyPressEvent(
              Key(
                code: k.code,
                text: k.text,
                mod: k.mod | KeyMod.alt,
                shiftedCode: k.shiftedCode,
                baseCode: k.baseCode,
                isRepeat: k.isRepeat,
              ),
            ),
          );
        }
        return (1 + n, ev);
    }
  }

  return parseUtf8(buf);
}