Flutter Engine
keyboard_key_handler_unittests.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 #include "flutter/shell/platform/windows/keyboard_key_handler.h"
5 
6 #include <rapidjson/document.h>
7 #include <memory>
8 
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11 
12 namespace flutter {
13 namespace testing {
14 
15 namespace {
16 
17 static constexpr int kHandledScanCode = 20;
18 static constexpr int kHandledScanCode2 = 22;
19 static constexpr int kUnhandledScanCode = 21;
20 
21 constexpr uint64_t kScanCodeShiftRight = 0x36;
22 constexpr uint64_t kScanCodeControl = 0x1D;
23 constexpr uint64_t kScanCodeAltLeft = 0x38;
24 
25 typedef std::function<void(bool)> Callback;
26 typedef std::function<void(Callback&)> CallbackHandler;
27 void dont_respond(Callback& callback) {}
28 void respond_true(Callback& callback) {
29  callback(true);
30 }
31 void respond_false(Callback& callback) {
32  callback(false);
33 }
34 
35 // A testing |KeyHandlerDelegate| that records all calls
36 // to |KeyboardHook| and can be customized with whether
37 // the hook is handled in async.
38 class MockKeyHandlerDelegate
39  : public KeyboardKeyHandler::KeyboardKeyHandlerDelegate {
40  public:
41  class KeyboardHookCall {
42  public:
44  int key;
45  int scancode;
46  int action;
47  char32_t character;
48  bool extended;
49  bool was_down;
50  std::function<void(bool)> callback;
51  };
52 
53  // Create a |MockKeyHandlerDelegate|.
54  //
55  // The |delegate_id| is an arbitrary ID to tell between delegates
56  // that will be recorded in |KeyboardHookCall|.
57  //
58  // The |hook_history| will store every call to |KeyboardHookCall| that are
59  // handled asynchronously.
60  //
61  // The |is_async| is a function that the class calls upon every
62  // |KeyboardHookCall| to decide whether the call is handled asynchronously.
63  // Defaults to always returning true (async).
64  MockKeyHandlerDelegate(int delegate_id,
65  std::list<KeyboardHookCall>* hook_history)
66  : delegate_id(delegate_id),
67  hook_history(hook_history),
68  callback_handler(dont_respond) {}
69  virtual ~MockKeyHandlerDelegate() = default;
70 
71  virtual void KeyboardHook(int key,
72  int scancode,
73  int action,
74  char32_t character,
75  bool extended,
76  bool was_down,
77  std::function<void(bool)> callback) {
78  hook_history->push_back(KeyboardHookCall{
79  .delegate_id = delegate_id,
80  .key = key,
81  .scancode = scancode,
82  .character = character,
83  .extended = extended,
84  .was_down = was_down,
85  .callback = std::move(callback),
86  });
87  callback_handler(hook_history->back().callback);
88  }
89 
90  CallbackHandler callback_handler;
91  int delegate_id;
92  std::list<KeyboardHookCall>* hook_history;
93 };
94 
96  kNoResponse,
97  kHandled,
98  kUnhandled,
99 };
100 
101 static KeyEventResponse key_event_response = kNoResponse;
102 
103 void OnKeyEventResult(bool handled) {
104  key_event_response = handled ? kHandled : kUnhandled;
105 }
106 
107 } // namespace
108 
109 TEST(KeyboardKeyHandlerTest, SingleDelegateWithAsyncResponds) {
110  std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
111 
112  KeyboardKeyHandler handler;
113  // Add one delegate
114  auto delegate = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
115  handler.AddDelegate(std::move(delegate));
116 
117  /// Test 1: One event that is handled by the framework
118 
119  // Dispatch a key event
120  handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, true,
121  OnKeyEventResult);
122  EXPECT_EQ(key_event_response, kNoResponse);
123  EXPECT_EQ(hook_history.size(), 1);
124  EXPECT_EQ(hook_history.back().delegate_id, 1);
125  EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
126  EXPECT_EQ(hook_history.back().was_down, true);
127 
128  EXPECT_EQ(key_event_response, kNoResponse);
129  hook_history.back().callback(true);
130  EXPECT_EQ(key_event_response, kHandled);
131 
132  key_event_response = kNoResponse;
133  hook_history.clear();
134 
135  /// Test 2: Two events that are unhandled by the framework
136 
137  handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, false,
138  OnKeyEventResult);
139  EXPECT_EQ(key_event_response, kNoResponse);
140  EXPECT_EQ(hook_history.size(), 1);
141  EXPECT_EQ(hook_history.back().delegate_id, 1);
142  EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
143  EXPECT_EQ(hook_history.back().was_down, false);
144 
145  // Dispatch another key event
146  handler.KeyboardHook(65, kHandledScanCode2, WM_KEYUP, L'b', false, true,
147  OnKeyEventResult);
148  EXPECT_EQ(key_event_response, kNoResponse);
149  EXPECT_EQ(hook_history.size(), 2);
150  EXPECT_EQ(hook_history.back().delegate_id, 1);
151  EXPECT_EQ(hook_history.back().scancode, kHandledScanCode2);
152  EXPECT_EQ(hook_history.back().was_down, true);
153 
154  // Resolve the second event first to test out-of-order response
155  hook_history.back().callback(false);
156  EXPECT_EQ(key_event_response, kUnhandled);
157  key_event_response = kNoResponse;
158 
159  // Resolve the first event then
160  hook_history.front().callback(false);
161  EXPECT_EQ(key_event_response, kUnhandled);
162 
163  hook_history.clear();
164  key_event_response = kNoResponse;
165 }
166 
167 TEST(KeyboardKeyHandlerTest, SingleDelegateWithSyncResponds) {
168  std::list<MockKeyHandlerDelegate::KeyboardHookCall> hook_history;
169 
170  KeyboardKeyHandler handler;
171  // Add one delegate
172  auto delegate = std::make_unique<MockKeyHandlerDelegate>(1, &hook_history);
173  CallbackHandler& delegate_handler = delegate->callback_handler;
174  handler.AddDelegate(std::move(delegate));
175 
176  /// Test 1: One event that is handled by the framework
177 
178  // Dispatch a key event
179  delegate_handler = respond_true;
180  handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, false,
181  OnKeyEventResult);
182  EXPECT_EQ(key_event_response, kHandled);
183  EXPECT_EQ(hook_history.size(), 1);
184  EXPECT_EQ(hook_history.back().delegate_id, 1);
185  EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
186  EXPECT_EQ(hook_history.back().was_down, false);
187 
188  hook_history.clear();
189 
190  /// Test 2: An event unhandled by the framework
191 
192  delegate_handler = respond_false;
193  handler.KeyboardHook(64, kHandledScanCode, WM_KEYDOWN, L'a', false, false,
194  OnKeyEventResult);
195  EXPECT_EQ(key_event_response, kUnhandled);
196  EXPECT_EQ(hook_history.size(), 1);
197  EXPECT_EQ(hook_history.back().delegate_id, 1);
198  EXPECT_EQ(hook_history.back().scancode, kHandledScanCode);
199  EXPECT_EQ(hook_history.back().was_down, false);
200 
201  hook_history.clear();
202  key_event_response = kNoResponse;
203 }
204 
205 } // namespace testing
206 } // namespace flutter
void KeyboardHook(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback) override
Dart_NativeFunction function
Definition: fuchsia.cc:51
char32_t character
std::function< void(bool)> callback
std::list< KeyboardHookCall > * hook_history
TEST(DisplayList, SingleOpSizes)
void AddDelegate(std::unique_ptr< KeyboardKeyHandlerDelegate > delegate)
CallbackHandler callback_handler