diff --git a/DEPS b/DEPS index 52fdd0d061fcf..966f73e11e249 100644 --- a/DEPS +++ b/DEPS @@ -18,7 +18,7 @@ vars = { 'llvm_git': 'https://llvm.googlesource.com', # OCMock is for testing only so there is no google clone 'ocmock_git': 'https://github.com/erikdoe/ocmock.git', - 'skia_revision': '07b833fd6c79d89593a9735154bf61c5c9d5ad46', + 'skia_revision': '79c3cf00a31b2d4835d666fa3f75ee0e0813e2a7', # WARNING: DO NOT EDIT canvaskit_cipd_instance MANUALLY # See `lib/web_ui/README.md` for how to roll CanvasKit to a new version. diff --git a/ci/licenses_golden/licenses_skia b/ci/licenses_golden/licenses_skia index 0949c5e14b3b6..6149e989cbeb0 100644 --- a/ci/licenses_golden/licenses_skia +++ b/ci/licenses_golden/licenses_skia @@ -1,4 +1,4 @@ -Signature: e3bd2f2fed908d3abff03d8b74fe28a8 +Signature: 9687aa666ab6c3af6d59a35a74087a03 UNUSED LICENSES: diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm index 6f6706305223f..116c94537d9be 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManager.mm @@ -269,9 +269,9 @@ - (void)buildLayout { } // Derive key mapping for each key code based on their layout clues. - // Max key code is 127 for ADB keyboards. - // https://developer.apple.com/documentation/coreservices/1390584-uckeytranslate?language=objc#parameters - const uint16_t kMaxKeyCode = 127; + // Key code 0x00 - 0x32 are typewriter keys (letters, digits, and symbols.) + // See keyCodeToPhysicalKey. + const uint16_t kMaxKeyCode = 0x32; #ifdef DEBUG_PRINT_LAYOUT NSString* debugLayoutData = @""; #endif @@ -303,8 +303,10 @@ - (void)buildLayout { } bool hasAnyEascii = isEascii(thisKeyClues[0]) || isEascii(thisKeyClues[1]); // See if any produced char meets the requirement as a logical key. - if (_layoutMap[@(keyCode)] == nil && !hasAnyEascii) { - _layoutMap[@(keyCode)] = @(usLayoutGoalsByKeyCode[keyCode].keyChar); + auto foundUsLayoutGoal = usLayoutGoalsByKeyCode.find(keyCode); + if (foundUsLayoutGoal != usLayoutGoalsByKeyCode.end() && _layoutMap[@(keyCode)] == nil && + !hasAnyEascii) { + _layoutMap[@(keyCode)] = @(foundUsLayoutGoal->second.keyChar); } } #ifdef DEBUG_PRINT_LAYOUT diff --git a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm index e257e94a9a031..b5fe0e65626f6 100644 --- a/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm +++ b/shell/platform/darwin/macos/framework/Source/FlutterKeyboardManagerUnittests.mm @@ -17,6 +17,7 @@ using flutter::testing::keycodes::kLogicalBracketLeft; using flutter::testing::keycodes::kLogicalDigit1; +using flutter::testing::keycodes::kLogicalDigit2; using flutter::testing::keycodes::kLogicalKeyA; using flutter::testing::keycodes::kLogicalKeyM; using flutter::testing::keycodes::kLogicalKeyQ; @@ -67,26 +68,7 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x0006c, 0x0004c, 0x0006a, 0x0004a, 0x00027, 0x00022, /* 0x28 */ 0x0006b, 0x0004b, 0x0003b, 0x0003a, 0x0005c, 0x0007c, 0x0002c, 0x0003c, /* 0x2c */ 0x0002f, 0x0003f, 0x0006e, 0x0004e, 0x0006d, 0x0004d, 0x0002e, 0x0003e, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x00060, 0x0007e, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002e, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x00060, 0x0007e, }; MockLayoutData kFrenchLayout = { @@ -103,26 +85,7 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x0006c, 0x0004c, 0x0006a, 0x0004a, 0x000f9, 0x00025, /* 0x28 */ 0x0006b, 0x0004b, 0x0006d, 0x0004d, 0x10060, 0x000a3, 0x0003b, 0x0002e, /* 0x2c */ 0x0003d, 0x0002b, 0x0006e, 0x0004e, 0x0002c, 0x0003f, 0x0003a, 0x0002f, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0003c, 0x0003e, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002c, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x00040, 0x00023, 0x0003c, 0x0003e, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0003c, 0x0003e, }; MockLayoutData kRussianLayout = { @@ -139,26 +102,24 @@ typedef void (^AsyncEmbedderCallbackHandler)(const FlutterKeyEvent* event, /* 0x24 */ 0x00000, 0x00000, 0x00434, 0x00414, 0x0043e, 0x0041e, 0x0044d, 0x0042d, /* 0x28 */ 0x0043b, 0x0041b, 0x00436, 0x00416, 0x00451, 0x00401, 0x00431, 0x00411, /* 0x2c */ 0x0002f, 0x0003f, 0x00442, 0x00422, 0x0044c, 0x0042c, 0x0044e, 0x0042e, - /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0005d, 0x0005b, 0x00000, 0x00000, - /* 0x34 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x38 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x3c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x40 */ 0x00000, 0x00000, 0x0002c, 0x0002e, 0x00000, 0x0002a, 0x0002a, 0x0002a, - /* 0x44 */ 0x00000, 0x00000, 0x0002b, 0x0002b, 0x00000, 0x0002b, 0x00000, 0x00000, - /* 0x48 */ 0x00000, 0x0003d, 0x00000, 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002f, - /* 0x4c */ 0x00000, 0x00000, 0x00000, 0x0002f, 0x0002d, 0x0002d, 0x00000, 0x00000, - /* 0x50 */ 0x00000, 0x00000, 0x0003d, 0x0003d, 0x00030, 0x00030, 0x00031, 0x00031, - /* 0x54 */ 0x00032, 0x00032, 0x00033, 0x00033, 0x00034, 0x00034, 0x00035, 0x00035, - /* 0x58 */ 0x00036, 0x00036, 0x00037, 0x00037, 0x00000, 0x00000, 0x00038, 0x00038, - /* 0x5c */ 0x00039, 0x00039, 0x0003e, 0x0003c, 0x0005d, 0x0005b, 0x00000, 0x00000, - /* 0x60 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x64 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x68 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x6c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x70 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x74 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x78 */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, - /* 0x7c */ 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, 0x00000, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x00020, 0x0005d, 0x0005b, +}; + +MockLayoutData kKhmerLayout = { + // +0x0 Shift +0x1 Shift +0x2 Shift +0x3 Shift + /* 0x00 */ 0x017b6, 0x017ab, 0x0179f, 0x017c3, 0x0178a, 0x0178c, 0x01790, 0x01792, + /* 0x04 */ 0x017a0, 0x017c7, 0x01784, 0x017a2, 0x0178b, 0x0178d, 0x01781, 0x01783, + /* 0x08 */ 0x01785, 0x01787, 0x0179c, 0x017c8, 0x00000, 0x00000, 0x01794, 0x01796, + /* 0x0c */ 0x01786, 0x01788, 0x017b9, 0x017ba, 0x017c1, 0x017c2, 0x0179a, 0x017ac, + /* 0x10 */ 0x01799, 0x017bd, 0x0178f, 0x01791, 0x017e1, 0x00021, 0x017e2, 0x017d7, + /* 0x14 */ 0x017e3, 0x00022, 0x017e4, 0x017db, 0x017e6, 0x017cd, 0x017e5, 0x00025, + /* 0x18 */ 0x017b2, 0x017ce, 0x017e9, 0x017b0, 0x017e7, 0x017d0, 0x017a5, 0x017cc, + /* 0x1c */ 0x017e8, 0x017cf, 0x017e0, 0x017b3, 0x017aa, 0x017a7, 0x017c4, 0x017c5, + /* 0x20 */ 0x017bb, 0x017bc, 0x017c0, 0x017bf, 0x017b7, 0x017b8, 0x01795, 0x01797, + /* 0x24 */ 0x00000, 0x00000, 0x0179b, 0x017a1, 0x017d2, 0x01789, 0x017cb, 0x017c9, + /* 0x28 */ 0x01780, 0x01782, 0x017be, 0x017d6, 0x017ad, 0x017ae, 0x017a6, 0x017b1, + /* 0x2c */ 0x017ca, 0x017af, 0x01793, 0x0178e, 0x01798, 0x017c6, 0x017d4, 0x017d5, + /* 0x30 */ 0x00000, 0x00000, 0x00020, 0x0200b, 0x000ab, 0x000bb, }; NSEvent* keyDownEvent(unsigned short keyCode, NSString* chars = @"", NSString* charsUnmod = @"") { @@ -757,6 +718,13 @@ - (bool)correctLogicalKeyForLayouts { sendTap(kVK_ANSI_LeftBracket, @"х", @"х"); VERIFY_DOWN(kLogicalBracketLeft, "х"); + /* Khmer keyboard layout */ + // Regression test for https://github.com/flutter/flutter/issues/108729 + [tester setLayout:kKhmerLayout]; + + sendTap(kVK_ANSI_2, @"២", @"២"); // Digit2 + VERIFY_DOWN(kLogicalDigit2, "២"); + return TRUE; } diff --git a/shell/platform/windows/keyboard_key_embedder_handler.cc b/shell/platform/windows/keyboard_key_embedder_handler.cc index 5d596091a4053..0a072e80551f7 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.cc +++ b/shell/platform/windows/keyboard_key_embedder_handler.cc @@ -186,6 +186,7 @@ void KeyboardKeyEmbedderHandler::KeyboardHookImpl( const bool is_event_down = action == WM_KEYDOWN || action == WM_SYSKEYDOWN; + bool event_key_can_be_repeat = true; UpdateLastSeenCritialKey(key, physical_key, sequence_logical_key); // Synchronize the toggled states of critical keys (such as whether CapsLocks // is enabled). Toggled states can only be changed upon a down event, so if @@ -197,14 +198,15 @@ void KeyboardKeyEmbedderHandler::KeyboardHookImpl( // updated to the true state, while the critical keys whose toggled state have // been changed will be pressed regardless of their true pressed state. // Updating the pressed state will be done by SynchronizeCritialPressedStates. - SynchronizeCritialToggledStates(key, is_event_down); + SynchronizeCritialToggledStates(key, is_event_down, &event_key_can_be_repeat); // Synchronize the pressed states of critical keys (such as whether CapsLocks // is pressed). // // After this function, all critical keys except for the target key will have // their toggled state and pressed state matched with their true states. The // target key's pressed state will be updated immediately after this. - SynchronizeCritialPressedStates(key, physical_key, is_event_down); + SynchronizeCritialPressedStates(key, physical_key, is_event_down, + event_key_can_be_repeat); // The resulting event's `type`. FlutterKeyEventType type; @@ -340,7 +342,8 @@ void KeyboardKeyEmbedderHandler::UpdateLastSeenCritialKey( void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( int event_virtual_key, - bool is_event_down) { + bool is_event_down, + bool* event_key_can_be_repeat) { // NowState ----------------> PreEventState --------------> TrueState // Synchronization Event for (auto& kv : critical_keys_) { @@ -385,6 +388,7 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( key_info.physical_key, key_info.logical_key, empty_character), nullptr, nullptr); + *event_key_can_be_repeat = false; } key_info.toggled_on = true_toggled; } @@ -394,7 +398,8 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates( void KeyboardKeyEmbedderHandler::SynchronizeCritialPressedStates( int event_virtual_key, int event_physical_key, - bool is_event_down) { + bool is_event_down, + bool event_key_can_be_repeat) { // During an incoming event, there might be a synthesized Flutter event for // each key of each pressing goal, followed by an eventual main Flutter // event. @@ -424,8 +429,18 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialPressedStates( if (is_event_down) { // For down events, this key is the event key if they have the same // virtual key, because virtual key represents "functionality." + // + // In that case, normally Flutter should synthesize nothing since the + // resulting event can adapt to the current state by dispatching either + // a down or a repeat event. However, in certain cases (when Flutter has + // just synchronized the key's toggling state) the event must not be a + // repeat event. if (virtual_key == event_virtual_key) { - pre_event_pressed = false; + if (event_key_can_be_repeat) { + continue; + } else { + pre_event_pressed = false; + } } } else { // For up events, this key is the event key if they have the same diff --git a/shell/platform/windows/keyboard_key_embedder_handler.h b/shell/platform/windows/keyboard_key_embedder_handler.h index 426a38d42deab..67ff6490e5fc4 100644 --- a/shell/platform/windows/keyboard_key_embedder_handler.h +++ b/shell/platform/windows/keyboard_key_embedder_handler.h @@ -115,12 +115,14 @@ class KeyboardKeyEmbedderHandler // Check each key's state from |get_key_state_| and synthesize events // if their toggling states have been desynchronized. void SynchronizeCritialToggledStates(int event_virtual_key, - bool is_event_down); + bool is_event_down, + bool* event_key_can_be_repeat); // Check each key's state from |get_key_state_| and synthesize events // if their pressing states have been desynchronized. void SynchronizeCritialPressedStates(int event_virtual_key, int event_physical_key, - bool is_event_down); + bool is_event_down, + bool event_key_can_be_repeat); // Wraps perform_send_event_ with state tracking. Use this instead of // |perform_send_event_| to send events to the framework. diff --git a/shell/platform/windows/keyboard_unittests.cc b/shell/platform/windows/keyboard_unittests.cc index 0bea6b97167d8..f532c1a92af85 100644 --- a/shell/platform/windows/keyboard_unittests.cc +++ b/shell/platform/windows/keyboard_unittests.cc @@ -696,6 +696,18 @@ TEST(KeyboardTest, ShiftLeftUnhandled) { clear_key_calls(); EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); + // Hold ShiftLeft + tester.InjectKeyboardChanges(std::vector{ + WmKeyDownInfo{VK_SHIFT, kScanCodeShiftLeft, kNotExtended, kWasDown}.Build( + kWmResultZero)}); + + EXPECT_EQ(key_calls.size(), 1); + EXPECT_CALL_IS_EVENT(key_calls[0], kFlutterKeyEventTypeRepeat, + kPhysicalShiftLeft, kLogicalShiftLeft, "", + kNotSynthesized); + clear_key_calls(); + EXPECT_EQ(tester.RedispatchedMessageCountAndClear(), 1); + // Release ShiftLeft tester.InjectKeyboardChanges(std::vector{ KeyStateChange{VK_LSHIFT, false, true},