diff --git a/engine/src/flutter/shell/platform/windows/cursor_handler.cc b/engine/src/flutter/shell/platform/windows/cursor_handler.cc index 19cd90567a6..638fd59ead1 100644 --- a/engine/src/flutter/shell/platform/windows/cursor_handler.cc +++ b/engine/src/flutter/shell/platform/windows/cursor_handler.cc @@ -8,7 +8,6 @@ #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_method_codec.h" #include "flutter/shell/platform/windows/flutter_windows_engine.h" -#include "flutter/shell/platform/windows/flutter_windows_view.h" static constexpr char kChannelName[] = "flutter/mousecursor"; @@ -74,16 +73,7 @@ void CursorHandler::HandleMethodCall( return; } const auto& kind = std::get(kind_iter->second); - - // TODO(loicsharma): Remove implicit view assumption. - // https://github.com/flutter/flutter/issues/142845 - FlutterWindowsView* view = engine_->view(kImplicitViewId); - if (view == nullptr) { - result->Error(kCursorError, - "Cursor is not available in Windows headless mode"); - return; - } - view->UpdateFlutterCursor(kind); + engine_->UpdateFlutterCursor(kind); result->Success(); } else if (method.compare(kCreateCustomCursorMethod) == 0) { const auto& arguments = std::get(*method_call.arguments()); @@ -167,16 +157,7 @@ void CursorHandler::HandleMethodCall( return; } HCURSOR cursor = custom_cursors_[name]; - - // TODO(loicsharma): Remove implicit view assumption. - // https://github.com/flutter/flutter/issues/142845 - FlutterWindowsView* view = engine_->view(kImplicitViewId); - if (view == nullptr) { - result->Error(kCursorError, - "Cursor is not available in Windows headless mode"); - return; - } - view->SetFlutterCursor(cursor); + engine_->SetFlutterCursor(cursor); result->Success(); } else if (method.compare(kDeleteCustomCursorMethod) == 0) { const auto& arguments = std::get(*method_call.arguments()); diff --git a/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc b/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc index f6bc9c50a81..c93cc4905bf 100644 --- a/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/cursor_handler_unittests.cc @@ -14,6 +14,7 @@ #include "flutter/shell/platform/windows/testing/engine_modifier.h" #include "flutter/shell/platform/windows/testing/flutter_windows_engine_builder.h" #include "flutter/shell/platform/windows/testing/mock_window_binding_handler.h" +#include "flutter/shell/platform/windows/testing/mock_windows_proc_table.h" #include "flutter/shell/platform/windows/testing/test_binary_messenger.h" #include "flutter/shell/platform/windows/testing/windows_test.h" #include "gmock/gmock.h" @@ -24,6 +25,7 @@ namespace testing { namespace { using ::testing::_; +using ::testing::IsNull; using ::testing::NotNull; using ::testing::Return; @@ -63,6 +65,7 @@ class CursorHandlerTest : public WindowsTest { FlutterWindowsEngine* engine() { return engine_.get(); } FlutterWindowsView* view() { return view_.get(); } MockWindowBindingHandler* window() { return window_; } + MockWindowsProcTable* proc_table() { return windows_proc_table_.get(); } void UseHeadlessEngine() { FlutterWindowsEngineBuilder builder{GetContext()}; @@ -71,7 +74,10 @@ class CursorHandlerTest : public WindowsTest { } void UseEngineWithView() { + windows_proc_table_ = std::make_shared(); + FlutterWindowsEngineBuilder builder{GetContext()}; + builder.SetWindowsProcTable(windows_proc_table_); auto window = std::make_unique(); EXPECT_CALL(*window.get(), SetView).Times(1); @@ -79,17 +85,14 @@ class CursorHandlerTest : public WindowsTest { window_ = window.get(); engine_ = builder.Build(); - view_ = std::make_unique(kImplicitViewId, engine_.get(), - std::move(window)); - - EngineModifier modifier{engine_.get()}; - modifier.SetImplicitView(view_.get()); + view_ = engine_->CreateView(std::move(window)); } private: std::unique_ptr engine_; std::unique_ptr view_; MockWindowBindingHandler* window_; + std::shared_ptr windows_proc_table_; FML_DISALLOW_COPY_AND_ASSIGN(CursorHandlerTest); }; @@ -100,7 +103,8 @@ TEST_F(CursorHandlerTest, ActivateSystemCursor) { TestBinaryMessenger messenger; CursorHandler cursor_handler(&messenger, engine()); - EXPECT_CALL(*window(), UpdateFlutterCursor("click")).Times(1); + EXPECT_CALL(*proc_table(), LoadCursor(IsNull(), IDC_HAND)).Times(1); + EXPECT_CALL(*proc_table(), SetCursor).Times(1); bool success = false; MethodResultFunctions<> result_handler( @@ -120,33 +124,6 @@ TEST_F(CursorHandlerTest, ActivateSystemCursor) { EXPECT_TRUE(success); } -TEST_F(CursorHandlerTest, ActivateSystemCursorRequiresView) { - UseHeadlessEngine(); - - TestBinaryMessenger messenger; - CursorHandler cursor_handler(&messenger, engine()); - - bool error = false; - MethodResultFunctions<> result_handler( - nullptr, - [&error](const std::string& error_code, const std::string& error_message, - const EncodableValue* value) { - error = true; - EXPECT_EQ(error_message, - "Cursor is not available in Windows headless mode"); - }, - nullptr); - - SimulateCursorMessage(&messenger, kActivateSystemCursorMethod, - std::make_unique(EncodableMap{ - {EncodableValue("device"), EncodableValue(0)}, - {EncodableValue("kind"), EncodableValue("click")}, - }), - &result_handler); - - EXPECT_TRUE(error); -} - TEST_F(CursorHandlerTest, CreateCustomCursor) { UseEngineWithView(); @@ -196,7 +173,8 @@ TEST_F(CursorHandlerTest, SetCustomCursor) { }, nullptr, nullptr); - EXPECT_CALL(*window(), SetFlutterCursor(/*cursor=*/NotNull())).Times(1); + EXPECT_CALL(*proc_table(), LoadCursor).Times(0); + EXPECT_CALL(*proc_table(), SetCursor(NotNull())).Times(1); SimulateCursorMessage(&messenger, kCreateCustomCursorMethod, std::make_unique(EncodableMap{ @@ -218,47 +196,6 @@ TEST_F(CursorHandlerTest, SetCustomCursor) { EXPECT_TRUE(success); } -TEST_F(CursorHandlerTest, SetCustomCursorRequiresView) { - UseHeadlessEngine(); - - TestBinaryMessenger messenger; - CursorHandler cursor_handler(&messenger, engine()); - - // Create a 4x4 raw BGRA test cursor buffer. - std::vector buffer(4 * 4 * 4, 0); - - bool error = false; - MethodResultFunctions<> create_result_handler(nullptr, nullptr, nullptr); - MethodResultFunctions<> set_result_handler( - nullptr, - [&error](const std::string& error_code, const std::string& error_message, - const EncodableValue* value) { - error = true; - EXPECT_EQ(error_message, - "Cursor is not available in Windows headless mode"); - }, - nullptr); - - SimulateCursorMessage(&messenger, kCreateCustomCursorMethod, - std::make_unique(EncodableMap{ - {EncodableValue("name"), EncodableValue("hello")}, - {EncodableValue("buffer"), EncodableValue(buffer)}, - {EncodableValue("width"), EncodableValue(4)}, - {EncodableValue("height"), EncodableValue(4)}, - {EncodableValue("hotX"), EncodableValue(0.0)}, - {EncodableValue("hotY"), EncodableValue(0.0)}, - }), - &create_result_handler); - - SimulateCursorMessage(&messenger, kSetCustomCursorMethod, - std::make_unique(EncodableMap{ - {EncodableValue("name"), EncodableValue("hello")}, - }), - &set_result_handler); - - EXPECT_TRUE(error); -} - TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) { UseEngineWithView(); @@ -277,7 +214,8 @@ TEST_F(CursorHandlerTest, SetNonexistentCustomCursor) { }, nullptr); - EXPECT_CALL(*window(), SetFlutterCursor).Times(0); + EXPECT_CALL(*proc_table(), LoadCursor).Times(0); + EXPECT_CALL(*proc_table(), SetCursor).Times(0); SimulateCursorMessage(&messenger, kSetCustomCursorMethod, std::make_unique(EncodableMap{ diff --git a/engine/src/flutter/shell/platform/windows/flutter_window.cc b/engine/src/flutter/shell/platform/windows/flutter_window.cc index fddba026791..6c781c41d12 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_window.cc @@ -30,49 +30,6 @@ static const int kMaxTouchDeviceId = 128; static const int kLinesPerScrollWindowsDefault = 3; -// Maps a Flutter cursor name to an HCURSOR. -// -// Returns the arrow cursor for unknown constants. -// -// This map must be kept in sync with Flutter framework's -// services/mouse_cursor.dart. -static HCURSOR GetCursorByName(const std::string& cursor_name) { - static auto* cursors = new std::map{ - {"allScroll", IDC_SIZEALL}, - {"basic", IDC_ARROW}, - {"click", IDC_HAND}, - {"forbidden", IDC_NO}, - {"help", IDC_HELP}, - {"move", IDC_SIZEALL}, - {"none", nullptr}, - {"noDrop", IDC_NO}, - {"precise", IDC_CROSS}, - {"progress", IDC_APPSTARTING}, - {"text", IDC_IBEAM}, - {"resizeColumn", IDC_SIZEWE}, - {"resizeDown", IDC_SIZENS}, - {"resizeDownLeft", IDC_SIZENESW}, - {"resizeDownRight", IDC_SIZENWSE}, - {"resizeLeft", IDC_SIZEWE}, - {"resizeLeftRight", IDC_SIZEWE}, - {"resizeRight", IDC_SIZEWE}, - {"resizeRow", IDC_SIZENS}, - {"resizeUp", IDC_SIZENS}, - {"resizeUpDown", IDC_SIZENS}, - {"resizeUpLeft", IDC_SIZENWSE}, - {"resizeUpRight", IDC_SIZENESW}, - {"resizeUpLeftDownRight", IDC_SIZENWSE}, - {"resizeUpRightDownLeft", IDC_SIZENESW}, - {"wait", IDC_WAIT}, - }; - const wchar_t* idc_name = IDC_ARROW; - auto it = cursors->find(cursor_name); - if (it != cursors->end()) { - idc_name = it->second; - } - return ::LoadCursor(nullptr, idc_name); -} - static constexpr int32_t kDefaultPointerDeviceId = 0; // This method is only valid during a window message related to mouse/touch @@ -144,7 +101,6 @@ FlutterWindow::FlutterWindow( keyboard_manager_ = std::make_unique(this); InitializeChild("FLUTTERVIEW", width, height); - current_cursor_ = ::LoadCursor(nullptr, IDC_ARROW); } // Base constructor for mocks @@ -176,15 +132,6 @@ PhysicalWindowBounds FlutterWindow::GetPhysicalWindowBounds() { return {GetCurrentWidth(), GetCurrentHeight()}; } -void FlutterWindow::UpdateFlutterCursor(const std::string& cursor_name) { - SetFlutterCursor(GetCursorByName(cursor_name)); -} - -void FlutterWindow::SetFlutterCursor(HCURSOR cursor) { - current_cursor_ = cursor; - ::SetCursor(current_cursor_); -} - bool FlutterWindow::Focus() { auto hwnd = GetWindowHandle(); if (hwnd == nullptr) { @@ -257,10 +204,6 @@ void FlutterWindow::OnPointerLeave(double x, binding_handler_delegate_->OnPointerLeave(x, y, device_kind, device_id); } -void FlutterWindow::OnSetCursor() { - ::SetCursor(current_cursor_); -} - void FlutterWindow::OnText(const std::u16string& text) { binding_handler_delegate_->OnText(text); } @@ -649,7 +592,8 @@ FlutterWindow::HandleMessage(UINT const message, case WM_SETCURSOR: { UINT hit_test_result = LOWORD(lparam); if (hit_test_result == HTCLIENT) { - OnSetCursor(); + // Halt further processing to prevent DefWindowProc from setting the + // cursor back to the registered class cursor. return TRUE; } break; diff --git a/engine/src/flutter/shell/platform/windows/flutter_window.h b/engine/src/flutter/shell/platform/windows/flutter_window.h index 1ce6cd5987e..01d3175b041 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window.h +++ b/engine/src/flutter/shell/platform/windows/flutter_window.h @@ -104,9 +104,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate, FlutterPointerDeviceKind device_kind, int32_t device_id); - // Called when the cursor should be set for the client area. - virtual void OnSetCursor(); - // |WindowBindingHandlerDelegate| virtual void OnText(const std::u16string& text) override; @@ -161,12 +158,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate, // |FlutterWindowBindingHandler| virtual PhysicalWindowBounds GetPhysicalWindowBounds() override; - // |FlutterWindowBindingHandler| - virtual void UpdateFlutterCursor(const std::string& cursor_name) override; - - // |FlutterWindowBindingHandler| - virtual void SetFlutterCursor(HCURSOR cursor) override; - // |FlutterWindowBindingHandler| virtual bool OnBitmapSurfaceCleared() override; @@ -329,9 +320,6 @@ class FlutterWindow : public KeyboardManager::WindowDelegate, // windowing and input state. WindowBindingHandlerDelegate* binding_handler_delegate_ = nullptr; - // The last cursor set by Flutter. Defaults to the arrow cursor. - HCURSOR current_cursor_; - // The cursor rect set by Flutter. RECT cursor_rect_; diff --git a/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc b/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc index 8f0d6578fe8..6d4304d6e87 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_window_unittests.cc @@ -66,7 +66,6 @@ class MockFlutterWindow : public FlutterWindow { OnPointerLeave, (double, double, FlutterPointerDeviceKind, int32_t), (override)); - MOCK_METHOD(void, OnSetCursor, (), (override)); MOCK_METHOD(float, GetScrollOffsetMultiplier, (), (override)); MOCK_METHOD(float, GetDpiScale, (), (override)); MOCK_METHOD(void, UpdateCursorRect, (const Rect&), (override)); @@ -422,12 +421,5 @@ TEST_F(FlutterWindowTest, CachedLifecycleMessage) { EXPECT_TRUE(restored); } -TEST_F(FlutterWindowTest, UpdateCursor) { - FlutterWindow win32window(100, 100); - win32window.UpdateFlutterCursor("text"); - HCURSOR cursor = ::GetCursor(); - EXPECT_EQ(cursor, ::LoadCursor(nullptr, IDC_IBEAM)); -} - } // namespace testing } // namespace flutter diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc index e8033bd098c..42667d00503 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.cc @@ -801,6 +801,44 @@ void FlutterWindowsEngine::SetNextFrameCallback(fml::closure callback) { this); } +HCURSOR FlutterWindowsEngine::GetCursorByName( + const std::string& cursor_name) const { + static auto* cursors = new std::map{ + {"allScroll", IDC_SIZEALL}, + {"basic", IDC_ARROW}, + {"click", IDC_HAND}, + {"forbidden", IDC_NO}, + {"help", IDC_HELP}, + {"move", IDC_SIZEALL}, + {"none", nullptr}, + {"noDrop", IDC_NO}, + {"precise", IDC_CROSS}, + {"progress", IDC_APPSTARTING}, + {"text", IDC_IBEAM}, + {"resizeColumn", IDC_SIZEWE}, + {"resizeDown", IDC_SIZENS}, + {"resizeDownLeft", IDC_SIZENESW}, + {"resizeDownRight", IDC_SIZENWSE}, + {"resizeLeft", IDC_SIZEWE}, + {"resizeLeftRight", IDC_SIZEWE}, + {"resizeRight", IDC_SIZEWE}, + {"resizeRow", IDC_SIZENS}, + {"resizeUp", IDC_SIZENS}, + {"resizeUpDown", IDC_SIZENS}, + {"resizeUpLeft", IDC_SIZENWSE}, + {"resizeUpRight", IDC_SIZENESW}, + {"resizeUpLeftDownRight", IDC_SIZENWSE}, + {"resizeUpRightDownLeft", IDC_SIZENESW}, + {"wait", IDC_WAIT}, + }; + const wchar_t* idc_name = IDC_ARROW; + auto it = cursors->find(cursor_name); + if (it != cursors->end()) { + idc_name = it->second; + } + return windows_proc_table_->LoadCursor(nullptr, idc_name); +} + void FlutterWindowsEngine::SendSystemLocales() { std::vector languages = GetPreferredLanguageInfo(*windows_proc_table_); @@ -995,6 +1033,15 @@ std::optional FlutterWindowsEngine::ProcessExternalWindowMessage( return std::nullopt; } +void FlutterWindowsEngine::UpdateFlutterCursor( + const std::string& cursor_name) const { + SetFlutterCursor(GetCursorByName(cursor_name)); +} + +void FlutterWindowsEngine::SetFlutterCursor(HCURSOR cursor) const { + windows_proc_table_->SetCursor(cursor); +} + void FlutterWindowsEngine::OnChannelUpdate(std::string name, bool listening) { if (name == "flutter/platform" && listening) { lifecycle_manager_->BeginProcessingExit(); diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h index 739912d943c..c4e590023cc 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_engine.h @@ -307,6 +307,13 @@ class FlutterWindowsEngine { return windows_proc_table_; } + // Sets the cursor that should be used when the mouse is over the Flutter + // content. See mouse_cursor.dart for the values and meanings of cursor_name. + void UpdateFlutterCursor(const std::string& cursor_name) const; + + // Sets the cursor directly from a cursor handle. + void SetFlutterCursor(HCURSOR cursor) const; + protected: // Creates the keyboard key handler. // @@ -341,6 +348,14 @@ class FlutterWindowsEngine { // Allows swapping out embedder_api_ calls in tests. friend class EngineModifier; + // Maps a Flutter cursor name to an HCURSOR. + // + // Returns the arrow cursor for unknown constants. + // + // This map must be kept in sync with Flutter framework's + // services/mouse_cursor.dart. + HCURSOR GetCursorByName(const std::string& cursor_name) const; + // Sends system locales to the engine. // // Should be called just after the engine is run, and after any relevant diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc index 7a990048916..a4f7523bad2 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.cc @@ -176,14 +176,6 @@ bool FlutterWindowsView::OnFrameGenerated(size_t width, size_t height) { return true; } -void FlutterWindowsView::UpdateFlutterCursor(const std::string& cursor_name) { - binding_handler_->UpdateFlutterCursor(cursor_name); -} - -void FlutterWindowsView::SetFlutterCursor(HCURSOR cursor) { - binding_handler_->SetFlutterCursor(cursor); -} - void FlutterWindowsView::ForceRedraw() { if (resize_status_ == ResizeState::kDone) { // Request new frame. diff --git a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h index 98689daee28..66ab0f0f0a4 100644 --- a/engine/src/flutter/shell/platform/windows/flutter_windows_view.h +++ b/engine/src/flutter/shell/platform/windows/flutter_windows_view.h @@ -125,13 +125,6 @@ class FlutterWindowsView : public WindowBindingHandlerDelegate { // This completes a view resize if one is pending. virtual void OnFramePresented(); - // Sets the cursor that should be used when the mouse is over the Flutter - // content. See mouse_cursor.dart for the values and meanings of cursor_name. - void UpdateFlutterCursor(const std::string& cursor_name); - - // Sets the cursor directly from a cursor handle. - void SetFlutterCursor(HCURSOR cursor); - // |WindowBindingHandlerDelegate| bool OnWindowSizeChanged(size_t width, size_t height) override; diff --git a/engine/src/flutter/shell/platform/windows/testing/mock_window.h b/engine/src/flutter/shell/platform/windows/testing/mock_window.h index d62601c619f..4a1007840ba 100644 --- a/engine/src/flutter/shell/platform/windows/testing/mock_window.h +++ b/engine/src/flutter/shell/platform/windows/testing/mock_window.h @@ -54,7 +54,6 @@ class MockWindow : public FlutterWindow { OnPointerLeave, (double, double, FlutterPointerDeviceKind, int32_t), (override)); - MOCK_METHOD(void, OnSetCursor, (), (override)); MOCK_METHOD(void, OnText, (const std::u16string&), (override)); MOCK_METHOD(void, OnKey, diff --git a/engine/src/flutter/shell/platform/windows/testing/mock_window_binding_handler.h b/engine/src/flutter/shell/platform/windows/testing/mock_window_binding_handler.h index 95244285004..dcb6b50d8d4 100644 --- a/engine/src/flutter/shell/platform/windows/testing/mock_window_binding_handler.h +++ b/engine/src/flutter/shell/platform/windows/testing/mock_window_binding_handler.h @@ -23,11 +23,6 @@ class MockWindowBindingHandler : public WindowBindingHandler { MOCK_METHOD(HWND, GetWindowHandle, (), (override)); MOCK_METHOD(float, GetDpiScale, (), (override)); MOCK_METHOD(PhysicalWindowBounds, GetPhysicalWindowBounds, (), (override)); - MOCK_METHOD(void, - UpdateFlutterCursor, - (const std::string& cursor_name), - (override)); - MOCK_METHOD(void, SetFlutterCursor, (HCURSOR cursor_name), (override)); MOCK_METHOD(void, OnCursorRectUpdated, (const Rect& rect), (override)); MOCK_METHOD(void, OnResetImeComposing, (), (override)); MOCK_METHOD(bool, OnBitmapSurfaceCleared, (), (override)); diff --git a/engine/src/flutter/shell/platform/windows/testing/mock_windows_proc_table.h b/engine/src/flutter/shell/platform/windows/testing/mock_windows_proc_table.h index 0d79e67c8e4..f7e47b9f603 100644 --- a/engine/src/flutter/shell/platform/windows/testing/mock_windows_proc_table.h +++ b/engine/src/flutter/shell/platform/windows/testing/mock_windows_proc_table.h @@ -34,6 +34,13 @@ class MockWindowsProcTable : public WindowsProcTable { MOCK_METHOD(HRESULT, DwmFlush, (), (const, override)); + MOCK_METHOD(HCURSOR, + LoadCursor, + (HINSTANCE instance, LPCWSTR cursor_name), + (const, override)); + + MOCK_METHOD(HCURSOR, SetCursor, (HCURSOR cursor), (const, override)); + private: FML_DISALLOW_COPY_AND_ASSIGN(MockWindowsProcTable); }; diff --git a/engine/src/flutter/shell/platform/windows/window_binding_handler.h b/engine/src/flutter/shell/platform/windows/window_binding_handler.h index bfd24e08713..90fa690ad39 100644 --- a/engine/src/flutter/shell/platform/windows/window_binding_handler.h +++ b/engine/src/flutter/shell/platform/windows/window_binding_handler.h @@ -54,13 +54,6 @@ class WindowBindingHandler { // Returns the bounds of the backing window in physical pixels. virtual PhysicalWindowBounds GetPhysicalWindowBounds() = 0; - // Sets the cursor that should be used when the mouse is over the Flutter - // content. See mouse_cursor.dart for the values and meanings of cursor_name. - virtual void UpdateFlutterCursor(const std::string& cursor_name) = 0; - - // Sets the cursor directly from a cursor handle. - virtual void SetFlutterCursor(HCURSOR cursor) = 0; - // Invoked when the cursor/composing rect has been updated in the framework. virtual void OnCursorRectUpdated(const Rect& rect) = 0; diff --git a/engine/src/flutter/shell/platform/windows/windows_proc_table.cc b/engine/src/flutter/shell/platform/windows/windows_proc_table.cc index 663faaa73e7..2cb8e26fc1c 100644 --- a/engine/src/flutter/shell/platform/windows/windows_proc_table.cc +++ b/engine/src/flutter/shell/platform/windows/windows_proc_table.cc @@ -58,4 +58,13 @@ HRESULT WindowsProcTable::DwmFlush() const { return ::DwmFlush(); } +HCURSOR WindowsProcTable::LoadCursor(HINSTANCE instance, + LPCWSTR cursor_name) const { + return ::LoadCursorW(instance, cursor_name); +} + +HCURSOR WindowsProcTable::SetCursor(HCURSOR cursor) const { + return ::SetCursor(cursor); +} + } // namespace flutter diff --git a/engine/src/flutter/shell/platform/windows/windows_proc_table.h b/engine/src/flutter/shell/platform/windows/windows_proc_table.h index ed0ed04ae6d..dd1190a7f24 100644 --- a/engine/src/flutter/shell/platform/windows/windows_proc_table.h +++ b/engine/src/flutter/shell/platform/windows/windows_proc_table.h @@ -57,6 +57,19 @@ class WindowsProcTable { // https://learn.microsoft.com/windows/win32/api/dwmapi/nf-dwmapi-dwmflush virtual HRESULT DwmFlush() const; + // Loads the specified cursor resource from the executable (.exe) file + // associated with an application instance. + // + // See: + // https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-loadcursorw + virtual HCURSOR LoadCursor(HINSTANCE instance, LPCWSTR cursor_name) const; + + // Sets the cursor shape. + // + // See: + // https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-setcursor + virtual HCURSOR SetCursor(HCURSOR cursor) const; + private: using GetPointerType_ = BOOL __stdcall(UINT32 pointerId, POINTER_INPUT_TYPE* pointerType); diff --git a/packages/flutter/lib/src/services/mouse_cursor.dart b/packages/flutter/lib/src/services/mouse_cursor.dart index 09fd6beb943..bfccef85dce 100644 --- a/packages/flutter/lib/src/services/mouse_cursor.dart +++ b/packages/flutter/lib/src/services/mouse_cursor.dart @@ -408,8 +408,7 @@ abstract final class SystemMouseCursors { // // * Android: shell/platform/android/io/flutter/plugin/mouse/MouseCursorPlugin.java // * Web: lib/web_ui/lib/src/engine/mouse_cursor.dart - // * Windows: shell/platform/windows/win32_flutter_window_win32.cc - // * Windows UWP: shell/platform/windows/win32_flutter_window_winuwp.cc + // * Windows: shell/platform/windows/flutter_windows_engine.cc // * Linux: shell/platform/linux/fl_mouse_cursor_plugin.cc // * macOS: shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm