Skip to content

Conversation

@777genius
Copy link
Contributor

Description

This PR adds support for Cyrillic (Russian ЙЦУКЕН) keyboard layout in the flutter_tools terminal handler, allowing users to use hot reload, hot restart, and other terminal commands without switching keyboard layouts.

Motivation

Developers working with Cyrillic keyboard layouts currently must switch to a Latin layout every time they want to use terminal commands like hot reload (r/R) or help (h). This disrupts the development workflow and reduces productivity.

Changes

The implementation maps Cyrillic characters to their corresponding Latin equivalents based on physical key positions on QWERTY/ЙЦУКЕН layouts:

  • к/К → r/R (hot reload/restart)
  • й/Й → q/Q (exit)
  • ц/Ц → w/W (dump widget tree)
  • в/В → d/D (detach)
  • р/Р → h/H (help)
  • ш/Ш → i/I (widget inspector/invert images)
  • ы/Ы → s/S (screenshot/semantics)
  • е/Е → t/T (render tree)
  • м/М → v/V (DevTools)
  • а → f (focus tree)
  • п → g (source generators)
  • Д → L (layer tree)
  • щ/Щ → o/O (platform toggle)
  • з/З → p/P (debug paint/performance overlay)
  • Г → U (semantics inverse order)
  • ф → a (profile widgets)
  • и → b (brightness)
  • с → c (clear)

Testing

  • Added comprehensive test coverage for Cyrillic keyboard commands
  • All existing terminal_handler tests pass
  • Verified that Cyrillic characters trigger the same actions as their Latin equivalents

Impact

This change improves the developer experience for users working with Cyrillic keyboard layouts by eliminating the need for constant layout switching during development. The implementation follows Flutter code style guidelines and does not affect existing functionality.

@github-actions github-actions bot added the tool Affects the "flutter" command-line tool. See also t: labels. label Oct 31, 2025
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Cyrillic keyboard layouts in the flutter_tools terminal, which is a valuable enhancement for developers using these layouts. The implementation correctly maps Cyrillic characters to their Latin equivalents, and the new functionality is well-tested. My feedback includes suggestions to refactor the growing switch statement into a more maintainable Map and to adopt a data-driven approach for the new tests to reduce code duplication.

@777genius 777genius force-pushed the feature/cyrillic-keyboard-support branch 4 times, most recently from 0b80293 to 5116ca1 Compare October 31, 2025 19:43
@bkonyi
Copy link
Contributor

bkonyi commented Nov 3, 2025

Thanks for the contribution @777genius! Do you happen to know if there's already an issue filed for this? If so, could you link it here? Otherwise, we should file an issue describing the problem so that we can continue to track work in this area.

This approach does work, but I'm sure if you're encountering this issue for Cyrillic keyboard layouts, other users are encountering if with other layouts as well. This means that we should probably come up with a more generalizable solution that allows for us to add mappings for other languages as well without having to introduce case statements for each individual mapping.

I think this can be done by creating a String mapKeyToLatin(String key) which will try and lookup key in a Map<String, String>, returning the latin character if the key has a valid mapping, and returning key itself otherwise. Then we don't have to add new cases to the switch statement, and we can have a constant Map that can be easily updated with new mappings as they're requested.

@bkonyi
Copy link
Contributor

bkonyi commented Nov 10, 2025

Hi @777genius, is this something you're still interested in pursuing?

@bkonyi bkonyi added the waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds label Nov 10, 2025
@777genius
Copy link
Contributor Author

Thank you for the feedback, @bkonyi! You're absolutely right about making this more generalizable. I found several related issues that confirm this is a broader problem affecting multiple keyboard layouts:

#27021 - Flutter run not handling keypresses with non-English layouts (Cyrillic, closed in 2020 but the terminal command issue persists)
#100456 - Keyboard layout analysis for non-Latin layouts, specifically mentions Cyrillic users
#116658 - Making shortcuts portable across different keyboard layouts
I agree that using a Map<String, String> approach is much cleaner and more maintainable. I'll refactor the implementation to:

I agree that using a Map<String, String> approach is much cleaner and more maintainable. I'll refactor the implementation to use your suggested approach:

  1. Create a constant map with all keyboard layout mappings:
/// Maps non-Latin keyboard layout characters to their Latin equivalents
/// based on physical key positions.
///
/// This allows users with non-Latin keyboard layouts to use terminal commands
/// without switching layouts. Contributors can add mappings for additional
/// layouts (Arabic, Hebrew, Greek, etc.) by adding entries to this map.
const Map<String, String> _keyboardLayoutMappings = {
  // Cyrillic (Russian ЙЦУКЕН) layout -> QWERTY Latin
  'к': 'r', 'К': 'R',  // hot reload / hot restart
  'й': 'q', 'Й': 'Q',  // quit
  'ц': 'w', 'Ц': 'W',  // dump widget tree
  'р': 'h', 'Р': 'H',  // help
  'ы': 's', 'Ы': 'S',  // screenshot / semantics
  'в': 'd', 'В': 'D',  // detach
  'а': 'f', 'А': 'F',  // dump focus tree
  'п': 'g', 'П': 'G',  // run source generators
  'ш': 'i', 'Ш': 'I',  // widget inspector / invert images
  'д': 'l', 'Д': 'L',  // dump layer tree
  'щ': 'o', 'Щ': 'O',  // toggle platform
  'з': 'p', 'З': 'P',  // debug paint / performance overlay
  'т': 'n', 'Т': 'N',  // (reserved for future use)
  'е': 't', 'Е': 'T',  // dump render tree
  'г': 'u', 'Г': 'U',  // dump semantics (inverse hit test)
  'м': 'v', 'М': 'V',  // open DevTools
  // TODO: Add mappings for other non-Latin layouts as needed
};
  1. Implement the lookup function:
/// Maps a keyboard character to its Latin equivalent if a mapping exists.
/// Returns the original character if no mapping is found.
String _mapKeyToLatin(String key) {
  return _keyboardLayoutMappings[key] ?? key;
}
  1. Use it at the start of the command handler:
Future<bool> _commonTerminalInputHandler(String character) async {
  // Map non-Latin characters to Latin equivalents based on physical key position
  character = _mapKeyToLatin(character);
  
  _logger.printStatus('');
  switch (character) {
    case 'a':
      return residentRunner.debugToggleProfileWidgetBuilds();
    case 'r':
      // ... existing hot reload logic
    // ... rest of the switch statement remains unchanged
  }
}

This approach has several benefits:

  • New keyboard layouts can be added by simply extending the map
  • No changes needed to the switch statement logic
  • Easy for contributors to add their own layouts
  • Clear documentation showing which keys map to which commands

How do you like the solution?

@bkonyi
Copy link
Contributor

bkonyi commented Nov 11, 2025

That sounds good to me!

@777genius 777genius force-pushed the feature/cyrillic-keyboard-support branch from 5116ca1 to af39447 Compare November 13, 2025 20:42
…mmands

Implements a keyboard layout mapping layer that allows users with non-Latin
layouts to use flutter_tools terminal commands without switching layouts.

The implementation uses a Map-based approach for character translation,
mapping characters based on physical key positions rather than linguistic
equivalents. This design makes it easy for contributors to add support for
additional layouts (Arabic, Hebrew, Greek, etc.).

Includes comprehensive test coverage following Flutter's testing patterns,
with tests for basic functionality, error handling (fatal/non-fatal), and
unsupported operations.

Fixes: flutter#27021, flutter#100456, flutter#116658
@777genius 777genius force-pushed the feature/cyrillic-keyboard-support branch from af39447 to 5eec195 Compare November 13, 2025 20:43
@777genius
Copy link
Contributor Author

@bkonyi Please take a look with your professional eye.

Updated the implementation to use the Map-based approach as suggested. Changes include:

  • Refactored to use _keyboardLayoutMappings static const Map for character translation
  • Added _mapKeyToLatin() helper function for cleaner integration
  • Comprehensive test coverage (13 tests) following Flutter's testing patterns
  • Tests cover basic functionality, error handling (fatal/non-fatal), and unsupported operations

The implementation is now much more maintainable and makes it easy to add support for other keyboard layouts (Arabic, Hebrew, Greek, etc.) in the future.

Ready for review!

@bkonyi
Copy link
Contributor

bkonyi commented Nov 25, 2025

Sorry for the delay @777genius. I'll review this today!

Copy link
Contributor

@bkonyi bkonyi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments, but looks good overall!

static const _keyboardLayoutMappings = <String, String>{
// Cyrillic (Russian ЙЦУКЕН) layout → QWERTY Latin
// Maps based on physical key positions for terminal commands
'к': 'r', 'К': 'R', // hot reload / hot restart
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment here warning that these keys are not QWERTY Latin, even if they look identical? That way future contributors know that р is not p 😅

switch (character) {
case 'a':
case 'ф': // 'a' in Cyrillic (QWERTY 'a' → ЙЦУКЕН 'ф')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these cases needed anymore since _mapKeyToLatin(...) does the conversion?

.file(globals.artifacts!.getHostArtifact(HostArtifact.flutterWebLibrariesJson))
.uri
.toString(),
librariesSpec:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you may have accidentally formatted these files with an older version of the Dart formatter. Can you upgrade your Flutter installation to the latest stable and format this again?

- Add warning comment about visually similar Cyrillic/Latin characters
- Remove redundant Cyrillic cases from switch (already handled by _mapKeyToLatin)
- Update docstring to reference _keyboardLayoutMappings
- Reformat with latest dart formatter
@777genius
Copy link
Contributor Author

@bkonyi Thanks for the top-level review! I've addressed all your comments:

  1. Added a warning comment explaining that some Cyrillic characters look visually identical to Latin but are different
    Unicode code points (e.g., 'р' U+0440 maps to 'h', not 'p')
  2. Removed redundant Cyrillic cases from the switch statement since _mapKeyToLatin() already handles the conversion
    before the switch
  3. Reformatted with the latest Dart formatter

Ready for another look!

@bkonyi
Copy link
Contributor

bkonyi commented Dec 11, 2025

Thanks for addressing the comments @777genius! This LGTM!

@chingjun would you mind giving a second review?

@bkonyi bkonyi requested a review from chingjun December 11, 2025 15:52
@chingjun
Copy link
Contributor

Linux analyze is failing because the code is not properly formatted, can you run dart format?

Also, can we add a test, or an assert, that we never add regular ASCII characters as keys in the _keyboardLayoutMappings map? They are impossible to tell if someone made a mistake.

- Format terminal_handler_test.dart
- Expose keyboardLayoutMappings with @VisibleForTesting
- Add test to ensure mapping keys have code points > 127
  (prevents accidental addition of Latin characters as keys)
@777genius 777genius force-pushed the feature/cyrillic-keyboard-support branch from bb6195c to 13df6fb Compare December 13, 2025 15:39
@777genius
Copy link
Contributor Author

@chingjun Thank you for the review and helpful suggestions! CI is green.

@bkonyi bkonyi added the autosubmit Merge PR when tree becomes green via auto submit App label Dec 16, 2025
@auto-submit auto-submit bot added this pull request to the merge queue Dec 16, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 18, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 19, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 19, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 19, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 19, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 19, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 20, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 20, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 21, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 21, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 21, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 22, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 22, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 22, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Dec 23, 2025
stuartmorgan-g pushed a commit to flutter/packages that referenced this pull request Dec 23, 2025
Manual roll Flutter from d81baab to 57c3f8b (38 revisions)

Manual roll requested by stuartmorgan@google.com

flutter/flutter@d81baab...57c3f8b

2025-12-17 bruno.leroux@gmail.com Add FloatingActionButtonTheme
(flutter/flutter#179736)
2025-12-17 engine-flutter-autoroll@skia.org Roll Skia from b1569739f431
to fb576bd6827a (1 revision) (flutter/flutter#179989)
2025-12-17 bruno.leroux@gmail.com Update more comments related to theme
normalization (flutter/flutter#179682)
2025-12-17 engine-flutter-autoroll@skia.org Roll Skia from cce9b86bda7d
to b1569739f431 (1 revision) (flutter/flutter#179979)
2025-12-17 jobguldemeester@gmail.com Adds property passthrough for
CheckboxListTile, SwitchListTile and RadioListTile
(flutter/flutter#178098)
2025-12-17 engine-flutter-autoroll@skia.org Roll Dart SDK from
ca949b915846 to 3793f3d2d0c4 (2 revisions) (flutter/flutter#179973)
2025-12-17 engine-flutter-autoroll@skia.org Roll Skia from 318400199beb
to cce9b86bda7d (1 revision) (flutter/flutter#179976)
2025-12-17 ahmedsameha1@gmail.com Make sure that a
CupertinoTextFormFieldRow doesn't crash in 0x0 envir…
(flutter/flutter#179932)
2025-12-17 ahmedsameha1@gmail.com Make sure that a CupertinoTabView
doesn't crash in 0x0 environment (flutter/flutter#179845)
2025-12-17 ahmedsameha1@gmail.com Make sure that a CupertinoTextField
doesn't crash in 0x0 environment (flutter/flutter#179865)
2025-12-17 ahmedsameha1@gmail.com Make sure that a CupertinoSwitch
doesn't crash in 0x0 environment (flutter/flutter#179748)
2025-12-17 116356835+AbdeMohlbi@users.noreply.github.com Update
`BuildContext` docs to make it easier to understand
(flutter/flutter#178616)
2025-12-17 41930132+hellohuanlin@users.noreply.github.com [ios][pv]
quick fix to enable and re-enable web view's gesture recognizer
(flutter/flutter#179908)
2025-12-17 biggs0125@gmail.com Deduplicate wasm dry run entries in
analytics. (flutter/flutter#179970)
2025-12-17 engine-flutter-autoroll@skia.org Roll Skia from 99899cbb415b
to 318400199beb (1 revision) (flutter/flutter#179969)
2025-12-17 engine-flutter-autoroll@skia.org Roll Skia from 2ac4a8709bc9
to 99899cbb415b (1 revision) (flutter/flutter#179968)
2025-12-17 engine-flutter-autoroll@skia.org Roll Dart SDK from
95a92bc705d3 to ca949b915846 (6 revisions) (flutter/flutter#179967)
2025-12-17 biggs0125@gmail.com Add package info to wasm dry run events.
(flutter/flutter#179826)
2025-12-17 matt.boetger@gmail.com Platform View Hide/Show Integration
test (flutter/flutter#179902)
2025-12-16 engine-flutter-autoroll@skia.org Roll Skia from 61162d72343f
to 2ac4a8709bc9 (14 revisions) (flutter/flutter#179961)
2025-12-16 engine-flutter-autoroll@skia.org Roll Fuchsia Linux SDK from
433KtmJvbMyaDMJvD... to fAoyBAT99XxwPE5hL... (flutter/flutter#179960)
2025-12-16 bkonyi@google.com [ Tool ] Fix update-packages not accounting
for path dependencies (flutter/flutter#179951)
2025-12-16 45459898+RamonFarizel@users.noreply.github.com ListTile fix
MinIntrinsicHeight calculation (flutter/flutter#179515)
2025-12-16 108678139+manu-sncf@users.noreply.github.com Fix pinned
header in NestedScrollView (flutter/flutter#179210)
2025-12-16 bruno.leroux@gmail.com Update some comments related to theme
normalization (flutter/flutter#179624)
2025-12-16 iliyazelenkog@gmail.com Add Cyrillic keyboard layout support
for flutter_tools terminal commands (flutter/flutter#177855)
2025-12-16 lauren@selfisekai.rocks Minor fixes for libstdc++ 15
(flutter/flutter#178601)
2025-12-16 34465683+rkishan516@users.noreply.github.com Feat: Add top
gap for cupertino sheet (flutter/flutter#171348)
2025-12-16 116356835+AbdeMohlbi@users.noreply.github.com Align
`Build.API_LEVELS` usage in `FlutterImageDecoder.java‎` with existing
usage (flutter/flutter#179868)
2025-12-16 41930132+hellohuanlin@users.noreply.github.com Revert
"[ios][pv] accept/reject gesture based on hitTest (with new wi…
(flutter/flutter#179895)
2025-12-16 codefu@google.com fix: line endings for
flutter/dart/flutter-dev (flutter/flutter#179912)
2025-12-16 22373191+Hari-07@users.noreply.github.com Platform view blur
clipping - Rounded Rect (iOS) (flutter/flutter#177551)
2025-12-16 engine-flutter-autoroll@skia.org Roll Dart SDK from
20d114f951db to 95a92bc705d3 (1 revision) (flutter/flutter#179909)
2025-12-16 34871572+gmackall@users.noreply.github.com [Reland]
Unmodified android sdk bundle (flutter/flutter#179920)
2025-12-16 engine-flutter-autoroll@skia.org Roll Skia from 6903a4e65c3f
to 61162d72343f (2 revisions) (flutter/flutter#179915)
2025-12-16 engine-flutter-autoroll@skia.org Roll Packages from
2cd921c to 57725eb (1 revision) (flutter/flutter#179942)
2025-12-16 45490440+shindonghwi@users.noreply.github.com Filter out
FrameEvents/updateAcquireFence log spam from adb logcat
(flutter/flutter#179884)
2025-12-16 30870216+gaaclarke@users.noreply.github.com `flutter
update-packages --force-upgrade --update-hashes`
(flutter/flutter#179950)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC bmparr@google.com,stuartmorgan@google.com on the revert to
ensure that a human
is aware of the problem.
...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

tool Affects the "flutter" command-line tool. See also t: labels. waiting for customer response The Flutter team cannot make further progress on this issue until the original reporter responds

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants