| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:io'; |
| |
| import 'package:path/path.dart' as path; |
| |
| import 'base_code_gen.dart'; |
| import 'data.dart'; |
| import 'logical_key_data.dart'; |
| import 'physical_key_data.dart'; |
| import 'utils.dart'; |
| |
| bool _isAsciiLetter(String? char) { |
| if (char == null) { |
| return false; |
| } |
| const int charUpperA = 0x41; |
| const int charUpperZ = 0x5A; |
| const int charLowerA = 0x61; |
| const int charLowerZ = 0x7A; |
| assert(char.length == 1); |
| final int charCode = char.codeUnitAt(0); |
| return (charCode >= charUpperA && charCode <= charUpperZ) |
| || (charCode >= charLowerA && charCode <= charLowerZ); |
| } |
| |
| bool _isDigit(String? char) { |
| if (char == null) { |
| return false; |
| } |
| final int charDigit0 = '0'.codeUnitAt(0); |
| final int charDigit9 = '9'.codeUnitAt(0); |
| assert(char.length == 1); |
| final int charCode = char.codeUnitAt(0); |
| return charCode >= charDigit0 && charCode <= charDigit9; |
| } |
| |
| /// Generates the keyboard_maps.g.dart files, based on the information in the key |
| /// data structure given to it. |
| class KeyboardMapsCodeGenerator extends BaseCodeGenerator { |
| KeyboardMapsCodeGenerator(super.keyData, super.logicalData); |
| |
| List<PhysicalKeyEntry> get _numpadKeyData { |
| return keyData.entries.where((PhysicalKeyEntry entry) { |
| return entry.constantName.startsWith('numpad') && LogicalKeyData.printable.containsKey(entry.name); |
| }).toList(); |
| } |
| |
| List<PhysicalKeyEntry> get _functionKeyData { |
| final RegExp functionKeyRe = RegExp(r'^f[0-9]+$'); |
| return keyData.entries.where((PhysicalKeyEntry entry) { |
| return functionKeyRe.hasMatch(entry.constantName); |
| }).toList(); |
| } |
| |
| List<LogicalKeyEntry> get _numpadLogicalKeyData { |
| return logicalData.entries.where((LogicalKeyEntry entry) { |
| return entry.constantName.startsWith('numpad') && LogicalKeyData.printable.containsKey(entry.name); |
| }).toList(); |
| } |
| |
| /// This generates the map of GLFW number pad key codes to logical keys. |
| String get _glfwNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('GLFW numpad map'); |
| for (final PhysicalKeyEntry entry in _numpadKeyData) { |
| final LogicalKeyEntry logicalKey = logicalData.entryByName(entry.name); |
| for (final int code in logicalKey.glfwValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of GLFW key codes to logical keys. |
| String get _glfwKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('GLFW key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int value in entry.glfwValues) { |
| lines.add(value, ' $value: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of GTK number pad key codes to logical keys. |
| String get _gtkNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('GTK numpad map'); |
| for (final LogicalKeyEntry entry in _numpadLogicalKeyData) { |
| for (final int code in entry.gtkValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of GTK key codes to logical keys. |
| String get _gtkKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('GTK key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int code in entry.gtkValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of XKB USB HID codes to physical keys. |
| String get _xkbScanCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('GTK scancode map'); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.xKbScanCode != null) { |
| lines.add(entry.xKbScanCode!, |
| ' ${toHex(entry.xKbScanCode)}: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Android key codes to logical keys. |
| String get _androidKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('Android key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int code in entry.androidValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Android number pad key codes to logical keys. |
| String get _androidNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('Android numpad map'); |
| for (final LogicalKeyEntry entry in _numpadLogicalKeyData) { |
| for (final int code in entry.androidValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Android scan codes to physical keys. |
| String get _androidScanCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('Android scancode map'); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.androidScanCodes != null) { |
| for (final int code in entry.androidScanCodes) { |
| lines.add(code, ' $code: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Windows scan codes to physical keys. |
| String get _windowsScanCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('Windows scancode map'); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.windowsScanCode != null) { |
| lines.add(entry.windowsScanCode!, ' ${entry.windowsScanCode}: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Windows number pad key codes to logical keys. |
| String get _windowsNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('Windows numpad map'); |
| for (final LogicalKeyEntry entry in _numpadLogicalKeyData) { |
| for (final int code in entry.windowsValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Windows key codes to logical keys. |
| String get _windowsKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('Windows key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| // Letter keys on Windows are not recorded in logical_key_data.g.json, |
| // because they are not used by the embedding. Add them manually. |
| final List<int>? keyCodes = entry.windowsValues.isNotEmpty |
| ? entry.windowsValues |
| : (_isAsciiLetter(entry.keyLabel) ? <int>[entry.keyLabel!.toUpperCase().codeUnitAt(0)] : |
| _isDigit(entry.keyLabel) ? <int>[entry.keyLabel!.toUpperCase().codeUnitAt(0)] : |
| null); |
| if (keyCodes != null) { |
| for (final int code in keyCodes) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of macOS key codes to physical keys. |
| String get _macOSScanCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('macOS scancode map'); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.macOSScanCode != null) { |
| lines.add(entry.macOSScanCode!, ' ${toHex(entry.macOSScanCode)}: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of macOS number pad key codes to logical keys. |
| String get _macOSNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('macOS numpad map'); |
| for (final PhysicalKeyEntry entry in _numpadKeyData) { |
| if (entry.macOSScanCode != null) { |
| lines.add(entry.macOSScanCode!, ' ${toHex(entry.macOSScanCode)}: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| String get _macOSFunctionKeyMap { |
| final OutputLines<int> lines = OutputLines<int>('macOS function key map'); |
| for (final PhysicalKeyEntry entry in _functionKeyData) { |
| if (entry.macOSScanCode != null) { |
| lines.add(entry.macOSScanCode!, ' ${toHex(entry.macOSScanCode)}: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of macOS key codes to physical keys. |
| String get _macOSKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('MacOS key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int code in entry.macOSKeyCodeValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of iOS key codes to physical keys. |
| String get _iOSScanCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('iOS scancode map'); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.iOSScanCode != null) { |
| lines.add(entry.iOSScanCode!, ' ${toHex(entry.iOSScanCode)}: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of iOS key label to logical keys for special keys. |
| String get _iOSSpecialMap { |
| final OutputLines<int> lines = OutputLines<int>('iOS special key mapping'); |
| kIosSpecialKeyMapping.forEach((String key, String logicalName) { |
| final LogicalKeyEntry entry = logicalData.entryByName(logicalName); |
| lines.add(entry.value, " '$key': LogicalKeyboardKey.${entry.constantName},"); |
| }); |
| return lines.join().trimRight(); |
| } |
| |
| /// This generates the map of iOS number pad key codes to logical keys. |
| String get _iOSNumpadMap { |
| final OutputLines<int> lines = OutputLines<int>('iOS numpad map'); |
| for (final PhysicalKeyEntry entry in _numpadKeyData) { |
| if (entry.iOSScanCode != null) { |
| lines.add(entry.iOSScanCode!,' ${toHex(entry.iOSScanCode)}: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of macOS key codes to physical keys. |
| String get _iOSKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('iOS key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int code in entry.iOSKeyCodeValues) { |
| lines.add(code, ' $code: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Fuchsia key codes to logical keys. |
| String get _fuchsiaKeyCodeMap { |
| final OutputLines<int> lines = OutputLines<int>('Fuchsia key code map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final int value in entry.fuchsiaValues) { |
| lines.add(value, ' ${toHex(value)}: LogicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Fuchsia USB HID codes to physical keys. |
| String get _fuchsiaHidCodeMap { |
| final StringBuffer fuchsiaScanCodeMap = StringBuffer(); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| if (entry.usbHidCode != null) { |
| fuchsiaScanCodeMap.writeln(' ${toHex(entry.usbHidCode)}: PhysicalKeyboardKey.${entry.constantName},'); |
| } |
| } |
| return fuchsiaScanCodeMap.toString().trimRight(); |
| } |
| |
| /// This generates the map of Web KeyboardEvent codes to logical keys. |
| String get _webLogicalKeyMap { |
| final OutputLines<String> lines = OutputLines<String>('Web logical key map'); |
| for (final LogicalKeyEntry entry in logicalData.entries) { |
| for (final String name in entry.webNames) { |
| lines.add(name, " '$name': LogicalKeyboardKey.${entry.constantName},"); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Web KeyboardEvent codes to physical keys. |
| String get _webPhysicalKeyMap { |
| final OutputLines<String> lines = OutputLines<String>('Web physical key map', behavior: DeduplicateBehavior.kKeep); |
| for (final PhysicalKeyEntry entry in keyData.entries) { |
| for (final String webCodes in entry.webCodes()) { |
| lines.add(entry.name, " '$webCodes': PhysicalKeyboardKey.${entry.constantName},"); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| String get _webNumpadMap { |
| final OutputLines<String> lines = OutputLines<String>('Web numpad map'); |
| for (final LogicalKeyEntry entry in _numpadLogicalKeyData) { |
| if (entry.name != null) { |
| lines.add(entry.name, " '${entry.name}': LogicalKeyboardKey.${entry.constantName},"); |
| } |
| } |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| /// This generates the map of Web number pad codes to logical keys. |
| String get _webLocationMap { |
| final String jsonRaw = File(path.join(dataRoot, 'web_logical_location_mapping.json')).readAsStringSync(); |
| final Map<String, List<String?>> locationMap = parseMapOfListOfNullableString(jsonRaw); |
| final OutputLines<String> lines = OutputLines<String>('Web location map'); |
| locationMap.forEach((String key, List<String?> keyNames) { |
| final String keyStrings = keyNames.map((String? keyName) { |
| final String? constantName = keyName == null ? null : logicalData.entryByName(keyName).constantName; |
| return constantName != null ? 'LogicalKeyboardKey.$constantName' : 'null'; |
| }).join(', '); |
| lines.add(key, " '$key': <LogicalKeyboardKey?>[$keyStrings],"); |
| }); |
| return lines.sortedJoin().trimRight(); |
| } |
| |
| @override |
| String get templatePath => path.join(dataRoot, 'keyboard_maps.tmpl'); |
| |
| @override |
| Map<String, String> mappings() { |
| return <String, String>{ |
| 'ANDROID_SCAN_CODE_MAP': _androidScanCodeMap, |
| 'ANDROID_KEY_CODE_MAP': _androidKeyCodeMap, |
| 'ANDROID_NUMPAD_MAP': _androidNumpadMap, |
| 'FUCHSIA_SCAN_CODE_MAP': _fuchsiaHidCodeMap, |
| 'FUCHSIA_KEY_CODE_MAP': _fuchsiaKeyCodeMap, |
| 'MACOS_SCAN_CODE_MAP': _macOSScanCodeMap, |
| 'MACOS_NUMPAD_MAP': _macOSNumpadMap, |
| 'MACOS_FUNCTION_KEY_MAP': _macOSFunctionKeyMap, |
| 'MACOS_KEY_CODE_MAP': _macOSKeyCodeMap, |
| 'IOS_SCAN_CODE_MAP': _iOSScanCodeMap, |
| 'IOS_SPECIAL_MAP': _iOSSpecialMap, |
| 'IOS_NUMPAD_MAP': _iOSNumpadMap, |
| 'IOS_KEY_CODE_MAP': _iOSKeyCodeMap, |
| 'GLFW_KEY_CODE_MAP': _glfwKeyCodeMap, |
| 'GLFW_NUMPAD_MAP': _glfwNumpadMap, |
| 'GTK_KEY_CODE_MAP': _gtkKeyCodeMap, |
| 'GTK_NUMPAD_MAP': _gtkNumpadMap, |
| 'XKB_SCAN_CODE_MAP': _xkbScanCodeMap, |
| 'WEB_LOGICAL_KEY_MAP': _webLogicalKeyMap, |
| 'WEB_PHYSICAL_KEY_MAP': _webPhysicalKeyMap, |
| 'WEB_NUMPAD_MAP': _webNumpadMap, |
| 'WEB_LOCATION_MAP': _webLocationMap, |
| 'WINDOWS_LOGICAL_KEY_MAP': _windowsKeyCodeMap, |
| 'WINDOWS_PHYSICAL_KEY_MAP': _windowsScanCodeMap, |
| 'WINDOWS_NUMPAD_MAP': _windowsNumpadMap, |
| }; |
| } |
| } |