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 |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.
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 
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:103
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:109
flutter::KeyboardManager::WindowDelegate
Definition: keyboard_manager.h:52
flutter::KeyboardManager::HandleMessage
bool HandleMessage(UINT const message, WPARAM const wparam, LPARAM const lparam)
Definition: keyboard_manager.cc:144
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
content
union flutter::testing::@87::KeyboardChange::@0 content
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:51
flutter::KeyboardManager::WindowDelegate::Win32DispatchMessage
virtual UINT Win32DispatchMessage(UINT Msg, WPARAM wParam, LPARAM lParam)=0