blob: f4feebbb3a132a5e0fb40c03242872b327dd3ad9 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/shell/platform/windows/keyboard_key_handler.h"
#include <windows.h>
#include "flutter/fml/logging.h"
#include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h"
#include "flutter/shell/platform/windows/keyboard_utils.h"
namespace flutter {
namespace {
// The maximum number of pending events to keep before
// emitting a warning on the console about unhandled events.
static constexpr int kMaxPendingEvents = 1000;
// The name of the channel for keyboard state queries.
static constexpr char kChannelName[] = "flutter/keyboard";
static constexpr char kGetKeyboardStateMethod[] = "getKeyboardState";
} // namespace
KeyboardKeyHandler::KeyboardKeyHandlerDelegate::~KeyboardKeyHandlerDelegate() =
default;
KeyboardKeyHandler::KeyboardKeyHandler(flutter::BinaryMessenger* messenger)
: last_sequence_id_(1),
channel_(std::make_unique<MethodChannel<EncodableValue>>(
messenger,
kChannelName,
&StandardMethodCodec::GetInstance())) {}
KeyboardKeyHandler::~KeyboardKeyHandler() = default;
void KeyboardKeyHandler::InitKeyboardChannel() {
channel_->SetMethodCallHandler(
[this](const MethodCall<EncodableValue>& call,
std::unique_ptr<MethodResult<EncodableValue>> result) {
HandleMethodCall(call, std::move(result));
});
}
void KeyboardKeyHandler::HandleMethodCall(
const MethodCall<EncodableValue>& method_call,
std::unique_ptr<MethodResult<EncodableValue>> result) {
const std::string& method = method_call.method_name();
if (method.compare(kGetKeyboardStateMethod) == 0) {
EncodableMap value;
const auto& pressed_state = GetPressedState();
for (const auto& pressed_key : pressed_state) {
EncodableValue physical_value(static_cast<long long>(pressed_key.first));
EncodableValue logical_value(static_cast<long long>(pressed_key.second));
value[physical_value] = logical_value;
}
result->Success(EncodableValue(value));
} else {
result->NotImplemented();
}
}
void KeyboardKeyHandler::AddDelegate(
std::unique_ptr<KeyboardKeyHandlerDelegate> delegate) {
delegates_.push_back(std::move(delegate));
}
void KeyboardKeyHandler::SyncModifiersIfNeeded(int modifiers_state) {
// Only call SyncModifierIfNeeded on the key embedder handler.
auto& key_embedder_handler = delegates_.front();
key_embedder_handler->SyncModifiersIfNeeded(modifiers_state);
}
std::map<uint64_t, uint64_t> KeyboardKeyHandler::GetPressedState() {
// The embedder responder is the first element in delegates_.
auto& key_embedder_handler = delegates_.front();
return key_embedder_handler->GetPressedState();
}
void KeyboardKeyHandler::KeyboardHook(int key,
int scancode,
int action,
char32_t character,
bool extended,
bool was_down,
KeyEventCallback callback) {
std::unique_ptr<PendingEvent> incoming = std::make_unique<PendingEvent>();
uint64_t sequence_id = ++last_sequence_id_;
incoming->sequence_id = sequence_id;
incoming->unreplied = delegates_.size();
incoming->any_handled = false;
incoming->callback = std::move(callback);
if (pending_responds_.size() > kMaxPendingEvents) {
FML_LOG(ERROR)
<< "There are " << pending_responds_.size()
<< " keyboard events that have not yet received a response from the "
<< "framework. Are responses being sent?";
}
pending_responds_.push_back(std::move(incoming));
for (const auto& delegate : delegates_) {
delegate->KeyboardHook(key, scancode, action, character, extended, was_down,
[sequence_id, this](bool handled) {
ResolvePendingEvent(sequence_id, handled);
});
}
// |ResolvePendingEvent| might trigger redispatching synchronously,
// which might occur before |KeyboardHook| is returned. This won't
// make events out of order though, because |KeyboardHook| will always
// return true at this time, preventing this event from affecting
// others.
}
void KeyboardKeyHandler::ResolvePendingEvent(uint64_t sequence_id,
bool handled) {
// Find the pending event
for (auto iter = pending_responds_.begin(); iter != pending_responds_.end();
++iter) {
if ((*iter)->sequence_id == sequence_id) {
PendingEvent& event = **iter;
event.any_handled = event.any_handled || handled;
event.unreplied -= 1;
FML_DCHECK(event.unreplied >= 0)
<< "Pending events must have unreplied count > 0";
// If all delegates have replied, report if any of them handled the event.
if (event.unreplied == 0) {
std::unique_ptr<PendingEvent> event_ptr = std::move(*iter);
pending_responds_.erase(iter);
event.callback(event.any_handled);
}
// Return here; |iter| can't do ++ after erase.
return;
}
}
// The pending event should always be found.
FML_LOG(FATAL) << "Could not find pending key event for sequence ID "
<< sequence_id;
}
} // namespace flutter