cc_code_gen.dart 11.8 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6 7 8 9 10 11 12
// 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 'package:gen_keycodes/key_data.dart';
import 'package:gen_keycodes/utils.dart';

/// Generates the keyboard_keys.dart and keyboard_maps.dart files, based on the
/// information in the key data structure given to it.
13 14
class CcCodeGenerator {
  CcCodeGenerator(this.keyData);
15 16 17

  /// Given an [input] string, wraps the text at 80 characters and prepends each
  /// line with the [prefix] string. Use for generated comments.
18
  String wrapString(String input, {String prefix = '  // '}) {
19 20 21 22
    final int wrapWidth = 80 - prefix.length;
    final StringBuffer result = StringBuffer();
    final List<String> words = input.split(RegExp(r'\s+'));
    String currentLine = words.removeAt(0);
23
    for (final String word in words) {
24 25 26 27
      if ((currentLine.length + word.length) < wrapWidth) {
        currentLine += ' $word';
      } else {
        result.writeln('$prefix$currentLine');
28
        currentLine = word;
29 30 31 32 33 34 35 36
      }
    }
    if (currentLine.isNotEmpty) {
      result.writeln('$prefix$currentLine');
    }
    return result.toString();
  }

Mouad Debbar's avatar
Mouad Debbar committed
37 38 39 40 41 42
  List<Key> get numpadKeyData {
    return keyData.data.where((Key entry) {
      return entry.constantName.startsWith('numpad') && entry.keyLabel != null;
    }).toList();
  }

43 44 45 46 47 48 49
  List<Key> get functionKeyData {
    final RegExp functionKeyRe = RegExp(r'^f[0-9]+$');
    return keyData.data.where((Key entry) {
      return functionKeyRe.hasMatch(entry.constantName);
    }).toList();
  }

50
  /// This generates the map of Flutter key codes to logical keys.
51 52
  String get predefinedKeyCodeMap {
    final StringBuffer keyCodeMap = StringBuffer();
53
    for (final Key entry in keyData.data) {
54 55
      keyCodeMap.writeln('    ${toHex(entry.flutterId, digits: 10)}: ${entry.constantName},');
    }
56
    for (final String entry in Key.synonyms.keys) {
57 58 59 60 61 62 63 64 65
      // Use the first item in the synonyms as a template for the ID to use.
      // It won't end up being the same value because it'll be in the pseudo-key
      // plane.
      final Key primaryKey = keyData.data.firstWhere((Key item) {
        return item.name == Key.synonyms[entry][0];
      }, orElse: () => null);
      assert(primaryKey != null);
      keyCodeMap.writeln('    ${toHex(Key.synonymPlane | primaryKey.flutterId, digits: 10)}: $entry,');
    }
66 67 68
    return keyCodeMap.toString().trimRight();
  }

69 70 71
  /// This generates the map of GLFW number pad key codes to logical keys.
  String get glfwNumpadMap {
    final StringBuffer glfwNumpadMap = StringBuffer();
72
    for (final Key entry in numpadKeyData) {
73
      if (entry.glfwKeyCodes != null) {
74
        for (final int code in entry.glfwKeyCodes.cast<int>()) {
75
          glfwNumpadMap.writeln('  { $code, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
76 77 78 79 80 81 82 83 84
        }
      }
    }
    return glfwNumpadMap.toString().trimRight();
  }

  /// This generates the map of GLFW key codes to logical keys.
  String get glfwKeyCodeMap {
    final StringBuffer glfwKeyCodeMap = StringBuffer();
85
    for (final Key entry in keyData.data) {
86
      if (entry.glfwKeyCodes != null) {
87
        for (final int code in entry.glfwKeyCodes.cast<int>()) {
88
          glfwKeyCodeMap.writeln('  { $code, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
89 90 91 92 93 94
        }
      }
    }
    return glfwKeyCodeMap.toString().trimRight();
  }

95
  /// This generates the map of XKB scan codes to USB HID codes.
96 97
  String get xkbScanCodeMap {
    final StringBuffer xkbScanCodeMap = StringBuffer();
98
    for (final Key entry in keyData.data) {
99
      if (entry.xKbScanCode != null) {
100
        xkbScanCodeMap.writeln('  { ${toHex(entry.xKbScanCode)}, ${toHex(entry.usbHidCode)} },    // ${entry.constantName}');
101 102 103 104 105
      }
    }
    return xkbScanCodeMap.toString().trimRight();
  }

106 107 108
  /// This generates the map of Android key codes to logical keys.
  String get androidKeyCodeMap {
    final StringBuffer androidKeyCodeMap = StringBuffer();
109
    for (final Key entry in keyData.data) {
110
      if (entry.androidKeyCodes != null) {
111
        for (final int code in entry.androidKeyCodes.cast<int>()) {
112
          androidKeyCodeMap.writeln('  { $code, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
113 114 115 116 117 118 119 120 121
        }
      }
    }
    return androidKeyCodeMap.toString().trimRight();
  }

  /// This generates the map of Android number pad key codes to logical keys.
  String get androidNumpadMap {
    final StringBuffer androidKeyCodeMap = StringBuffer();
122
    for (final Key entry in numpadKeyData) {
123
      if (entry.androidKeyCodes != null) {
124
        for (final int code in entry.androidKeyCodes.cast<int>()) {
125
          androidKeyCodeMap.writeln('  { $code, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
126 127 128 129 130 131 132 133 134
        }
      }
    }
    return androidKeyCodeMap.toString().trimRight();
  }

  /// This generates the map of Android scan codes to physical keys.
  String get androidScanCodeMap {
    final StringBuffer androidScanCodeMap = StringBuffer();
135
    for (final Key entry in keyData.data) {
136
      if (entry.androidScanCodes != null) {
137
        for (final int code in entry.androidScanCodes.cast<int>()) {
138
          androidScanCodeMap.writeln('  { $code, ${toHex(entry.usbHidCode)} },    // ${entry.constantName}');
139 140 141 142 143 144
        }
      }
    }
    return androidScanCodeMap.toString().trimRight();
  }

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
  /// This generates the map of Windows scan codes to physical keys.
  String get windowsScanCodeMap {
    final StringBuffer windowsScanCodeMap = StringBuffer();
    for (final Key entry in keyData.data) {
      if (entry.windowsScanCode != null) {
        windowsScanCodeMap.writeln('  { ${entry.windowsScanCode}, ${toHex(entry.usbHidCode)} },    // ${entry.constantName}');
      }
    }
    return windowsScanCodeMap.toString().trimRight();
  }

  /// This generates the map of Windows number pad key codes to logical keys.
  String get windowsNumpadMap {
    final StringBuffer windowsNumPadMap = StringBuffer();
    for (final Key entry in numpadKeyData) {
      if (entry.windowsScanCode != null) {
        windowsNumPadMap.writeln('  { ${toHex(entry.windowsScanCode)}, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
      }
    }
    return windowsNumPadMap.toString().trimRight();
  }

  /// This generates the map of Android key codes to logical keys.
  String get windowsKeyCodeMap {
    final StringBuffer windowsKeyCodeMap = StringBuffer();
    for (final Key entry in keyData.data) {
      if (entry.windowsKeyCodes != null) {
        for (final int code in entry.windowsKeyCodes.cast<int>()) {
          windowsKeyCodeMap.writeln('  { $code, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
        }
      }
    }
    return windowsKeyCodeMap.toString().trimRight();
  }

180 181 182
  /// This generates the map of macOS key codes to physical keys.
  String get macOsScanCodeMap {
    final StringBuffer macOsScanCodeMap = StringBuffer();
183
    for (final Key entry in keyData.data) {
184
      if (entry.macOsScanCode != null) {
185
        macOsScanCodeMap.writeln('  { ${toHex(entry.macOsScanCode)}, ${toHex(entry.usbHidCode)} },    // ${entry.constantName}');
186 187 188 189 190 191 192 193
      }
    }
    return macOsScanCodeMap.toString().trimRight();
  }

  /// This generates the map of macOS number pad key codes to logical keys.
  String get macOsNumpadMap {
    final StringBuffer macOsNumPadMap = StringBuffer();
194
    for (final Key entry in numpadKeyData) {
195
      if (entry.macOsScanCode != null) {
196
        macOsNumPadMap.writeln('  { ${toHex(entry.macOsScanCode)}, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
197 198 199 200 201
      }
    }
    return macOsNumPadMap.toString().trimRight();
  }

202 203
  String get macOsFunctionKeyMap {
    final StringBuffer macOsFunctionKeyMap = StringBuffer();
204
    for (final Key entry in functionKeyData) {
205
      if (entry.macOsScanCode != null) {
206
        macOsFunctionKeyMap.writeln('  { ${toHex(entry.macOsScanCode)}, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
207 208 209 210 211
      }
    }
    return macOsFunctionKeyMap.toString().trimRight();
  }

212 213 214
  /// This generates the map of Fuchsia key codes to logical keys.
  String get fuchsiaKeyCodeMap {
    final StringBuffer fuchsiaKeyCodeMap = StringBuffer();
215
    for (final Key entry in keyData.data) {
216
      if (entry.usbHidCode != null) {
217
        fuchsiaKeyCodeMap.writeln('  { ${toHex(entry.flutterId)}, ${toHex(entry.flutterId, digits: 10)} },    // ${entry.constantName}');
218 219 220 221 222 223 224 225
      }
    }
    return fuchsiaKeyCodeMap.toString().trimRight();
  }

  /// This generates the map of Fuchsia USB HID codes to physical keys.
  String get fuchsiaHidCodeMap {
    final StringBuffer fuchsiaScanCodeMap = StringBuffer();
226
    for (final Key entry in keyData.data) {
227
      if (entry.usbHidCode != null) {
228
        fuchsiaScanCodeMap.writeln(' { ${toHex(entry.usbHidCode)}, ${toHex(entry.usbHidCode)} },    // ${entry.constantName}');
229 230 231 232 233
      }
    }
    return fuchsiaScanCodeMap.toString().trimRight();
  }

Mouad Debbar's avatar
Mouad Debbar committed
234 235 236
  /// This generates the map of Web KeyboardEvent codes to logical keys.
  String get webLogicalKeyMap {
    final StringBuffer result = StringBuffer();
237
    for (final Key entry in keyData.data) {
Mouad Debbar's avatar
Mouad Debbar committed
238
      if (entry.name != null) {
239
        result.writeln("  '${entry.name}': ${toHex(entry.flutterId, digits: 10)},    // ${entry.constantName}");
Mouad Debbar's avatar
Mouad Debbar committed
240 241 242 243 244 245 246 247
      }
    }
    return result.toString().trimRight();
  }

  /// This generates the map of Web KeyboardEvent codes to physical keys.
  String get webPhysicalKeyMap {
    final StringBuffer result = StringBuffer();
248
    for (final Key entry in keyData.data) {
Mouad Debbar's avatar
Mouad Debbar committed
249
      if (entry.name != null) {
250
        result.writeln("  '${entry.name}': ${toHex(entry.usbHidCode)},    // ${entry.constantName}");
Mouad Debbar's avatar
Mouad Debbar committed
251 252 253 254 255 256 257 258
      }
    }
    return result.toString().trimRight();
  }

  /// This generates the map of Web number pad codes to logical keys.
  String get webNumpadMap {
    final StringBuffer result = StringBuffer();
259
    for (final Key entry in numpadKeyData) {
Mouad Debbar's avatar
Mouad Debbar committed
260
      if (entry.name != null) {
261
        result.writeln("  '${entry.name}': ${toHex(entry.flutterId, digits: 10)},    // ${entry.constantName}");
Mouad Debbar's avatar
Mouad Debbar committed
262 263 264 265 266
      }
    }
    return result.toString().trimRight();
  }

267 268
  /// Substitutes the various platform specific maps into the template file for
  /// keyboard_maps.dart.
269
  String generateKeyboardMaps(String platform) {
270 271 272
    // There is no macOS keycode map since macOS uses keycode to represent a physical key.
    // The LogicalKeyboardKey is generated by raw_keyboard_macos.dart from the unmodified characters
    // from NSEvent.
273 274 275 276 277 278
    final Map<String, String> mappings = <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,
279 280
      'MACOS_SCAN_CODE_MAP': macOsScanCodeMap,
      'MACOS_NUMPAD_MAP': macOsNumpadMap,
281
      'MACOS_FUNCTION_KEY_MAP': macOsFunctionKeyMap,
282 283 284
      'GLFW_KEY_CODE_MAP': glfwKeyCodeMap,
      'GLFW_NUMPAD_MAP': glfwNumpadMap,
      'XKB_SCAN_CODE_MAP': xkbScanCodeMap,
Mouad Debbar's avatar
Mouad Debbar committed
285 286 287
      'WEB_LOGICAL_KEY_MAP': webLogicalKeyMap,
      'WEB_PHYSICAL_KEY_MAP': webPhysicalKeyMap,
      'WEB_NUMPAD_MAP': webNumpadMap,
288 289 290
      'WINDOWS_SCAN_CODE_MAP': windowsScanCodeMap,
      'WINDOWS_NUMPAD_MAP': windowsNumpadMap,
      'WINDOWS_KEY_CODE_MAP': windowsKeyCodeMap,
291 292
    };

293
    final String template = File(path.join(flutterRoot.path, 'dev', 'tools', 'gen_keycodes', 'data', 'keyboard_map_${platform}_cc.tmpl')).readAsStringSync();
294 295 296 297 298 299 300 301
    return _injectDictionary(template, mappings);
  }

  /// The database of keys loaded from disk.
  final KeyData keyData;

  static String _injectDictionary(String template, Map<String, String> dictionary) {
    String result = template;
302
    for (final String key in dictionary.keys) {
303 304 305 306 307
      result = result.replaceAll('@@@$key@@@', dictionary[key]);
    }
    return result;
  }
}