diff --git a/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart b/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart index 1f41ab12..8a302954 100644 --- a/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart +++ b/flutter_inappwebview_windows/lib/src/in_app_webview/custom_platform_view.dart @@ -220,6 +220,16 @@ class CustomPlatformViewController return _methodChannel .invokeMethod('setSize', [size.width, size.height, scaleFactor]); } + + /// Sets the surface size to the provided [size]. + Future _setPosition(Offset position, double scaleFactor) async { + if (_isDisposed) { + return; + } + assert(value.isInitialized); + return _methodChannel + .invokeMethod('setPosition', [position.dx, position.dy, scaleFactor]); + } } class CustomPlatformView extends StatefulWidget { @@ -273,8 +283,11 @@ class _CustomPlatformViewState extends State { }, arguments: widget.creationParams); - // Report initial surface size - WidgetsBinding.instance.addPostFrameCallback((_) => _reportSurfaceSize()); + // Report initial surface size and widget position + WidgetsBinding.instance.addPostFrameCallback((_) { + _reportSurfaceSize(); + _reportWidgetPosition(); + }); _cursorSubscription = _controller._cursor.listen((cursor) { setState(() { @@ -301,6 +314,7 @@ class _CustomPlatformViewState extends State { return NotificationListener( onNotification: (notification) { _reportSurfaceSize(); + _reportWidgetPosition(); return true; }, child: SizeChangedLayoutNotifier( @@ -316,6 +330,9 @@ class _CustomPlatformViewState extends State { _controller._setCursorPos(ev.localPosition); }, onPointerDown: (ev) { + _reportSurfaceSize(); + _reportWidgetPosition(); + if (!_focusNode.hasFocus) { _focusNode.requestFocus(); Future.delayed(const Duration(milliseconds: 50), () { @@ -401,6 +418,17 @@ class _CustomPlatformViewState extends State { await _controller.ready; unawaited(_controller._setSize( box.size, widget.scaleFactor ?? window.devicePixelRatio)); + + } + } + + void _reportWidgetPosition() async { + final box = _key.currentContext?.findRenderObject() as RenderBox?; + if (box != null) { + await _controller.ready; + final position = box.localToGlobal(Offset.zero); + unawaited(_controller._setPosition( + position, widget.scaleFactor ?? window.devicePixelRatio)); } } diff --git a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc index 34579e12..c955f87d 100644 --- a/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc +++ b/flutter_inappwebview_windows/windows/custom_platform_view/custom_platform_view.cc @@ -15,6 +15,7 @@ namespace flutter_inappwebview_plugin constexpr auto kErrorInvalidArgs = "invalidArguments"; constexpr auto kMethodSetSize = "setSize"; + constexpr auto kMethodSetPosition = "setPosition"; constexpr auto kMethodSetCursorPos = "setCursorPos"; constexpr auto kMethodSetPointerUpdate = "setPointerUpdate"; constexpr auto kMethodSetPointerButton = "setPointerButton"; @@ -299,8 +300,20 @@ namespace flutter_inappwebview_plugin } return result->Error(kErrorInvalidArgs); } + else if (method_name.compare(kMethodSetPosition) == 0) { + auto position = GetPointAndScaleFactorFromArgs(method_call.arguments()); + if (position && view) { + const auto [x, y, scale_factor] = position.value(); - if (method_name.compare(kMethodSetFpsLimit) == 0) { + view->setPosition(static_cast(x), + static_cast(y), + static_cast(scale_factor)); + + return result->Success(); + } + return result->Error(kErrorInvalidArgs); + } + else if (method_name.compare(kMethodSetFpsLimit) == 0) { if (const auto value = std::get_if(method_call.arguments())) { texture_bridge_->SetFpsLimit(*value == 0 ? std::nullopt : std::make_optional(*value)); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp index e494c6a8..034b573d 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.cpp @@ -14,6 +14,7 @@ #include "../utils/strconv.h" #include "../utils/string.h" #include "in_app_webview.h" + #include "in_app_webview_manager.h" namespace flutter_inappwebview_plugin @@ -872,6 +873,38 @@ namespace flutter_inappwebview_plugin } } + + void InAppWebView::setPosition(size_t x, size_t y, float scale_factor) + { + if (!webViewController || !plugin || !plugin->registrar) { + return; + } + + if (x >= 0 && y >= 0) { + scaleFactor_ = scale_factor; + auto scaled_x = static_cast(x * scale_factor); + auto scaled_y = static_cast(y * scale_factor); + + auto titleBarHeight = ((GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME)) * scale_factor) + GetSystemMetrics(SM_CXPADDEDBORDER); + auto borderWidth = (GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXPADDEDBORDER)) * scale_factor; + + RECT flutterWindowRect; + HWND flutterWindowHWnd = plugin->registrar->GetView()->GetNativeWindow(); + GetWindowRect(flutterWindowHWnd, &flutterWindowRect); + + HWND webViewHWnd; + if (succeededOrLog(webViewController->get_ParentWindow(&webViewHWnd))) { + ::SetWindowPos(webViewHWnd, + nullptr, + static_cast(flutterWindowRect.left + scaled_x - borderWidth), + static_cast(flutterWindowRect.top + scaled_y - titleBarHeight), + 0, 0, + SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + } + } + } + + void InAppWebView::setCursorPos(double x, double y) { if (!webViewCompositionController) { @@ -999,92 +1032,16 @@ namespace flutter_inappwebview_plugin auto offset = static_cast(delta * kScrollMultiplier); - /* - // For some reason, - // setting the point other than (x: 0, y: 0) - // will not make the scroll work. - // Unfortunately, this will break the scroll event - // for nested HTML scrollable elements. - POINT point; - point.x = 0; - point.y = 0; - - if (horizontal) { webViewCompositionController->SendMouseInput( - COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, virtual_keys_.state(), - offset, point); + COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, virtualKeys_.state(), + offset, lastCursorPos_); } else { webViewCompositionController->SendMouseInput(COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL, - virtual_keys_.state(), offset, - point); + virtualKeys_.state(), offset, + lastCursorPos_); } - */ - - // Workaround for scroll events - auto workaroundScrollJS = "(function(horizontal, offset, x, y) { \ - function elemCanScrollY(elem) { \ - if (elem.scrollTop > 0) { \ - return elem; \ - } else { \ - elem.scrollTop++; \ - const top = elem.scrollTop; \ - top && (elem.scrollTop = 0); \ - if (top > 0) { \ - return elem; \ - } else { \ - return elemCanScrollY(elem.parentElement); \ - } \ - } \ - } \ - function elemCanScrollX(elem) { \ - if (elem.scrollLeft > 0) { \ - return elem; \ - } else { \ - elem.scrollLeft++; \ - const left = elem.scrollLeft; \ - left && (elem.scrollLeft = 0); \ - if (left > 0) { \ - return elem; \ - } else { \ - return elemCanScrollX(elem.parentElement); \ - } \ - } \ - } \ - const elem = document.elementFromPoint(x, y); \ - const elem2 = horizontal ? elemCanScrollX(elem) : elemCanScrollY(elem); \ - const handled = elem2 != null && elem2 != document.documentElement && elem2 != document.body; \ - if (handled) { \ - elem2.scrollBy({left: horizontal ? offset : 0, top: horizontal ? 0 : offset}); \ - } \ - return handled; \ -})(" + std::to_string(horizontal) + ", " + std::to_string(offset) + ", " + std::to_string(lastCursorPos_.x) + ", " + std::to_string(lastCursorPos_.y) + ");"; - - webView->ExecuteScript(utf8_to_wide(workaroundScrollJS).c_str(), Callback( - [this, horizontal, offset](HRESULT error, PCWSTR result) -> HRESULT - { - if (webViewCompositionController && (error != S_OK || wide_to_utf8(result).compare("false") == 0)) { - // try to use native mouse wheel handler - - POINT point; - point.x = 0; - point.y = 0; - - if (horizontal) { - webViewCompositionController->SendMouseInput( - COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, virtualKeys_.state(), - offset, point); - } - else { - webViewCompositionController->SendMouseInput(COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL, - virtualKeys_.state(), offset, - point); - } - } - - return S_OK; - }).Get()); } void InAppWebView::setScrollDelta(double delta_x, double delta_y) diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h index c1645cbb..d5daa5e4 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview.h @@ -112,6 +112,7 @@ namespace flutter_inappwebview_plugin return surface_.get(); } void setSurfaceSize(size_t width, size_t height, float scale_factor); + void setPosition(size_t x, size_t y, float scale_factor); void setCursorPos(double x, double y); void setPointerUpdate(int32_t pointer, InAppWebViewPointerEventKind eventKind, double x, double y, double size, double pressure); diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp index 44cbe303..c1ef879c 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.cpp @@ -56,7 +56,7 @@ namespace flutter_inappwebview_plugin if (string_equals(methodName, "createInAppWebView")) { if (isSupported()) { - createInAppBrowser(arguments, std::move(result)); + createInAppWebView(arguments, std::move(result)); } else { result->Error("0", "Creating an InAppWebView instance is not supported! Graphics Context is not valid!"); @@ -74,7 +74,7 @@ namespace flutter_inappwebview_plugin } } - void InAppWebViewManager::createInAppBrowser(const flutter::EncodableMap* arguments, std::unique_ptr> result) + void InAppWebViewManager::createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr> result) { auto result_ = std::shared_ptr>(std::move(result)); @@ -84,8 +84,13 @@ namespace flutter_inappwebview_plugin auto initialDataMap = get_optional_fl_map_value(*arguments, "initialData"); auto initialUserScriptList = get_optional_fl_map_value(*arguments, "initialUserScripts"); - auto hwnd = CreateWindowEx(0, windowClass_.lpszClassName, L"", 0, CW_DEFAULT, - CW_DEFAULT, 0, 0, HWND_MESSAGE, nullptr, + RECT bounds; + GetClientRect(plugin->registrar->GetView()->GetNativeWindow(), &bounds); + + auto hwnd = CreateWindowEx(0, windowClass_.lpszClassName, L"", 0, 0, + 0, bounds.right - bounds.left, bounds.bottom - bounds.top, + plugin->registrar->GetView()->GetNativeWindow(), // HWND_MESSAGE, + nullptr, windowClass_.hInstance, nullptr); InAppWebView::createInAppWebViewEnv(hwnd, true, diff --git a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h index 5d89e9cc..8630ceeb 100644 --- a/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h +++ b/flutter_inappwebview_windows/windows/in_app_webview/in_app_webview_manager.h @@ -44,7 +44,7 @@ namespace flutter_inappwebview_plugin const flutter::MethodCall& method_call, std::unique_ptr> result); - void createInAppBrowser(const flutter::EncodableMap* arguments, std::unique_ptr> result); + void createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr> result); private: std::unique_ptr rohelper_; winrt::com_ptr