//---------------------------------------------------------------------------------------------
//  Copyright (c) 2022 Google LLC
//  Licensed under the MIT License. See License.txt in the project root for license information.
//--------------------------------------------------------------------------------------------*/

// DO NOT EDIT -- DO NOT EDIT -- DO NOT EDIT
//
// This file is auto generated by flutter/engine:flutter/tools/gen_web_keyboard_keymap based on
// https://github.com/microsoft/vscode/tree/422b581e3802e30cfb780c21d9cc1a2cd0c9f0aa/src/vs/workbench/services/keybinding/browser/keyboardLayouts
//
// Edit the following files instead:
//
//  - Script: lib/main.dart
//  - Templates: data/*.tmpl
//
// See flutter/engine:flutter/tools/gen_web_locale_keymap/README.md for more information.

/// Used in the final mapping indicating the logical key should be derived from
/// KeyboardEvent.keyCode.
///
/// This value is chosen because it's a printable character within EASCII that
/// will never be mapped to (checked in the marshalling algorithm).
const int kUseKeyCode = 0xFF;

/// Used in the final mapping indicating the event key is 'Dead', the dead key.
final String _kUseDead = String.fromCharCode(0xFE);

/// The KeyboardEvent.key for a dead key.
const String _kEventKeyDead = 'Dead';

/// A map of all goals from the scan codes to their mapped value in US layout.
const Map<String, String> kLayoutGoals = <String, String>{
  'KeyA': 'a',
  'KeyB': 'b',
  'KeyC': 'c',
  'KeyD': 'd',
  'KeyE': 'e',
  'KeyF': 'f',
  'KeyG': 'g',
  'KeyH': 'h',
  'KeyI': 'i',
  'KeyJ': 'j',
  'KeyK': 'k',
  'KeyL': 'l',
  'KeyM': 'm',
  'KeyN': 'n',
  'KeyO': 'o',
  'KeyP': 'p',
  'KeyQ': 'q',
  'KeyR': 'r',
  'KeyS': 's',
  'KeyT': 't',
  'KeyU': 'u',
  'KeyV': 'v',
  'KeyW': 'w',
  'KeyX': 'x',
  'KeyY': 'y',
  'KeyZ': 'z',
  'Digit1': '1',
  'Digit2': '2',
  'Digit3': '3',
  'Digit4': '4',
  'Digit5': '5',
  'Digit6': '6',
  'Digit7': '7',
  'Digit8': '8',
  'Digit9': '9',
  'Digit0': '0',
  'Minus': '-',
  'Equal': '=',
  'BracketLeft': '[',
  'BracketRight': ']',
  'Backslash': r'\',
  'Semicolon': ';',
  'Quote': "'",
  'Backquote': '`',
  'Comma': ',',
  'Period': '.',
  'Slash': '/',
};

final int _kLowerA = 'a'.codeUnitAt(0);
final int _kUpperA = 'A'.codeUnitAt(0);
final int _kLowerZ = 'z'.codeUnitAt(0);
final int _kUpperZ = 'Z'.codeUnitAt(0);

bool _isAscii(int charCode) {
  // 0x20 is the first printable character in ASCII.
  return charCode >= 0x20 && charCode <= 0x7F;
}

/// Returns whether the `char` is a single character of a letter or a digit.
bool isLetter(int charCode) {
  return (charCode >= _kLowerA && charCode <= _kLowerZ)
      || (charCode >= _kUpperA && charCode <= _kUpperZ);
}

/// A set of rules that can derive a large number of logical keys simply from
/// the event's code and key.
///
/// This greatly reduces the entries needed in the final mapping.
int? heuristicMapper(String code, String key) {
  // Digit code: return the digit by event code.
  if (code.startsWith('Digit')) {
    assert(code.length == 6);
    return code.codeUnitAt(5); // The character immediately after 'Digit'
  }
  final int charCode = key.codeUnitAt(0);
  // Non-ascii: return the goal (i.e. US mapping by event code).
  if (key.length > 1 || !_isAscii(charCode)) {
    return kLayoutGoals[code]?.codeUnitAt(0);
  }
  // Letter key: return the event key letter.
  if (isLetter(charCode)) {
    return key.toLowerCase().codeUnitAt(0);
  }
  return null;
}

// Maps an integer to a printable EASCII character by adding it to this value.
//
// We could've chosen 0x20, the first printable character, for a slightly bigger
// range, but it's prettier this way and sufficient.
final int _kMarshallIntBase = '0'.codeUnitAt(0);

class _StringStream {
  _StringStream(this._data) : _offset = 0;

  final String _data;
  final Map<int, String> _goalToEventCode = Map<int, String>.fromEntries(
    kLayoutGoals
      .entries
      .map((MapEntry<String, String> beforeEntry) =>
          MapEntry<int, String>(beforeEntry.value.codeUnitAt(0), beforeEntry.key))
  );

  int get offest => _offset;
  int _offset;

  int readIntAsVerbatim() {
    final int result = _data.codeUnitAt(_offset);
    _offset += 1;
    assert(result >= _kMarshallIntBase);
    return result - _kMarshallIntBase;
  }

  int readIntAsChar() {
    final int result = _data.codeUnitAt(_offset);
    _offset += 1;
    return result;
  }

  String readEventKey() {
    final String char = String.fromCharCode(readIntAsChar());
    if (char == _kUseDead) {
      return _kEventKeyDead;
    } else {
      return char;
    }
  }

  String readEventCode() {
    final int charCode = _data.codeUnitAt(_offset);
    _offset += 1;
    return _goalToEventCode[charCode]!;
  }
}

Map<String, int> _unmarshallCodeMap(_StringStream stream) {
  final int entryNum = stream.readIntAsVerbatim();
  return <String, int>{
    for (int i = 0; i < entryNum; i++)
      stream.readEventKey(): stream.readIntAsChar(),
  };
}

/// Decode a key mapping data out of the string.
Map<String, Map<String, int>> unmarshallMappingData(String compressed) {
  final _StringStream stream = _StringStream(compressed);
  final int eventCodeNum = stream.readIntAsVerbatim();
  return <String, Map<String, int>>{
    for (int i = 0; i < eventCodeNum; i++)
      stream.readEventCode() : _unmarshallCodeMap(stream),
  };
}

/// Data for [LocaleKeymap] on Windows.
///
/// Do not use this value, but [LocaleKeymap.win] instead.
///
/// The keys are `KeyboardEvent.code` and then `KeyboardEvent.key`. The values
/// are logical keys or [kUseKeyCode]. Entries that can be derived using
/// heuristics have been omitted.
Map<String, Map<String, int>> getMappingDataWin() {
  return unmarshallMappingData(
    r';'
    r'b1{b'
    r'c1&c'
    r'f1[f'
    r'g1]g'
    r'm2<m?m'
    r'n1}n'
    r'q3/q@q\q'
    r'v1@v'
    r'w3"w?w|w'
    r'x2#x)x'
    r'z2(z>y'
  ); // 59 characters
}

/// Data for [LocaleKeymap] on Linux.
///
/// Do not use this value, but [LocaleKeymap.linux] instead.
///
/// The keys are `KeyboardEvent.code` and then `KeyboardEvent.key`. The values
/// are logical keys or [kUseKeyCode]. Entries that can be derived using
/// heuristics have been omitted.
Map<String, Map<String, int>> getMappingDataLinux() {
  return unmarshallMappingData(
    r'8'
    r'a2@qΩq'
    r'k1&k'
    r'q3@qÆaæa'
    r'w2<z«z'
    r'x1>x'
    r'y2¥ÿ←ÿ'
    r'z5<z»yŁwłw›y'
    r';2µmºm'
  ); // 53 characters
}

/// Data for [LocaleKeymap] on Darwin.
///
/// Do not use this value, but [LocaleKeymap.darwin] instead.
///
/// The keys are `KeyboardEvent.code` and then `KeyboardEvent.key`. The values
/// are logical keys or [kUseKeyCode]. Entries that can be derived using
/// heuristics have been omitted.
Map<String, Map<String, int>> getMappingDataDarwin() {
  return unmarshallMappingData(
    r'M'
    r',2„w∑w'
    r'a2Ωq‡q'
    r'b2˛x≈x'
    r'c3 cÔj∆j'
    r'd2þe´e'
    r'f2þu¨u'
    r'g2þÿˆi'
    r'h3 hÎÿ∂d'
    r'i3 iÇcçc'
    r'j2Óh˙h'
    r'k2ˇÿ†t'
    r'l5 l@lþÿ|l˜n'
    r'm1~m'
    r'n3 nıÿ∫b'
    r'o2®r‰r'
    r'p2¬lÒl'
    r'q2Æaæa'
    r'r3 rπp∏p'
    r's3 sØoøo'
    r't2¥yÁy'
    r'u3 u©g˝g'
    r'v2˚kk'
    r'w2ÂzÅz'
    r'x2Œqœq'
    r'y5 yÏfƒfˇzΩz'
    r'z5 z¥y‡y‹ÿ›w'
    r'.2√v◊v'
    r';4µmÍsÓmßs'
    r'/2¸zΩz'
  ); // 209 characters
}
