mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
This changes the Windows text handling so that keyboard events are sent to the framework first for handling, and then passed to the text input plugin, so that the framework has a chance to handle keys before they get given to the text field. This is complicated by the async nature of the interaction with the framework, since Windows wants a synchronous response. So, in this change, I always tell Windows that the event was handled, and if the framework (eventually) responds that it wasn't, then I synthesize a new event and send it with SendEvent. I also added support for detecting "extended" keys, since that was missing, and converted the OnKey handlers in the API to return a bool to indicate whether or not they have handled the event.
119 lines
4.7 KiB
C++
119 lines
4.7 KiB
C++
// 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/key_event_handler.h"
|
|
|
|
#include <rapidjson/document.h>
|
|
#include <memory>
|
|
|
|
#include "flutter/shell/platform/common/cpp/json_message_codec.h"
|
|
#include "flutter/shell/platform/windows/flutter_windows_view.h"
|
|
#include "flutter/shell/platform/windows/testing/test_binary_messenger.h"
|
|
#include "gmock/gmock.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
namespace flutter {
|
|
namespace testing {
|
|
|
|
static constexpr char kScanCodeKey[] = "scanCode";
|
|
static constexpr int kHandledScanCode = 20;
|
|
static constexpr int kUnhandledScanCode = 21;
|
|
|
|
std::unique_ptr<std::vector<uint8_t>> CreateResponse(bool handled) {
|
|
auto response_doc =
|
|
std::make_unique<rapidjson::Document>(rapidjson::kObjectType);
|
|
auto& allocator = response_doc->GetAllocator();
|
|
response_doc->AddMember("handled", handled, allocator);
|
|
return JsonMessageCodec::GetInstance().EncodeMessage(*response_doc);
|
|
}
|
|
|
|
TEST(KeyEventHandlerTest, KeyboardHookHandling) {
|
|
auto handled_message = CreateResponse(true);
|
|
auto unhandled_message = CreateResponse(false);
|
|
int received_scancode = 0;
|
|
|
|
TestBinaryMessenger messenger(
|
|
[&received_scancode, &handled_message, &unhandled_message](
|
|
const std::string& channel, const uint8_t* message,
|
|
size_t message_size, BinaryReply reply) {
|
|
if (channel == "flutter/keyevent") {
|
|
auto message_doc = JsonMessageCodec::GetInstance().DecodeMessage(
|
|
message, message_size);
|
|
received_scancode = (*message_doc)[kScanCodeKey].GetInt();
|
|
if (received_scancode == kHandledScanCode) {
|
|
reply(handled_message->data(), handled_message->size());
|
|
} else {
|
|
reply(unhandled_message->data(), unhandled_message->size());
|
|
}
|
|
}
|
|
});
|
|
|
|
int redispatch_scancode = 0;
|
|
KeyEventHandler handler(&messenger,
|
|
[&redispatch_scancode](UINT cInputs, LPINPUT pInputs,
|
|
int cbSize) -> UINT {
|
|
EXPECT_TRUE(cbSize > 0);
|
|
redispatch_scancode = pInputs->ki.wScan;
|
|
return 1;
|
|
});
|
|
|
|
handler.KeyboardHook(nullptr, 64, kHandledScanCode, WM_KEYDOWN, L'a', false);
|
|
EXPECT_EQ(received_scancode, kHandledScanCode);
|
|
EXPECT_EQ(redispatch_scancode, 0);
|
|
received_scancode = 0;
|
|
handler.KeyboardHook(nullptr, 64, kUnhandledScanCode, WM_KEYDOWN, L'b',
|
|
false);
|
|
EXPECT_EQ(received_scancode, kUnhandledScanCode);
|
|
EXPECT_EQ(redispatch_scancode, kUnhandledScanCode);
|
|
}
|
|
|
|
TEST(KeyEventHandlerTest, ExtendedKeysAreSentToRedispatch) {
|
|
auto handled_message = CreateResponse(true);
|
|
auto unhandled_message = CreateResponse(false);
|
|
int received_scancode = 0;
|
|
bool is_extended_key = false;
|
|
|
|
TestBinaryMessenger messenger(
|
|
[&received_scancode, &handled_message, &unhandled_message](
|
|
const std::string& channel, const uint8_t* message,
|
|
size_t message_size, BinaryReply reply) {
|
|
if (channel == "flutter/keyevent") {
|
|
auto message_doc = JsonMessageCodec::GetInstance().DecodeMessage(
|
|
message, message_size);
|
|
received_scancode = (*message_doc)[kScanCodeKey].GetInt();
|
|
if (received_scancode == kHandledScanCode) {
|
|
reply(handled_message->data(), handled_message->size());
|
|
} else {
|
|
reply(unhandled_message->data(), unhandled_message->size());
|
|
}
|
|
}
|
|
});
|
|
|
|
int redispatch_scancode = 0;
|
|
KeyEventHandler handler(
|
|
&messenger,
|
|
[&redispatch_scancode, &is_extended_key](UINT cInputs, LPINPUT pInputs,
|
|
int cbSize) -> UINT {
|
|
EXPECT_TRUE(cbSize > 0);
|
|
redispatch_scancode = pInputs->ki.wScan;
|
|
is_extended_key = (pInputs->ki.dwFlags & KEYEVENTF_EXTENDEDKEY) != 0;
|
|
return 1;
|
|
});
|
|
|
|
// Extended key flag is passed to redispatched events if set.
|
|
handler.KeyboardHook(nullptr, 64, kUnhandledScanCode, WM_KEYDOWN, L'b', true);
|
|
EXPECT_EQ(received_scancode, kUnhandledScanCode);
|
|
EXPECT_EQ(redispatch_scancode, kUnhandledScanCode);
|
|
EXPECT_EQ(is_extended_key, true);
|
|
|
|
// Extended key flag is not passed to redispatched events if not set.
|
|
handler.KeyboardHook(nullptr, 64, kUnhandledScanCode, WM_KEYDOWN, L'b',
|
|
false);
|
|
EXPECT_EQ(received_scancode, kUnhandledScanCode);
|
|
EXPECT_EQ(redispatch_scancode, kUnhandledScanCode);
|
|
EXPECT_EQ(is_extended_key, false);
|
|
}
|
|
|
|
} // namespace testing
|
|
} // namespace flutter
|