Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 073e6c5

Browse files
authored
[Windows, Keyboard] Lift key event redispatching to KeyboardManagerWin32 (#30702)
1 parent fb3ee7f commit 073e6c5

22 files changed

+695
-641
lines changed

shell/platform/windows/flutter_window_win32.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,15 @@ void FlutterWindowWin32::OnText(const std::u16string& text) {
184184
binding_handler_delegate_->OnText(text);
185185
}
186186

187-
bool FlutterWindowWin32::OnKey(int key,
187+
void FlutterWindowWin32::OnKey(int key,
188188
int scancode,
189189
int action,
190190
char32_t character,
191191
bool extended,
192-
bool was_down) {
193-
return binding_handler_delegate_->OnKey(key, scancode, action, character,
194-
extended, was_down);
192+
bool was_down,
193+
KeyEventCallback callback) {
194+
binding_handler_delegate_->OnKey(key, scancode, action, character, extended,
195+
was_down, std::move(callback));
195196
}
196197

197198
void FlutterWindowWin32::OnComposeBegin() {

shell/platform/windows/flutter_window_win32.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,13 @@ class FlutterWindowWin32 : public WindowWin32, public WindowBindingHandler {
6767
void OnText(const std::u16string& text) override;
6868

6969
// |WindowWin32|
70-
bool OnKey(int key,
70+
void OnKey(int key,
7171
int scancode,
7272
int action,
7373
char32_t character,
7474
bool extended,
75-
bool was_down) override;
75+
bool was_down,
76+
KeyEventCallback callback) override;
7677

7778
// |WindowWin32|
7879
void OnComposeBegin() override;

shell/platform/windows/flutter_window_win32_unittests.cc

Lines changed: 63 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -34,28 +34,23 @@ static constexpr int32_t kDefaultPointerDeviceId = 0;
3434
// key event handler.
3535
class SpyKeyboardKeyHandler : public KeyboardHandlerBase {
3636
public:
37-
SpyKeyboardKeyHandler(flutter::BinaryMessenger* messenger,
38-
KeyboardKeyHandler::EventDispatcher dispatch_event) {
39-
real_implementation_ = std::make_unique<KeyboardKeyHandler>(dispatch_event);
37+
SpyKeyboardKeyHandler(flutter::BinaryMessenger* messenger) {
38+
real_implementation_ = std::make_unique<KeyboardKeyHandler>();
4039
real_implementation_->AddDelegate(
4140
std::make_unique<KeyboardKeyChannelHandler>(messenger));
42-
ON_CALL(*this, KeyboardHook(_, _, _, _, _, _))
41+
ON_CALL(*this, KeyboardHook(_, _, _, _, _, _, _))
4342
.WillByDefault(Invoke(real_implementation_.get(),
4443
&KeyboardKeyHandler::KeyboardHook));
4544
}
4645

47-
MOCK_METHOD6(KeyboardHook,
48-
bool(int key,
46+
MOCK_METHOD7(KeyboardHook,
47+
void(int key,
4948
int scancode,
5049
int action,
5150
char32_t character,
5251
bool extended,
53-
bool was_down));
54-
MOCK_METHOD0(ComposeBeginHook, void());
55-
MOCK_METHOD0(ComposeCommitHook, void());
56-
MOCK_METHOD0(ComposeEndHook, void());
57-
MOCK_METHOD2(ComposeChangeHook,
58-
void(const std::u16string& text, int cursor_pos));
52+
bool was_down,
53+
KeyEventCallback callback));
5954

6055
private:
6156
std::unique_ptr<KeyboardKeyHandler> real_implementation_;
@@ -101,7 +96,10 @@ class SpyTextInputPlugin : public TextInputPlugin,
10196
class MockFlutterWindowWin32 : public FlutterWindowWin32,
10297
public MockMessageQueue {
10398
public:
104-
MockFlutterWindowWin32() : FlutterWindowWin32(800, 600) {
99+
MockFlutterWindowWin32(WPARAM virtual_key = 0, bool is_printable = true)
100+
: virtual_key_(virtual_key),
101+
is_printable_(is_printable),
102+
FlutterWindowWin32(800, 600) {
105103
ON_CALL(*this, GetDpiScale())
106104
.WillByDefault(Return(this->FlutterWindowWin32::GetDpiScale()));
107105
}
@@ -151,27 +149,68 @@ class MockFlutterWindowWin32 : public FlutterWindowWin32,
151149
MOCK_METHOD0(OnResetImeComposing, void());
152150

153151
protected:
154-
virtual BOOL Win32PeekMessage(LPMSG lpMsg,
155-
UINT wMsgFilterMin,
156-
UINT wMsgFilterMax,
157-
UINT wRemoveMsg) override {
152+
// |KeyboardManagerWin32::WindowDelegate|
153+
BOOL Win32PeekMessage(LPMSG lpMsg,
154+
UINT wMsgFilterMin,
155+
UINT wMsgFilterMax,
156+
UINT wRemoveMsg) override {
158157
return MockMessageQueue::Win32PeekMessage(lpMsg, wMsgFilterMin,
159158
wMsgFilterMax, wRemoveMsg);
160159
}
161160

161+
// |KeyboardManagerWin32::WindowDelegate|
162162
LRESULT Win32DefWindowProc(HWND hWnd,
163163
UINT Msg,
164164
WPARAM wParam,
165165
LPARAM lParam) override {
166166
return kWmResultDefault;
167167
}
168168

169-
private:
169+
// |KeyboardManagerWin32::WindowDelegate|
170+
UINT Win32DispatchEvent(UINT cInputs, LPINPUT pInputs, int cbSize) override {
171+
for (UINT input_idx = 0; input_idx < cInputs; input_idx += 1) {
172+
SendInput(pInputs[input_idx].ki);
173+
}
174+
return 1;
175+
}
176+
177+
// |MockMessageQueue|
170178
LRESULT Win32SendMessage(UINT const message,
171179
WPARAM const wparam,
172180
LPARAM const lparam) override {
173181
return HandleMessage(message, wparam, lparam);
174182
}
183+
184+
private:
185+
UINT SendInput(KEYBDINPUT kbdinput) {
186+
// Simulate the event loop by just sending the event sent to
187+
// "SendInput" directly to the window.
188+
const bool is_key_up = kbdinput.dwFlags & KEYEVENTF_KEYUP;
189+
const UINT message = is_key_up ? WM_KEYUP : WM_KEYDOWN;
190+
191+
const LPARAM lparam = CreateKeyEventLparam(
192+
kbdinput.wScan, kbdinput.dwFlags & KEYEVENTF_EXTENDEDKEY, is_key_up);
193+
// Windows would normally fill in the virtual key code for us, so we
194+
// simulate it for the test with the key we know is in the test. The
195+
// KBDINPUT we're passed doesn't have it filled in (on purpose, so that
196+
// Windows will fill it in).
197+
//
198+
// TODO(dkwingsmt): Don't check the message results for redispatched
199+
// messages for now, because making them work takes non-trivial rework
200+
// to our current structure. https://github.com/flutter/flutter/issues/87843
201+
// If this is resolved, change them to kWmResultDefault.
202+
pending_responds_.push_back(
203+
Win32Message{message, virtual_key_, lparam, kWmResultDontCheck});
204+
if (is_printable_ && (kbdinput.dwFlags & KEYEVENTF_KEYUP) == 0) {
205+
pending_responds_.push_back(
206+
Win32Message{WM_CHAR, virtual_key_, lparam, kWmResultDontCheck});
207+
}
208+
return 1;
209+
}
210+
211+
std::vector<Win32Message> pending_responds_;
212+
WPARAM virtual_key_;
213+
bool is_printable_;
175214
};
176215

177216
class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
@@ -201,7 +240,8 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
201240
FlutterPointerMouseButtons));
202241
MOCK_METHOD2(OnPointerLeave, void(FlutterPointerDeviceKind, int32_t));
203242
MOCK_METHOD1(OnText, void(const std::u16string&));
204-
MOCK_METHOD6(OnKey, bool(int, int, int, char32_t, bool, bool));
243+
MOCK_METHOD7(OnKey,
244+
void(int, int, int, char32_t, bool, bool, KeyEventCallback));
205245
MOCK_METHOD0(OnComposeBegin, void());
206246
MOCK_METHOD0(OnComposeCommit, void());
207247
MOCK_METHOD0(OnComposeEnd, void());
@@ -223,32 +263,19 @@ class MockWindowBindingHandlerDelegate : public WindowBindingHandlerDelegate {
223263
// to register the keyboard hook handlers that can be spied upon.
224264
class TestFlutterWindowsView : public FlutterWindowsView {
225265
public:
226-
TestFlutterWindowsView(std::unique_ptr<WindowBindingHandler> window_binding,
227-
WPARAM virtual_key,
228-
bool is_printable = true)
229-
: FlutterWindowsView(std::move(window_binding)),
230-
virtual_key_(virtual_key),
231-
is_printable_(is_printable) {}
266+
TestFlutterWindowsView(std::unique_ptr<WindowBindingHandler> window_binding)
267+
: FlutterWindowsView(std::move(window_binding)) {}
232268

233269
SpyKeyboardKeyHandler* key_event_handler;
234270
SpyTextInputPlugin* text_input_plugin;
235271

236-
void InjectPendingEvents(MockFlutterWindowWin32* win32window) {
237-
win32window->InjectMessageList(pending_responds_.size(),
238-
pending_responds_.data());
239-
pending_responds_.clear();
240-
}
241-
242272
protected:
243273
std::unique_ptr<KeyboardHandlerBase> CreateKeyboardKeyHandler(
244274
flutter::BinaryMessenger* messenger,
245-
flutter::KeyboardKeyHandler::EventDispatcher dispatch_event,
246275
flutter::KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state)
247276
override {
248-
auto spy_key_event_handler = std::make_unique<SpyKeyboardKeyHandler>(
249-
messenger, [this](UINT cInputs, LPINPUT pInputs, int cbSize) -> UINT {
250-
return this->SendInput(cInputs, pInputs, cbSize);
251-
});
277+
auto spy_key_event_handler =
278+
std::make_unique<SpyKeyboardKeyHandler>(messenger);
252279
key_event_handler = spy_key_event_handler.get();
253280
return spy_key_event_handler;
254281
}
@@ -260,38 +287,6 @@ class TestFlutterWindowsView : public FlutterWindowsView {
260287
text_input_plugin = spy_key_event_handler.get();
261288
return spy_key_event_handler;
262289
}
263-
264-
private:
265-
UINT SendInput(UINT cInputs, LPINPUT pInputs, int cbSize) {
266-
// Simulate the event loop by just sending the event sent to
267-
// "SendInput" directly to the window.
268-
const KEYBDINPUT kbdinput = pInputs->ki;
269-
const bool is_key_up = kbdinput.dwFlags & KEYEVENTF_KEYUP;
270-
const UINT message = is_key_up ? WM_KEYUP : WM_KEYDOWN;
271-
272-
const LPARAM lparam = CreateKeyEventLparam(
273-
kbdinput.wScan, kbdinput.dwFlags & KEYEVENTF_EXTENDEDKEY, is_key_up);
274-
// Windows would normally fill in the virtual key code for us, so we
275-
// simulate it for the test with the key we know is in the test. The
276-
// KBDINPUT we're passed doesn't have it filled in (on purpose, so that
277-
// Windows will fill it in).
278-
//
279-
// TODO(dkwingsmt): Don't check the message results for redispatched
280-
// messages for now, because making them work takes non-trivial rework
281-
// to our current structure. https://github.com/flutter/flutter/issues/87843
282-
// If this is resolved, change them to kWmResultDefault.
283-
pending_responds_.push_back(
284-
Win32Message{message, virtual_key_, lparam, kWmResultDontCheck});
285-
if (is_printable_ && (kbdinput.dwFlags & KEYEVENTF_KEYUP) == 0) {
286-
pending_responds_.push_back(
287-
Win32Message{WM_CHAR, virtual_key_, lparam, kWmResultDontCheck});
288-
}
289-
return 1;
290-
}
291-
292-
std::vector<Win32Message> pending_responds_;
293-
WPARAM virtual_key_;
294-
bool is_printable_;
295290
};
296291

297292
// The static value to return as the "handled" value from the framework for key

shell/platform/windows/flutter_window_winuwp.cc

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ winrt::Windows::UI::Core::CoreCursor GetCursorByName(
6767
}
6868
}
6969

70+
// UWP does not care if key events are handled, since it can not redispatch them
71+
// anyway.
72+
static void IgnoreKeyEventResult(bool handled) {}
73+
7074
} // namespace
7175

7276
FlutterWindowWinUWP::FlutterWindowWinUWP(
@@ -347,9 +351,9 @@ void FlutterWindowWinUWP::OnKeyUp(
347351
unsigned int scancode = status.ScanCode;
348352
int key = static_cast<int>(args.VirtualKey());
349353
int action = 0x0101;
350-
binding_handler_delegate_->OnKey(key, scancode, action, 0,
351-
status.IsExtendedKey /* extended */,
352-
status.WasKeyDown /* was_down */);
354+
binding_handler_delegate_->OnKey(
355+
key, scancode, action, 0, status.IsExtendedKey /* extended */,
356+
status.WasKeyDown /* was_down */, IgnoreKeyEventResult);
353357
}
354358

355359
void FlutterWindowWinUWP::OnKeyDown(
@@ -363,9 +367,9 @@ void FlutterWindowWinUWP::OnKeyDown(
363367
unsigned int scancode = status.ScanCode;
364368
int key = static_cast<int>(args.VirtualKey());
365369
int action = 0x0100;
366-
binding_handler_delegate_->OnKey(key, scancode, action, 0,
367-
status.IsExtendedKey /* extended */,
368-
status.WasKeyDown /* was_down */);
370+
binding_handler_delegate_->OnKey(
371+
key, scancode, action, 0, status.IsExtendedKey /* extended */,
372+
status.WasKeyDown /* was_down */, IgnoreKeyEventResult);
369373
}
370374

371375
void FlutterWindowWinUWP::OnCharacterReceived(

shell/platform/windows/flutter_windows_view.cc

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,8 @@ void FlutterWindowsView::SetEngine(
7070
std::unique_ptr<KeyboardHandlerBase>
7171
FlutterWindowsView::CreateKeyboardKeyHandler(
7272
BinaryMessenger* messenger,
73-
KeyboardKeyHandler::EventDispatcher dispatch_event,
7473
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state) {
75-
// There must be only one handler that receives |SendInput|, i.e. only one
76-
// handler that might redispatch events. (See the documentation of
77-
// |KeyboardKeyHandler| to learn about redispatching.)
78-
//
79-
// Whether an event is a redispatched event is decided by calculating the hash
80-
// of the event. In order to allow the same real event in the future, the
81-
// handler is "toggled" when events pass through, therefore the redispatching
82-
// algorithm does not allow more than 1 handler that takes |SendInput|.
83-
auto keyboard_key_handler =
84-
std::make_unique<KeyboardKeyHandler>(dispatch_event);
74+
auto keyboard_key_handler = std::make_unique<KeyboardKeyHandler>();
8575
keyboard_key_handler->AddDelegate(
8676
std::make_unique<KeyboardKeyEmbedderHandler>(
8777
[this](const FlutterKeyEvent& event, FlutterKeyEventCallback callback,
@@ -207,13 +197,14 @@ void FlutterWindowsView::OnText(const std::u16string& text) {
207197
SendText(text);
208198
}
209199

210-
bool FlutterWindowsView::OnKey(int key,
200+
void FlutterWindowsView::OnKey(int key,
211201
int scancode,
212202
int action,
213203
char32_t character,
214204
bool extended,
215-
bool was_down) {
216-
return SendKey(key, scancode, action, character, extended, was_down);
205+
bool was_down,
206+
KeyEventCallback callback) {
207+
SendKey(key, scancode, action, character, extended, was_down, callback);
217208
}
218209

219210
void FlutterWindowsView::OnComposeBegin() {
@@ -267,14 +258,12 @@ void FlutterWindowsView::OnResetImeComposing() {
267258
void FlutterWindowsView::InitializeKeyboard() {
268259
auto internal_plugin_messenger = internal_plugin_registrar_->messenger();
269260
#ifdef WINUWP
270-
KeyboardKeyHandler::EventDispatcher dispatch_event = nullptr;
271261
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = nullptr;
272262
#else
273-
KeyboardKeyHandler::EventDispatcher dispatch_event = SendInput;
274263
KeyboardKeyEmbedderHandler::GetKeyStateHandler get_key_state = GetKeyState;
275264
#endif
276-
keyboard_key_handler_ = std::move(CreateKeyboardKeyHandler(
277-
internal_plugin_messenger, dispatch_event, get_key_state));
265+
keyboard_key_handler_ = std::move(
266+
CreateKeyboardKeyHandler(internal_plugin_messenger, get_key_state));
278267
text_input_plugin_ =
279268
std::move(CreateTextInputPlugin(internal_plugin_messenger));
280269
}
@@ -383,21 +372,22 @@ void FlutterWindowsView::SendText(const std::u16string& text) {
383372
text_input_plugin_->TextHook(text);
384373
}
385374

386-
bool FlutterWindowsView::SendKey(int key,
375+
void FlutterWindowsView::SendKey(int key,
387376
int scancode,
388377
int action,
389378
char32_t character,
390379
bool extended,
391-
bool was_down) {
392-
if (keyboard_key_handler_->KeyboardHook(key, scancode, action, character,
393-
extended, was_down)) {
394-
return true;
395-
}
396-
397-
text_input_plugin_->KeyboardHook(key, scancode, action, character, extended,
398-
was_down);
399-
400-
return false;
380+
bool was_down,
381+
KeyEventCallback callback) {
382+
keyboard_key_handler_->KeyboardHook(
383+
key, scancode, action, character, extended, was_down,
384+
[&, callback = std::move(callback)](bool handled) {
385+
if (!handled) {
386+
text_input_plugin_->KeyboardHook(key, scancode, action, character,
387+
extended, was_down);
388+
}
389+
callback(handled);
390+
});
401391
}
402392

403393
void FlutterWindowsView::SendComposeBegin() {

0 commit comments

Comments
 (0)