Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion lib/ui/key.dart
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,17 @@ class KeyData {
}
}

String? _quotedCharCode() {
if (character == null)
return '';
final Iterable<String> hexChars = character!.codeUnits
.map((int code) => code.toRadixString(16).padLeft(2, '0'));
return '0x${hexChars.join(' ')}';
}

@override
String toString() => 'KeyData(key ${_typeToString(type)}, physical: 0x${physical.toRadixString(16)}, '
'logical: ${_logicalToString()}, character: ${_escapeCharacter()})';
'logical: ${_logicalToString()}, character: ${_escapeCharacter()}${_quotedCharCode()}${synthesized ? ', synthesized' : ''})';

/// Returns a complete textual description of the information in this object.
String toStringFull() {
Expand Down
3 changes: 3 additions & 0 deletions shell/platform/windows/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -243,12 +243,15 @@ executable("flutter_windows_unittests") {
"keyboard_key_channel_handler_unittests.cc",
"keyboard_key_embedder_handler_unittests.cc",
"keyboard_key_handler_unittests.cc",
"keyboard_unittests.cc",
"testing/flutter_window_win32_test.cc",
"testing/flutter_window_win32_test.h",
"testing/mock_window_binding_handler.cc",
"testing/mock_window_binding_handler.h",
"testing/mock_window_win32.cc",
"testing/mock_window_win32.h",
"testing/test_keyboard.cc",
"testing/test_keyboard.h",
"text_input_plugin_unittest.cc",
"window_proc_delegate_manager_win32_unittests.cc",
"window_win32_unittests.cc",
Expand Down
35 changes: 19 additions & 16 deletions shell/platform/windows/flutter_window_win32_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ namespace {
// Creates a valid Windows LPARAM for WM_KEYDOWN and WM_CHAR from parameters
// given.
static LPARAM CreateKeyEventLparam(USHORT scancode,
bool extended = false,
bool was_down = 1,
bool extended,
bool was_down,
USHORT repeat_count = 1,
bool context_code = 0,
bool transition_state = 1) {
Expand Down Expand Up @@ -215,7 +215,11 @@ class TestFlutterWindowsView : public FlutterWindowsView {
}

protected:
void RegisterKeyboardHandlers(flutter::BinaryMessenger* messenger) override {
void RegisterKeyboardHandlers(
flutter::BinaryMessenger* messenger,
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event,
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state)
override {
auto spy_key_event_handler = std::make_unique<SpyKeyboardKeyHandler>(
messenger, [this](UINT cInputs, LPINPUT pInputs, int cbSize) -> UINT {
return this->SendInput(cInputs, pInputs, cbSize);
Expand All @@ -235,8 +239,9 @@ class TestFlutterWindowsView : public FlutterWindowsView {
const KEYBDINPUT kbdinput = pInputs->ki;
const UINT message =
(kbdinput.dwFlags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
const bool is_key_up = kbdinput.dwFlags & KEYEVENTF_KEYUP;
const LPARAM lparam = CreateKeyEventLparam(
kbdinput.wScan, kbdinput.dwFlags & KEYEVENTF_EXTENDEDKEY);
kbdinput.wScan, kbdinput.dwFlags & KEYEVENTF_EXTENDEDKEY, is_key_up);
// Windows would normally fill in the virtual key code for us, so we
// simulate it for the test with the key we know is in the test. The
// KBDINPUT we're passed doesn't have it filled in (on purpose, so that
Expand Down Expand Up @@ -345,8 +350,7 @@ TEST(FlutterWindowWin32Test, NonPrintableKeyDownPropagation) {
TestFlutterWindowsView flutter_windows_view(
std::move(window_binding_handler), virtual_key, false /* is_printable */);
win32window.SetView(&flutter_windows_view);
LPARAM lparam = CreateKeyEventLparam(scan_code, false /* extended */,
false /* PrevState */);
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);

// Test an event not handled by the framework
{
Expand Down Expand Up @@ -406,16 +410,15 @@ TEST(FlutterWindowWin32Test, CharKeyDownPropagation) {
TestFlutterWindowsView flutter_windows_view(
std::move(window_binding_handler), virtual_key, true /* is_printable */);
win32window.SetView(&flutter_windows_view);
LPARAM lparam = CreateKeyEventLparam(scan_code, false /* extended */,
true /* PrevState */);
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);
flutter_windows_view.SetEngine(std::move(GetTestEngine()));

// Test an event not handled by the framework
{
test_response = false;
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
EXPECT_CALL(*flutter_windows_view.key_event_handler,
KeyboardHook(_, virtual_key, scan_code, WM_KEYDOWN, character,
false, true))
false, false))
.Times(2)
.RetiresOnSaturation();
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
Expand All @@ -433,21 +436,21 @@ TEST(FlutterWindowWin32Test, CharKeyDownPropagation) {
EXPECT_EQ(win32window.InjectWindowMessage(WM_CHAR, virtual_key, lparam), 0);
flutter_windows_view.InjectPendingEvents(&win32window);
}
return;

// Test an event handled by the framework
{
test_response = true;
EXPECT_CALL(*flutter_windows_view.key_event_handler,
KeyboardHook(_, virtual_key, scan_code, WM_KEYDOWN, character,
false /* is_printable */, true))
false, false))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
KeyboardHook(_, _, _, _, _, _, _))
.Times(0);
EXPECT_CALL(*flutter_windows_view.key_event_handler, TextHook(_, _))
.Times(0);
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*flutter_windows_view.text_input_plugin, TextHook(_, _))
.Times(0);
EXPECT_EQ(win32window.InjectWindowMessage(WM_KEYDOWN, virtual_key, lparam),
Expand All @@ -471,15 +474,15 @@ TEST(FlutterWindowWin32Test, ModifierKeyDownPropagation) {
TestFlutterWindowsView flutter_windows_view(
std::move(window_binding_handler), virtual_key, false /* is_printable */);
win32window.SetView(&flutter_windows_view);
LPARAM lparam = CreateKeyEventLparam(scan_code);
LPARAM lparam = CreateKeyEventLparam(scan_code, false, false);

// Test an event not handled by the framework
{
test_response = false;
flutter_windows_view.SetEngine(std::move(GetTestEngine()));
EXPECT_CALL(*flutter_windows_view.key_event_handler,
KeyboardHook(_, virtual_key, scan_code, WM_KEYDOWN, character,
false /* extended */, true))
false /* extended */, false))
.Times(2)
.RetiresOnSaturation();
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
Expand All @@ -500,7 +503,7 @@ TEST(FlutterWindowWin32Test, ModifierKeyDownPropagation) {
test_response = true;
EXPECT_CALL(*flutter_windows_view.key_event_handler,
KeyboardHook(_, virtual_key, scan_code, WM_KEYDOWN, character,
false /* extended */, true))
false /* extended */, false))
.Times(1)
.RetiresOnSaturation();
EXPECT_CALL(*flutter_windows_view.text_input_plugin,
Expand Down
27 changes: 15 additions & 12 deletions shell/platform/windows/flutter_windows_view.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,17 @@ void FlutterWindowsView::SetEngine(

// Set up the system channel handlers.
auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
RegisterKeyboardHandlers(internal_plugin_messenger);
#ifdef WINUWP
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = nullptr;
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state =
nullptr;
#else
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event = SendInput;
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state =
GetKeyState;
#endif
RegisterKeyboardHandlers(internal_plugin_messenger, dispatch_event,
get_key_state);
platform_handler_ = PlatformHandler::Create(internal_plugin_messenger, this);
cursor_handler_ = std::make_unique<flutter::CursorHandler>(
internal_plugin_messenger, binding_handler_.get());
Expand All @@ -67,7 +77,9 @@ void FlutterWindowsView::SetEngine(
}

void FlutterWindowsView::RegisterKeyboardHandlers(
flutter::BinaryMessenger* messenger) {
flutter::BinaryMessenger* messenger,
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event,
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state) {
// There must be only one handler that receives |SendInput|, i.e. only one
// handler that might redispatch events. (See the documentation of
// |KeyboardKeyHandler| to learn about redispatching.)
Expand All @@ -76,17 +88,8 @@ void FlutterWindowsView::RegisterKeyboardHandlers(
// of the event. In order to allow the same real event in the future, the
// handler is "toggled" when events pass through, therefore the redispatching
// algorithm does not allow more than 1 handler that takes |SendInput|.
#ifdef WINUWP
flutter::KeyboardKeyHandler::EventDispatcher redispatch_event = nullptr;
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state =
nullptr;
#else
flutter::KeyboardKeyHandler::EventDispatcher redispatch_event = SendInput;
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state =
GetKeyState;
#endif
auto key_handler =
std::make_unique<flutter::KeyboardKeyHandler>(redispatch_event);
std::make_unique<flutter::KeyboardKeyHandler>(dispatch_event);
key_handler->AddDelegate(std::make_unique<KeyboardKeyEmbedderHandler>(
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
void* user_data) {
Expand Down
7 changes: 6 additions & 1 deletion shell/platform/windows/flutter_windows_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
#include "flutter/shell/platform/windows/cursor_handler.h"
#include "flutter/shell/platform/windows/flutter_windows_engine.h"
#include "flutter/shell/platform/windows/keyboard_handler_base.h"
#include "flutter/shell/platform/windows/keyboard_key_embedder_handler.h"
#include "flutter/shell/platform/windows/keyboard_key_handler.h"
#include "flutter/shell/platform/windows/platform_handler.h"
#include "flutter/shell/platform/windows/public/flutter_windows.h"
#include "flutter/shell/platform/windows/text_input_plugin_delegate.h"
Expand Down Expand Up @@ -144,7 +146,10 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate,

protected:
// Called to create the keyboard hook handlers.
virtual void RegisterKeyboardHandlers(flutter::BinaryMessenger* messenger);
virtual void RegisterKeyboardHandlers(
flutter::BinaryMessenger* messenger,
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event,
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state);

// Used by RegisterKeyboardHandlers to add a new keyboard hook handler.
void AddKeyboardHandler(
Expand Down
4 changes: 2 additions & 2 deletions shell/platform/windows/keyboard_key_embedder_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -267,10 +267,10 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialToggledStates(
continue;
}
assert(key_info.logical_key != 0);
SHORT state = get_key_state_(virtual_key);

// Check toggling state first, because it might alter pressing state.
if (key_info.check_toggled) {
SHORT state = get_key_state_(virtual_key);
bool should_toggled = state & kStateMaskToggled;
if (virtual_key == toggle_virtual_key) {
key_info.toggled_on = !key_info.toggled_on;
Expand Down Expand Up @@ -312,8 +312,8 @@ void KeyboardKeyEmbedderHandler::SynchronizeCritialPressedStates() {
continue;
}
assert(key_info.logical_key != 0);
SHORT state = get_key_state_(virtual_key);
if (key_info.check_pressed) {
SHORT state = get_key_state_(virtual_key);
auto recorded_pressed_iter = pressingRecords_.find(key_info.physical_key);
bool recorded_pressed = recorded_pressed_iter != pressingRecords_.end();
bool should_pressed = state & kStateMaskPressed;
Expand Down
16 changes: 10 additions & 6 deletions shell/platform/windows/keyboard_key_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ static bool IsKeyDownAltRight(int action, int virtual_key, bool extended) {
#ifdef WINUWP
return false;
#else
return virtual_key == VK_LMENU && extended && action == WM_KEYDOWN;
return virtual_key == VK_RMENU && extended && action == WM_KEYDOWN;
#endif
}

Expand All @@ -73,7 +73,7 @@ static bool IsKeyUpAltRight(int action, int virtual_key, bool extended) {
#ifdef WINUWP
return false;
#else
return virtual_key == VK_LMENU && extended && action == WM_KEYUP;
return virtual_key == VK_RMENU && extended && action == WM_KEYUP;
#endif
}

Expand Down Expand Up @@ -220,9 +220,11 @@ bool KeyboardKeyHandler::KeyboardHook(FlutterWindowsView* view,
}
pending_responds_.push_back(std::move(incoming));

const bool is_deadchar = character & 0x80000000;
const uint32_t key_character = is_deadchar ? 0 : character;
for (const auto& delegate : delegates_) {
delegate->KeyboardHook(key, scancode, action, character, extended, was_down,
[sequence_id, this](bool handled) {
delegate->KeyboardHook(key, scancode, action, key_character, extended,
was_down, [sequence_id, this](bool handled) {
ResolvePendingEvent(sequence_id, handled);
});
}
Expand All @@ -233,7 +235,7 @@ bool KeyboardKeyHandler::KeyboardHook(FlutterWindowsView* view,
// return true at this time, preventing this event from affecting
// others.

return true;
return !is_deadchar;
}

bool KeyboardKeyHandler::RemoveRedispatchedEvent(const PendingEvent& incoming) {
Expand Down Expand Up @@ -261,7 +263,9 @@ void KeyboardKeyHandler::ResolvePendingEvent(uint64_t sequence_id,
if (event.unreplied == 0) {
std::unique_ptr<PendingEvent> event_ptr = std::move(*iter);
pending_responds_.erase(iter);
if (!event_ptr->any_handled) {
const bool is_deadchar = event.character & 0x80000000;
const bool should_redispatch = !event_ptr->any_handled && !is_deadchar;
if (should_redispatch) {
RedispatchEvent(std::move(event_ptr));
}
}
Expand Down
Loading