| Flutter Windows Embedder |

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
17 namespace 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 |Window|, which also implements
30 // the window delegate. The key calls and text calls are forwarded to those of
31 // |Window|'s, and consequently, those of |FlutterWindowsView|'s.
32 //
33 // ## Terminology
34 //
35 // The keyboard system follows the following terminology instead of the
36 // inconsistent/incomplete one used by Win32:
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.
46 class KeyboardManager {
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|.
52 class WindowDelegate {
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,
70 KeyEventCallback callback) = 0;
71
72 // Win32's PeekMessage.
73 //
74 // Used to process key messages.
75 virtual BOOL Win32PeekMessage(LPMSG lpMsg,
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.
88 virtual UINT Win32DispatchMessage(UINT Msg,
89 WPARAM wParam,
90 LPARAM lParam) = 0;
91 };
92
93 using KeyEventCallback = WindowDelegate::KeyEventCallback;
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:
114 struct Win32Message {
115 UINT action;
116 WPARAM wparam;
117 LPARAM lparam;
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
128 struct PendingEvent {
129 WPARAM key;
130 uint8_t scancode;
131 UINT action;
132 char32_t character;
133 bool extended;
134 bool was_down;
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_
flutter::KeyboardManager::KeyboardManager
KeyboardManager(WindowDelegate *delegate)
Definition: keyboard_manager.cc:105
flutter::KeyboardManager::Win32Message::IsGeneralKeyDown
bool IsGeneralKeyDown() const
Definition: keyboard_manager.h:123
scancode
int scancode
Definition: keyboard_key_handler_unittests.cc:115
was_down
bool was_down
Definition: keyboard_key_handler_unittests.cc:119
extended
bool extended
Definition: keyboard_key_handler_unittests.cc:118
flutter::KeyboardManager::WindowDelegate::Win32MapVkToChar
virtual uint32_t Win32MapVkToChar(uint32_t virtual_key)=0
flutter::KeyboardManager::PendingEvent::extended
bool extended
Definition: keyboard_manager.h:133
flutter::KeyboardManager::WindowDelegate::OnText
virtual void OnText(const std::u16string &text)=0
character
char32_t character
Definition: keyboard_key_handler_unittests.cc:117
flutter::KeyboardManager::WindowDelegate::KeyEventCallback
std::function< void(bool)> KeyEventCallback
Definition: keyboard_manager.h:54
flutter::KeyboardManager::RedispatchEvent
virtual void RedispatchEvent(std::unique_ptr< PendingEvent > event)
Definition: keyboard_manager.cc:111
flutter::KeyboardManager::WindowDelegate
Definition: keyboard_manager.h:52
content
union flutter::testing::@66::KeyboardChange::@0 content
flutter::KeyboardManager::HandleMessage
bool HandleMessage(UINT const message, WPARAM const wparam, LPARAM const lparam)
Definition: keyboard_manager.cc:146
flutter::KeyboardManager::Win32Message::lparam
LPARAM lparam
Definition: keyboard_manager.h:117
text
std::u16string text
Definition: keyboard_unittests.cc:332
flutter::KeyboardManager::WindowDelegate::OnKey
virtual void OnKey(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback)=0
flutter::KeyboardManager::PendingEvent::key
WPARAM key
Definition: keyboard_manager.h:129
flutter::KeyboardManager::PendingEvent::session
std::vector< Win32Message > session
Definition: keyboard_manager.h:136
flutter::KeyboardManager::WindowDelegate::~WindowDelegate
virtual ~WindowDelegate()=default
flutter::KeyboardManager::PendingEvent::was_down
bool was_down
Definition: keyboard_manager.h:134
flutter
Definition: accessibility_bridge_windows.cc:11
flutter::KeyboardManager::Win32Message::IsHighSurrogate
bool IsHighSurrogate() const
Definition: keyboard_manager.h:119
flutter::KeyboardManager::WindowDelegate::Win32PeekMessage
virtual BOOL Win32PeekMessage(LPMSG lpMsg, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)=0
flutter::KeyboardManager
Definition: keyboard_manager.h:46
flutter::KeyboardManager::PendingEvent::character
char32_t character
Definition: keyboard_manager.h:132
flutter::KeyboardManager::PendingEvent
Definition: keyboard_manager.h:128
flutter::KeyboardManager::Win32Message::wparam
WPARAM wparam
Definition: keyboard_manager.h:116
flutter::KeyboardManager::Win32Message
Definition: keyboard_manager.h:114
flutter::KeyboardManager::KeyEventCallback
WindowDelegate::KeyEventCallback KeyEventCallback
Definition: keyboard_manager.h:93
flutter::KeyboardManager::PendingEvent::scancode
uint8_t scancode
Definition: keyboard_manager.h:130
message
Win32Message message
Definition: keyboard_unittests.cc:137
action
int action
Definition: keyboard_key_handler_unittests.cc:116
flutter::KeyboardManager::PendingEvent::action
UINT action
Definition: keyboard_manager.h:131
key
int key
Definition: keyboard_key_handler_unittests.cc:114
flutter::KeyboardManager::Win32Message::action
UINT action
Definition: keyboard_manager.h:115
flutter::KeyboardManager::Win32Message::IsLowSurrogate
bool IsLowSurrogate() const
Definition: keyboard_manager.h:121
callback
FlutterDesktopBinaryReply callback
Definition: flutter_windows_view_unittests.cc:46
flutter::KeyboardManager::WindowDelegate::Win32DispatchMessage
virtual UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam)=0