Flutter Engine
The Flutter Engine
keyboard_key_handler.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/keyboard_key_handler.h"
6
7#include <windows.h>
8
9#include "flutter/fml/logging.h"
10#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
11#include "flutter/shell/platform/windows/keyboard_utils.h"
12
13namespace flutter {
14
15namespace {
16
17// The maximum number of pending events to keep before
18// emitting a warning on the console about unhandled events.
19static constexpr int kMaxPendingEvents = 1000;
20
21// The name of the channel for keyboard state queries.
22static constexpr char kChannelName[] = "flutter/keyboard";
23
24static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
25
26} // namespace
27
29 default;
30
32 : last_sequence_id_(1),
33 channel_(std::make_unique<MethodChannel<EncodableValue>>(
34 messenger,
36 &StandardMethodCodec::GetInstance())) {}
37
39
41 channel_->SetMethodCallHandler(
42 [this](const MethodCall<EncodableValue>& call,
43 std::unique_ptr<MethodResult<EncodableValue>> result) {
44 HandleMethodCall(call, std::move(result));
45 });
46}
47
48void KeyboardKeyHandler::HandleMethodCall(
50 std::unique_ptr<MethodResult<EncodableValue>> result) {
51 const std::string& method = method_call.method_name();
52 if (method.compare(kGetKeyboardStateMethod) == 0) {
54 const auto& pressed_state = GetPressedState();
55 for (const auto& pressed_key : pressed_state) {
56 EncodableValue physical_value(static_cast<long long>(pressed_key.first));
57 EncodableValue logical_value(static_cast<long long>(pressed_key.second));
58 value[physical_value] = logical_value;
59 }
60 result->Success(EncodableValue(value));
61 } else {
62 result->NotImplemented();
63 }
64}
65
67 std::unique_ptr<KeyboardKeyHandlerDelegate> delegate) {
68 delegates_.push_back(std::move(delegate));
69}
70
72 // Only call SyncModifierIfNeeded on the key embedder handler.
73 auto& key_embedder_handler = delegates_.front();
74 key_embedder_handler->SyncModifiersIfNeeded(modifiers_state);
75}
76
77std::map<uint64_t, uint64_t> KeyboardKeyHandler::GetPressedState() {
78 // The embedder responder is the first element in delegates_.
79 auto& key_embedder_handler = delegates_.front();
80 return key_embedder_handler->GetPressedState();
81}
82
84 int scancode,
85 int action,
86 char32_t character,
87 bool extended,
88 bool was_down,
90 std::unique_ptr<PendingEvent> incoming = std::make_unique<PendingEvent>();
91
92 uint64_t sequence_id = ++last_sequence_id_;
93 incoming->sequence_id = sequence_id;
94 incoming->unreplied = delegates_.size();
95 incoming->any_handled = false;
96 incoming->callback = std::move(callback);
97
98 if (pending_responds_.size() > kMaxPendingEvents) {
100 << "There are " << pending_responds_.size()
101 << " keyboard events that have not yet received a response from the "
102 << "framework. Are responses being sent?";
103 }
104 pending_responds_.push_back(std::move(incoming));
105
106 for (const auto& delegate : delegates_) {
107 delegate->KeyboardHook(key, scancode, action, character, extended, was_down,
108 [sequence_id, this](bool handled) {
109 ResolvePendingEvent(sequence_id, handled);
110 });
111 }
112
113 // |ResolvePendingEvent| might trigger redispatching synchronously,
114 // which might occur before |KeyboardHook| is returned. This won't
115 // make events out of order though, because |KeyboardHook| will always
116 // return true at this time, preventing this event from affecting
117 // others.
118}
119
120void KeyboardKeyHandler::ResolvePendingEvent(uint64_t sequence_id,
121 bool handled) {
122 // Find the pending event
123 for (auto iter = pending_responds_.begin(); iter != pending_responds_.end();
124 ++iter) {
125 if ((*iter)->sequence_id == sequence_id) {
126 PendingEvent& event = **iter;
127 event.any_handled = event.any_handled || handled;
128 event.unreplied -= 1;
129 FML_DCHECK(event.unreplied >= 0)
130 << "Pending events must have unreplied count > 0";
131 // If all delegates have replied, report if any of them handled the event.
132 if (event.unreplied == 0) {
133 std::unique_ptr<PendingEvent> event_ptr = std::move(*iter);
134 pending_responds_.erase(iter);
135 event.callback(event.any_handled);
136 }
137 // Return here; |iter| can't do ++ after erase.
138 return;
139 }
140 }
141 // The pending event should always be found.
142 FML_LOG(FATAL) << "Could not find pending key event for sequence ID "
143 << sequence_id;
144}
145
146} // namespace flutter
static NSString *const kChannelName
std::function< void(bool)> KeyEventCallback
void SyncModifiersIfNeeded(int modifiers_state) override
KeyboardKeyHandler(flutter::BinaryMessenger *messenger)
void KeyboardHook(int key, int scancode, int action, char32_t character, bool extended, bool was_down, KeyEventCallback callback) override
void AddDelegate(std::unique_ptr< KeyboardKeyHandlerDelegate > delegate)
std::map< uint64_t, uint64_t > GetPressedState() override
#define FATAL(error)
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
FlKeyEvent * event
static constexpr char kGetKeyboardStateMethod[]
G_BEGIN_DECLS G_MODULE_EXPORT FlMethodCall * method_call
uint8_t value
GAsyncResult * result
#define FML_LOG(severity)
Definition: logging.h:82
#define FML_DCHECK(condition)
Definition: logging.h:103
def call(args)
Definition: dom.py:159
std::map< EncodableValue, EncodableValue > EncodableMap
Definition: ref_ptr.h:256
#define ERROR(message)
Definition: elf_loader.cc:260