From f8b009e576947b6a5fbdaff48d3cd1bf9f860fb7 Mon Sep 17 00:00:00 2001 From: Stuart Morgan Date: Wed, 1 Jul 2020 14:06:06 -0700 Subject: [PATCH] Implement cursor support for Windows Implements the basic engine support for Windows for https://github.com/flutter/flutter/issues/31952 --- ci/licenses_golden/licenses_flutter | 2 + shell/platform/windows/BUILD.gn | 2 + shell/platform/windows/cursor_handler.cc | 84 +++++++++++++++++++ shell/platform/windows/cursor_handler.h | 38 +++++++++ shell/platform/windows/flutter_windows.cc | 4 - .../windows/testing/win32_window_test.cc | 2 + .../windows/testing/win32_window_test.h | 3 + .../platform/windows/win32_flutter_window.cc | 12 +++ shell/platform/windows/win32_flutter_window.h | 14 ++++ shell/platform/windows/win32_window.cc | 8 ++ shell/platform/windows/win32_window.h | 3 + 11 files changed, 168 insertions(+), 4 deletions(-) create mode 100644 shell/platform/windows/cursor_handler.cc create mode 100644 shell/platform/windows/cursor_handler.h diff --git a/ci/licenses_golden/licenses_flutter b/ci/licenses_golden/licenses_flutter index e01e277e8fda0..758f22facae9e 100755 --- a/ci/licenses_golden/licenses_flutter +++ b/ci/licenses_golden/licenses_flutter @@ -1300,6 +1300,8 @@ FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flu FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/flutter_view_controller.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/include/flutter/plugin_registrar_windows.h FILE: ../../../flutter/shell/platform/windows/client_wrapper/plugin_registrar_windows_unittests.cc +FILE: ../../../flutter/shell/platform/windows/cursor_handler.cc +FILE: ../../../flutter/shell/platform/windows/cursor_handler.h FILE: ../../../flutter/shell/platform/windows/dpi_utils.cc FILE: ../../../flutter/shell/platform/windows/dpi_utils.h FILE: ../../../flutter/shell/platform/windows/dpi_utils_unittests.cc diff --git a/shell/platform/windows/BUILD.gn b/shell/platform/windows/BUILD.gn index 248d3ccdc24c7..9135c94b99d53 100644 --- a/shell/platform/windows/BUILD.gn +++ b/shell/platform/windows/BUILD.gn @@ -41,6 +41,8 @@ source_set("flutter_windows_source") { sources = [ "angle_surface_manager.cc", "angle_surface_manager.h", + "cursor_handler.cc", + "cursor_handler.h", "dpi_utils.cc", "dpi_utils.h", "flutter_windows.cc", diff --git a/shell/platform/windows/cursor_handler.cc b/shell/platform/windows/cursor_handler.cc new file mode 100644 index 0000000000000..da7554c9fa7f8 --- /dev/null +++ b/shell/platform/windows/cursor_handler.cc @@ -0,0 +1,84 @@ +// 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/cursor_handler.h" + +#include + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/standard_method_codec.h" +#include "flutter/shell/platform/windows/win32_flutter_window.h" + +static constexpr char kChannelName[] = "flutter/mousecursor"; + +static constexpr char kActivateSystemCursorMethod[] = "activateSystemCursor"; + +static constexpr char kKindKey[] = "kind"; + +namespace flutter { + +namespace { + +// Maps a Flutter cursor constant to an HCURSOR. +// +// Returns the arrow cursor for unknown constants. +static HCURSOR GetCursorForKind(const std::string& kind) { + // The following mapping must be kept in sync with Flutter framework's + // mouse_cursor.dart + if (kind.compare("none") == 0) { + return nullptr; + } + const wchar_t* cursor_name = IDC_ARROW; + if (kind.compare("basic") == 0) { + cursor_name = IDC_ARROW; + } else if (kind.compare("click") == 0) { + cursor_name = IDC_HAND; + } else if (kind.compare("text") == 0) { + cursor_name = IDC_IBEAM; + } else if (kind.compare("forbidden") == 0) { + cursor_name = IDC_NO; + } else if (kind.compare("horizontalDoubleArrow") == 0) { + cursor_name = IDC_SIZEWE; + } else if (kind.compare("verticalDoubleArrow") == 0) { + cursor_name = IDC_SIZENS; + } + return ::LoadCursor(nullptr, cursor_name); +} + +} // namespace + +CursorHandler::CursorHandler(flutter::BinaryMessenger* messenger, + Win32FlutterWindow* window) + : channel_(std::make_unique>( + messenger, + kChannelName, + &flutter::StandardMethodCodec::GetInstance())), + window_(window) { + channel_->SetMethodCallHandler( + [this](const flutter::MethodCall& call, + std::unique_ptr> result) { + HandleMethodCall(call, std::move(result)); + }); +} + +void CursorHandler::HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result) { + const std::string& method = method_call.method_name(); + if (method.compare(kActivateSystemCursorMethod) == 0) { + const flutter::EncodableMap& arguments = + method_call.arguments()->MapValue(); + auto kind_iter = arguments.find(EncodableValue(kKindKey)); + if (kind_iter == arguments.end()) { + result->Error("Argument error", + "Missing argument while trying to activate system cursor"); + } + const std::string& kind = kind_iter->second.StringValue(); + window_->UpdateFlutterCursor(GetCursorForKind(kind)); + result->Success(); + } else { + result->NotImplemented(); + } +} + +} // namespace flutter diff --git a/shell/platform/windows/cursor_handler.h b/shell/platform/windows/cursor_handler.h new file mode 100644 index 0000000000000..2d9a7e35d994b --- /dev/null +++ b/shell/platform/windows/cursor_handler.h @@ -0,0 +1,38 @@ +// 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. + +#ifndef FLUTTER_SHELL_PLATFORM_WINDOWS_CURSOR_HANDLER_H_ +#define FLUTTER_SHELL_PLATFORM_WINDOWS_CURSOR_HANDLER_H_ + +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/binary_messenger.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/encodable_value.h" +#include "flutter/shell/platform/common/cpp/client_wrapper/include/flutter/method_channel.h" +#include "flutter/shell/platform/windows/public/flutter_windows.h" + +namespace flutter { + +class Win32FlutterWindow; + +// Handler for the cursor system channel. +class CursorHandler { + public: + explicit CursorHandler(flutter::BinaryMessenger* messenger, + Win32FlutterWindow* window); + + private: + // Called when a method is called on |channel_|; + void HandleMethodCall( + const flutter::MethodCall& method_call, + std::unique_ptr> result); + + // The MethodChannel used for communication with the Flutter engine. + std::unique_ptr> channel_; + + // A reference to the win32 window. + Win32FlutterWindow* window_; +}; + +} // namespace flutter + +#endif // FLUTTER_SHELL_PLATFORM_WINDOWS_CURSOR_HANDLER_H_ diff --git a/shell/platform/windows/flutter_windows.cc b/shell/platform/windows/flutter_windows.cc index 52319db72d52b..1a914bc6c3725 100644 --- a/shell/platform/windows/flutter_windows.cc +++ b/shell/platform/windows/flutter_windows.cc @@ -20,10 +20,6 @@ #include "flutter/shell/platform/common/cpp/path_utils.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/dpi_utils.h" -#include "flutter/shell/platform/windows/key_event_handler.h" -#include "flutter/shell/platform/windows/keyboard_hook_handler.h" -#include "flutter/shell/platform/windows/platform_handler.h" -#include "flutter/shell/platform/windows/text_input_plugin.h" #include "flutter/shell/platform/windows/win32_flutter_window.h" #include "flutter/shell/platform/windows/win32_task_runner.h" #include "flutter/shell/platform/windows/window_state.h" diff --git a/shell/platform/windows/testing/win32_window_test.cc b/shell/platform/windows/testing/win32_window_test.cc index da4bc43b9dabe..c7aaf6038bf9a 100644 --- a/shell/platform/windows/testing/win32_window_test.cc +++ b/shell/platform/windows/testing/win32_window_test.cc @@ -19,6 +19,8 @@ void Win32WindowTest::OnPointerUp(double x, double y, UINT button) {} void Win32WindowTest::OnPointerLeave() {} +void Win32WindowTest::OnSetCursor() {} + void Win32WindowTest::OnText(const std::u16string& text) {} void Win32WindowTest::OnKey(int key, diff --git a/shell/platform/windows/testing/win32_window_test.h b/shell/platform/windows/testing/win32_window_test.h index 5d8630c0181c6..dade7a4061e69 100644 --- a/shell/platform/windows/testing/win32_window_test.h +++ b/shell/platform/windows/testing/win32_window_test.h @@ -41,6 +41,9 @@ class Win32WindowTest : public Win32Window { // |Win32Window| void OnPointerLeave() override; + // |Win32Window| + void OnSetCursor() override; + // |Win32Window| void OnText(const std::u16string& text) override; diff --git a/shell/platform/windows/win32_flutter_window.cc b/shell/platform/windows/win32_flutter_window.cc index 4976a70b064d0..b80387e97358d 100644 --- a/shell/platform/windows/win32_flutter_window.cc +++ b/shell/platform/windows/win32_flutter_window.cc @@ -11,6 +11,7 @@ constexpr int base_dpi = 96; Win32FlutterWindow::Win32FlutterWindow(int width, int height) { surface_manager = std::make_unique(); Win32Window::InitializeChild("FLUTTERVIEW", width, height); + current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW); } Win32FlutterWindow::~Win32FlutterWindow() { @@ -60,6 +61,8 @@ void Win32FlutterWindow::SetState(FLUTTER_API_SYMBOL(FlutterEngine) eng) { std::make_unique(internal_plugin_messenger)); platform_handler_ = std::make_unique( internal_plugin_messenger, this); + cursor_handler_ = + std::make_unique(internal_plugin_messenger, this); process_events_ = true; } @@ -189,6 +192,10 @@ void Win32FlutterWindow::OnFontChange() { FlutterEngineReloadSystemFonts(engine_); } +void Win32FlutterWindow::UpdateFlutterCursor(HCURSOR cursor) { + current_cursor_ = cursor; +} + // Sends new size information to FlutterEngine. void Win32FlutterWindow::SendWindowMetrics() { if (engine_ == nullptr) { @@ -264,6 +271,10 @@ void Win32FlutterWindow::SendPointerLeave() { SendPointerEventWithData(event); } +void Win32FlutterWindow::OnSetCursor() { + ::SetCursor(current_cursor_); +} + void Win32FlutterWindow::SendText(const std::u16string& text) { for (const auto& handler : keyboard_hook_handlers_) { handler->TextHook(this, text); @@ -362,4 +373,5 @@ void Win32FlutterWindow::DestroyRenderSurface() { } render_surface = EGL_NO_SURFACE; } + } // namespace flutter diff --git a/shell/platform/windows/win32_flutter_window.h b/shell/platform/windows/win32_flutter_window.h index aff194a0e5ea4..c2fd88ff3ff71 100644 --- a/shell/platform/windows/win32_flutter_window.h +++ b/shell/platform/windows/win32_flutter_window.h @@ -14,6 +14,7 @@ #include "flutter/shell/platform/common/cpp/incoming_message_dispatcher.h" #include "flutter/shell/platform/embedder/embedder.h" #include "flutter/shell/platform/windows/angle_surface_manager.h" +#include "flutter/shell/platform/windows/cursor_handler.h" #include "flutter/shell/platform/windows/key_event_handler.h" #include "flutter/shell/platform/windows/keyboard_hook_handler.h" #include "flutter/shell/platform/windows/platform_handler.h" @@ -56,6 +57,9 @@ class Win32FlutterWindow : public Win32Window { // |Win32Window| void OnPointerLeave() override; + // |Win32Window| + void OnSetCursor() override; + // |Win32Window| void OnText(const std::u16string& text) override; @@ -92,6 +96,10 @@ class Win32FlutterWindow : public Win32Window { // dimensions in physical void SendWindowMetrics(); + // Sets the cursor that is set when the mouse is in the client area of the + // window. If nullptr, the cursor will be hidden. + void UpdateFlutterCursor(HCURSOR cursor); + private: // Destroy current rendering surface if one has been allocated. void DestroyRenderSurface(); @@ -150,6 +158,9 @@ class Win32FlutterWindow : public Win32Window { // been added since it was last removed). bool pointer_currently_added_ = false; + // The last cursor set by Flutter. Defaults to the arrow cursor. + HCURSOR current_cursor_; + // The window handle given to API clients. std::unique_ptr window_wrapper_; @@ -169,6 +180,9 @@ class Win32FlutterWindow : public Win32Window { // Handler for the flutter/platform channel. std::unique_ptr platform_handler_; + // Handler for cursor events. + std::unique_ptr cursor_handler_; + // should we forword input messages or not bool process_events_ = false; }; diff --git a/shell/platform/windows/win32_window.cc b/shell/platform/windows/win32_window.cc index e4cf979167b73..04deae92882bd 100644 --- a/shell/platform/windows/win32_window.cc +++ b/shell/platform/windows/win32_window.cc @@ -150,6 +150,14 @@ Win32Window::MessageHandler(HWND hwnd, // detected again. tracking_mouse_leave_ = false; break; + case WM_SETCURSOR: { + UINT hit_test_result = LOWORD(lparam); + if (hit_test_result == HTCLIENT) { + window->OnSetCursor(); + return TRUE; + } + break; + } case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: diff --git a/shell/platform/windows/win32_window.h b/shell/platform/windows/win32_window.h index d4481d89e2a68..38a3e6cdff4cc 100644 --- a/shell/platform/windows/win32_window.h +++ b/shell/platform/windows/win32_window.h @@ -102,6 +102,9 @@ class Win32Window { // Called when the mouse leaves the window. virtual void OnPointerLeave() = 0; + // Called when the cursor should be set for the client area. + virtual void OnSetCursor() = 0; + // Called when text input occurs. virtual void OnText(const std::u16string& text) = 0;