Flutter Engine
The Flutter Engine
keyboard_manager.h
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#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_KEYBOARD_MANAGER_H_
6#define FLUTTER_SHELL_PLATFORM_WINDOWS_KEYBOARD_MANAGER_H_
7
8#include <windows.h>
9
10#include <atomic>
11#include <deque>
12#include <functional>
13#include <map>
14
15#include "flutter/fml/macros.h"
16
17namespace flutter {
18
19// Handles keyboard and text messages on Win32.
20//
21// |KeyboardManager| consumes raw Win32 messages related to key and chars, and
22// converts them to key calls (|WindowDelegate::OnKey|) and possibly text calls
23// (|WindowDelegate::OnText|).
24//
25// |KeyboardManager| requires a |WindowDelegate| to define how to access Win32
26// system calls (to allow mocking) and where to send the results of key calls
27// and text calls to.
28//
29// Typically, |KeyboardManager| is owned by a |FlutterWindow|, which also
30// implements the window delegate. The key calls and text calls are forwarded to
31// the |FlutterWindow|, and consequently, to the |FlutterWindowsView|.
32//
33// ## Terminology
34//
35// The keyboard system uses the following terminology (which is different
36// than Win32's terminology):
37//
38// * Message: An invocation of |WndProc|, which consists of an
39// action, an lparam, and a wparam.
40// * Action: The type of a message.
41// * Session: One to three messages that should be processed together, such
42// as a key down message followed by char messages.
43// * Event: A FlutterKeyEvent/ui.KeyData sent to the framework.
44// * Call: A call to |WindowDelegate::OnKey| or |WindowDelegate::OnText|,
45// which contains semi-processed messages.
47 public:
48 // Define how the keyboard manager accesses Win32 system calls (to allow
49 // mocking) and sends key calls and text calls.
50 //
51 // Typically implemented by |Window|.
53 public:
54 using KeyEventCallback = std::function<void(bool)>;
55
56 virtual ~WindowDelegate() = default;
57
58 // Called when text input occurs.
59 virtual void OnText(const std::u16string& text) = 0;
60
61 // Called when raw keyboard input occurs.
62 //
63 // The `callback` must be called exactly once.
64 virtual void OnKey(int key,
65 int scancode,
66 int action,
67 char32_t character,
68 bool extended,
69 bool was_down,
71
72 // Win32's PeekMessage.
73 //
74 // Used to process key messages.
76 UINT wMsgFilterMin,
77 UINT wMsgFilterMax,
78 UINT wRemoveMsg) = 0;
79
80 // Win32's MapVirtualKey(*, MAPVK_VK_TO_CHAR).
81 //
82 // Used to process key messages.
83 virtual uint32_t Win32MapVkToChar(uint32_t virtual_key) = 0;
84
85 // Win32's |SendMessage|.
86 //
87 // Used to synthesize key messages.
89 WPARAM wParam,
90 LPARAM lParam) = 0;
91 };
92
94
95 explicit KeyboardManager(WindowDelegate* delegate);
96
97 // Processes Win32 messages related to keyboard and text.
98 //
99 // All messages related to keyboard and text should be sent here without
100 // pre-processing, including WM_{SYS,}KEY{DOWN,UP} and WM_{SYS,}{DEAD,}CHAR.
101 // Other message types will trigger assertion error.
102 //
103 // |HandleMessage| returns true if Flutter keyboard system decides to handle
104 // this message synchronously. It doesn't mean that the Flutter framework
105 // handles it, which is reported asynchronously later. Not handling this
106 // message here usually means that this message is a redispatched message,
107 // but there are other rare cases too. |Window| should forward unhandled
108 // messages to |DefWindowProc|.
109 bool HandleMessage(UINT const message,
110 WPARAM const wparam,
111 LPARAM const lparam);
112
113 protected:
118
119 bool IsHighSurrogate() const { return IS_HIGH_SURROGATE(wparam); }
120
121 bool IsLowSurrogate() const { return IS_LOW_SURROGATE(wparam); }
122
123 bool IsGeneralKeyDown() const {
124 return action == WM_KEYDOWN || action == WM_SYSKEYDOWN;
125 }
126 };
127
130 uint8_t scancode;
132 char32_t character;
135
136 std::vector<Win32Message> session;
137 };
138
139 virtual void RedispatchEvent(std::unique_ptr<PendingEvent> event);
140
141 private:
142 using OnKeyCallback =
143 std::function<void(std::unique_ptr<PendingEvent>, bool)>;
144
145 struct PendingText {
146 bool ready;
147 std::u16string content;
148 bool placeholder = false;
149 };
150
151 // Resume processing the pending events.
152 //
153 // If there is at least one pending event and no event is being processed,
154 // the oldest pending event will be handed over to |PerformProcessEvent|.
155 // After the event is processed, the next pending event will be automatically
156 // started, until there are no pending events left.
157 //
158 // Otherwise, this call is a no-op.
159 void ProcessNextEvent();
160
161 // Process an event and call `callback` when it's completed.
162 //
163 // The `callback` is constructed by |ProcessNextEvent| to start the next
164 // event, and must be called exactly once.
165 void PerformProcessEvent(std::unique_ptr<PendingEvent> event,
166 std::function<void()> callback);
167
168 // Handle the result of |WindowDelegate::OnKey|, possibly dispatching the text
169 // result to |WindowDelegate::OnText| and then redispatching.
170 //
171 // The `pending_text` is either a valid iterator of `pending_texts`, or its
172 // end(). In the latter case, this OnKey message does not contain a text.
173 void HandleOnKeyResult(std::unique_ptr<PendingEvent> event,
174 bool framework_handled);
175
176 // Dispatch the text content of a |PendingEvent| to |WindowDelegate::OnText|.
177 //
178 // If the content is empty of invalid, |WindowDelegate::OnText| will not be
179 // called.
180 void DispatchText(const PendingEvent& event);
181
182 // Returns the type of the next WM message.
183 //
184 // The parameters limits the range of interested messages. See Win32's
185 // |PeekMessage| for information.
186 //
187 // If there's no message, returns 0.
188 UINT PeekNextMessageType(UINT wMsgFilterMin, UINT wMsgFilterMax);
189
190 // Find an event in the redispatch list that matches the given one.
191 //
192 // If an matching event is found, removes the matching event from the
193 // redispatch list, and returns true. Otherwise, returns false;
194 bool RemoveRedispatchedMessage(UINT action, WPARAM wparam, LPARAM lparam);
195
196 WindowDelegate* window_delegate_;
197
198 // Keeps track of all messages during the current session.
199 //
200 // At the end of a session, it is moved to the `PendingEvent`, which is
201 // passed to `WindowDelegate::OnKey`.
202 std::vector<Win32Message> current_session_;
203
204 // Whether the last event is a CtrlLeft key down.
205 //
206 // This is used to resolve a corner case described in |IsKeyDownAltRight|.
207 bool last_key_is_ctrl_left_down;
208
209 // The scancode of the last met CtrlLeft down.
210 //
211 // This is used to resolve a corner case described in |IsKeyDownAltRight|.
212 uint8_t ctrl_left_scancode;
213
214 // Whether a CtrlLeft up should be synthesized upon the next AltRight up.
215 //
216 // This is used to resolve a corner case described in |IsKeyDownAltRight|.
217 bool should_synthesize_ctrl_left_up;
218
219 // Store the messages coming from |HandleMessage|.
220 //
221 // Only one message is processed at a time. The next one will not start
222 // until the framework has responded to the previous message.
223 std::deque<std::unique_ptr<PendingEvent>> pending_events_;
224
225 // Whether a message is being processed.
226 std::atomic<bool> processing_event_;
227
228 // The queue of messages that have been redispatched to the system but have
229 // not yet been received for a second time.
230 std::deque<Win32Message> pending_redispatches_;
231
232 FML_DISALLOW_COPY_AND_ASSIGN(KeyboardManager);
233};
234
235} // namespace flutter
236
237#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_KEYBOARD_MANAGER_H_
virtual UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam)=0
virtual void OnText(const std::u16string &text)=0
virtual BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)=0
std::function< void(bool)> KeyEventCallback
virtual void OnKey(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback)=0
virtual uint32_t Win32MapVkToChar(uint32_t virtual_key)=0
KeyboardManager(WindowDelegate *delegate)
bool HandleMessage(UINT const message, WPARAM const wparam, LPARAM const lparam)
WindowDelegate::KeyEventCallback KeyEventCallback
virtual void RedispatchEvent(std::unique_ptr< PendingEvent > event)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
Dart_NativeFunction function
Definition: fuchsia.cc:51
std::u16string text
union flutter::testing::@2836::KeyboardChange::@76 content
Win32Message message
std::vector< Win32Message > session
int BOOL
Definition: windows_types.h:37
struct tagMSG * LPMSG
unsigned int UINT
Definition: windows_types.h:32
LONG_PTR LPARAM
Definition: windows_types.h:60
UINT_PTR WPARAM
Definition: windows_types.h:59