Flutter Engine
The Flutter Engine
test_keyboard.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "flutter/shell/platform/windows/testing/test_keyboard.h"
6
7#include <rapidjson/document.h>
8
9#include "flutter/fml/logging.h"
10#include "flutter/shell/platform/common/json_message_codec.h"
11#include "flutter/shell/platform/embedder/test_utils/proc_table_replacement.h"
12
13namespace flutter {
14namespace testing {
15
16char* clone_string(const char* string) {
17 if (string == nullptr) {
18 return nullptr;
19 }
20 size_t len = strlen(string);
21 char* result = new char[len + 1];
22 strcpy(result, string);
23 return result;
24}
25
26namespace {
27std::string _print_character(const char* s) {
28 if (s == nullptr) {
29 return "nullptr";
30 }
31 return std::string("\"") + s + "\"";
32}
33
34std::unique_ptr<std::vector<uint8_t>> _keyHandlingResponse(bool handled) {
35 rapidjson::Document document;
36 auto& allocator = document.GetAllocator();
37 document.SetObject();
38 document.AddMember("handled", handled, allocator);
40}
41
42static std::string ordinal(int num) {
43 switch (num) {
44 case 1:
45 return "st";
46 case 2:
47 return "nd";
48 case 3:
49 return "rd";
50 default:
51 return "th";
52 }
53}
54} // namespace
55
56#define _RETURN_IF_NOT_EQUALS(val1, val2) \
57 if ((val1) != (val2)) { \
58 return ::testing::AssertionFailure() \
59 << "Expected equality of these values:\n " #val1 "\n " << val2 \
60 << "\n Actual: \n " << val1; \
61 }
62
63::testing::AssertionResult _EventEquals(const char* expr_event,
64 const char* expr_expected,
66 const FlutterKeyEvent& expected) {
67 _RETURN_IF_NOT_EQUALS(event.struct_size, sizeof(FlutterKeyEvent));
68 _RETURN_IF_NOT_EQUALS(event.type, expected.type);
69 _RETURN_IF_NOT_EQUALS(event.physical, expected.physical);
70 _RETURN_IF_NOT_EQUALS(event.logical, expected.logical);
71 if ((event.character == nullptr) != (expected.character == nullptr) ||
72 strcmp(event.character, expected.character) != 0) {
73 return ::testing::AssertionFailure()
74 << "Expected equality of these values:\n expected.character\n "
75 << _print_character(expected.character) << "\n Actual: \n "
76 << _print_character(event.character);
77 }
78 _RETURN_IF_NOT_EQUALS(event.synthesized, expected.synthesized);
79 return ::testing::AssertionSuccess();
80}
81
83 bool extended,
84 bool was_down,
85 USHORT repeat_count,
86 bool context_code,
87 bool transition_state) {
88 return ((LPARAM(transition_state) << 31) | (LPARAM(was_down) << 30) |
89 (LPARAM(context_code) << 29) | (LPARAM(extended ? 0x1 : 0x0) << 24) |
90 (LPARAM(scancode) << 16) | LPARAM(repeat_count));
91}
92
93static std::shared_ptr<MockKeyResponseController> stored_response_controller;
94
95// Set EngineModifier, listen to event messages that go through the channel and
96// the embedder API, while disabling other methods so that the engine can be
97// run headlessly.
98//
99// The |channel_handler| and |embedder_handler| should return a boolean
100// indicating whether the framework decides to handle the event.
102 EngineModifier& modifier,
103 std::shared_ptr<MockKeyResponseController> response_controller) {
104 stored_response_controller = response_controller;
105 // This mock handles channel messages.
106 modifier.embedder_api()
109 if (std::string(message->channel) == std::string("flutter/settings")) {
110 return kSuccess;
111 }
112 if (std::string(message->channel) == std::string("flutter/keyevent")) {
113 stored_response_controller->HandleChannelMessage([message](bool handled) {
114 auto response = _keyHandlingResponse(handled);
115 auto response_handle = message->response_handle;
116 if (response_handle->callback != nullptr) {
117 response_handle->callback(response->data(), response->size(),
118 response_handle->user_data);
119 }
120 });
121 return kSuccess;
122 }
123 if (std::string(message->channel) == std::string("flutter/textinput")) {
124 std::unique_ptr<rapidjson::Document> document =
126 message->message, message->message_size);
127 if (document == nullptr) {
128 return kInvalidArguments;
129 }
130 stored_response_controller->HandleTextInputMessage(std::move(document));
131 return kSuccess;
132 }
133 return kSuccess;
134 };
135
136 // This mock handles key events sent through the embedder API.
137 modifier.embedder_api().SendKeyEvent =
140 stored_response_controller->HandleEmbedderMessage(
141 event, [callback, user_data](bool handled) {
142 if (callback != nullptr) {
143 callback(handled, user_data);
144 }
145 });
146 return kSuccess;
147 };
148
149 // The following mocks enable channel mocking.
151 [](auto engine, auto data_callback, auto user_data, auto response_out) {
152 auto response_handle = new FlutterPlatformMessageResponseHandle();
153 response_handle->user_data = user_data;
154 response_handle->callback = data_callback;
155 *response_out = response_handle;
156 return kSuccess;
157 };
158
162 delete response;
163 return kSuccess;
164 };
165
166 // The following mock disables responses for method channels sent from the
167 // embedding to the framework. (No code uses the response yet.)
171 const uint8_t* data, size_t data_length) { return kSuccess; };
172
173 // The following mocks allows RunWithEntrypoint to be run, which creates a
174 // non-empty FlutterEngine and enables SendKeyEvent.
175
176 modifier.embedder_api().Run =
177 [](size_t version, const FlutterRendererConfig* config,
178 const FlutterProjectArgs* args, void* user_data,
179 FLUTTER_API_SYMBOL(FlutterEngine) * engine_out) {
180 *engine_out = reinterpret_cast<FLUTTER_API_SYMBOL(FlutterEngine)>(1);
181
182 return kSuccess;
183 };
184 // Any time the associated EmbedderEngine will be mocked, such as here,
185 // the Update accessibility features must not attempt to actually push the
186 // update
190 modifier.embedder_api().UpdateLocales =
191 [](auto engine, const FlutterLocale** locales, size_t locales_count) {
192 return kSuccess;
193 };
195 [](auto engine, const FlutterWindowMetricsEvent* event) {
196 return kSuccess;
197 };
198 modifier.embedder_api().Shutdown = [](auto engine) { return kSuccess; };
200 [](auto engine, const FlutterEngineDisplaysUpdateType update_type,
201 const FlutterEngineDisplay* embedder_displays,
202 size_t display_count) { return kSuccess; };
203}
204
206 _pending_messages.push_back(*message);
207}
208
211 << "Called DispatchFront while pending message queue is empty";
213 _pending_messages.pop_front();
214 _sent_messages.push_back(message);
216 Win32SendMessage(message.message, message.wParam, message.lParam);
217 if (message.expected_result != kWmResultDontCheck) {
218 EXPECT_EQ(result, message.expected_result)
219 << " This is the " << _sent_messages.size()
220 << ordinal(_sent_messages.size()) << " event, with\n " << std::hex
221 << "Message 0x" << message.message << " LParam 0x" << message.lParam
222 << " WParam 0x" << message.wParam;
223 }
224 return result;
225}
226
228 UINT wMsgFilterMin,
229 UINT wMsgFilterMax,
230 UINT wRemoveMsg) {
231 for (auto iter = _pending_messages.begin(); iter != _pending_messages.end();
232 ++iter) {
233 if (iter->message >= wMsgFilterMin && iter->message <= wMsgFilterMax) {
234 *lpMsg = MSG{
235 .message = iter->message,
236 .wParam = iter->wParam,
237 .lParam = iter->lParam,
238 };
239 if ((wRemoveMsg & PM_REMOVE) == PM_REMOVE) {
240 _pending_messages.erase(iter);
241 }
242 return TRUE;
243 }
244 }
245 return FALSE;
246}
247
248} // namespace testing
249} // namespace flutter
FlutterEngineProcTable & embedder_api()
static const JsonMessageCodec & GetInstance()
std::unique_ptr< T > DecodeMessage(const uint8_t *binary_message, const size_t message_size) const
Definition: message_codec.h:29
std::unique_ptr< std::vector< uint8_t > > EncodeMessage(const T &message) const
Definition: message_codec.h:45
std::list< Win32Message > _pending_messages
std::list< Win32Message > _sent_messages
void PushBack(const Win32Message *message)
virtual LRESULT Win32SendMessage(UINT const message, WPARAM const wparam, LPARAM const lparam)=0
BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
struct _FlutterPlatformMessageResponseHandle FlutterPlatformMessageResponseHandle
Definition: embedder.h:1159
struct _FlutterEngine * FLUTTER_API_SYMBOL(FlutterEngine)
Definition: embedder.h:269
FlutterAccessibilityFeature
Definition: embedder.h:91
@ kInvalidArguments
Definition: embedder.h:75
@ kSuccess
Definition: embedder.h:73
FlutterEngineDisplaysUpdateType
Definition: embedder.h:2000
void(* FlutterKeyEventCallback)(bool, void *)
Definition: embedder.h:1155
FlutterEngine engine
Definition: main.cc:68
struct MyStruct s
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
GAsyncResult * result
#define FML_DCHECK(condition)
Definition: logging.h:103
Win32Message message
return FALSE
::testing::AssertionResult _EventEquals(const char *expr_event, const char *expr_expected, const FlutterKeyEvent &event, const FlutterKeyEvent &expected)
void MockEmbedderApiForKeyboard(EngineModifier &modifier, std::shared_ptr< MockKeyResponseController > response_controller)
constexpr LRESULT kWmResultDontCheck
Definition: wm_builders.h:16
static std::shared_ptr< MockKeyResponseController > stored_response_controller
LPARAM CreateKeyEventLparam(USHORT scancode, bool extended, bool was_down, USHORT repeat_count, bool context_code, bool transition_state)
char * clone_string(const char *string)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition: switches.h:41
FlutterEnginePlatformMessageReleaseResponseHandleFnPtr PlatformMessageReleaseResponseHandle
Definition: embedder.h:3337
FlutterEngineUpdateLocalesFnPtr UpdateLocales
Definition: embedder.h:3354
FlutterEngineSendKeyEventFnPtr SendKeyEvent
Definition: embedder.h:3332
FlutterEngineSendWindowMetricsEventFnPtr SendWindowMetricsEvent
Definition: embedder.h:3330
FlutterEngineShutdownFnPtr Shutdown
Definition: embedder.h:3326
FlutterEngineNotifyDisplayUpdateFnPtr NotifyDisplayUpdate
Definition: embedder.h:3360
FlutterEngineSendPlatformMessageFnPtr SendPlatformMessage
Definition: embedder.h:3333
FlutterEnginePlatformMessageCreateResponseHandleFnPtr PlatformMessageCreateResponseHandle
Definition: embedder.h:3335
FlutterEngineSendPlatformMessageResponseFnPtr SendPlatformMessageResponse
Definition: embedder.h:3338
FlutterEngineRunFnPtr Run
Definition: embedder.h:3325
FlutterEngineUpdateAccessibilityFeaturesFnPtr UpdateAccessibilityFeatures
Definition: embedder.h:3344
uint64_t logical
Definition: embedder.h:1134
uint64_t physical
Definition: embedder.h:1126
FlutterKeyEventType type
The event kind.
Definition: embedder.h:1118
const char * character
Definition: embedder.h:1137
#define _RETURN_IF_NOT_EQUALS(val1, val2)
void * user_data
int BOOL
Definition: windows_types.h:37
struct tagMSG * LPMSG
struct tagMSG MSG
LONG_PTR LRESULT
Definition: windows_types.h:61
unsigned int UINT
Definition: windows_types.h:32
LONG_PTR LPARAM
Definition: windows_types.h:60