parseUtf8At method

(int, Event?) parseUtf8At(
  1. List<int> buf,
  2. int offset
)

Implementation

(int, Event?) parseUtf8At(List<int> buf, int offset) {
  if (offset >= buf.length) return (0, null);
  final b = buf[offset];

  // Control codes + DEL (0x7F).
  if (b <= 0x1f || b == 0x7f) {
    return (1, parseControl(b));
  }

  // ASCII printable characters.
  if (b >= 0x20 && b < 0x7f) {
    if (b >= 0x41 && b <= 0x5a) {
      // Uppercase A-Z => lower code + shift modifier.
      final lower = b + 0x20;
      return (
        1,
        KeyPressEvent(
          Key(
            code: lower,
            shiftedCode: b,
            text: String.fromCharCode(b),
            mod: KeyMod.shift,
          ),
        ),
      );
    }
    return (1, KeyPressEvent(Key(code: b, text: String.fromCharCode(b))));
  }

  // UTF-8 grapheme clusters: decode runes until we have at least 2 clusters,
  // then return the first one.
  var consumed = 0;
  final sb = StringBuffer();

  while (offset + consumed < buf.length) {
    final decoded = decodeOneRuneAt(buf, offset + consumed);
    if (!decoded.ok) {
      if (decoded.consumed == 0) return (0, null); // need more bytes
      return (1, UnknownEvent(String.fromCharCode(b)));
    }
    consumed += decoded.consumed;
    sb.writeCharCode(decoded.rune);

    final s = sb.toString();
    final it = uni.graphemes(s).iterator;
    if (!it.moveNext()) continue;
    final firstCluster = it.current;
    if (it.moveNext()) {
      final bytesConsumed = utf8.encode(firstCluster).length;
      return (bytesConsumed, _keyFromCluster(firstCluster));
    }
  }

  // Only one grapheme cluster in the available buffer.
  final cluster = sb.toString();
  return (consumed, _keyFromCluster(cluster));
}