windows: fixed custom platform view context menu and window position
This commit is contained in:
parent
ed6283d3b3
commit
e4bfd68313
|
@ -220,6 +220,16 @@ class CustomPlatformViewController
|
|||
return _methodChannel
|
||||
.invokeMethod('setSize', [size.width, size.height, scaleFactor]);
|
||||
}
|
||||
|
||||
/// Sets the surface size to the provided [size].
|
||||
Future<void> _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<CustomPlatformView> {
|
|||
},
|
||||
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<CustomPlatformView> {
|
|||
return NotificationListener<SizeChangedLayoutNotification>(
|
||||
onNotification: (notification) {
|
||||
_reportSurfaceSize();
|
||||
_reportWidgetPosition();
|
||||
return true;
|
||||
},
|
||||
child: SizeChangedLayoutNotifier(
|
||||
|
@ -316,6 +330,9 @@ class _CustomPlatformViewState extends State<CustomPlatformView> {
|
|||
_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<CustomPlatformView> {
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<size_t>(x),
|
||||
static_cast<size_t>(y),
|
||||
static_cast<float>(scale_factor));
|
||||
|
||||
return result->Success();
|
||||
}
|
||||
return result->Error(kErrorInvalidArgs);
|
||||
}
|
||||
else if (method_name.compare(kMethodSetFpsLimit) == 0) {
|
||||
if (const auto value = std::get_if<int32_t>(method_call.arguments())) {
|
||||
texture_bridge_->SetFpsLimit(*value == 0 ? std::nullopt
|
||||
: std::make_optional(*value));
|
||||
|
|
|
@ -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<int>(x * scale_factor);
|
||||
auto scaled_y = static_cast<int>(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<int>(flutterWindowRect.left + scaled_x - borderWidth),
|
||||
static_cast<int>(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<short>(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<ICoreWebView2ExecuteScriptCompletedHandler>(
|
||||
[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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<flutter::MethodResult<flutter::EncodableValue>> result)
|
||||
void InAppWebViewManager::createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result)
|
||||
{
|
||||
auto result_ = std::shared_ptr<flutter::MethodResult<flutter::EncodableValue>>(std::move(result));
|
||||
|
||||
|
@ -84,8 +84,13 @@ namespace flutter_inappwebview_plugin
|
|||
auto initialDataMap = get_optional_fl_map_value<flutter::EncodableMap>(*arguments, "initialData");
|
||||
auto initialUserScriptList = get_optional_fl_map_value<flutter::EncodableList>(*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,
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace flutter_inappwebview_plugin
|
|||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
|
||||
void createInAppBrowser(const flutter::EncodableMap* arguments, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
void createInAppWebView(const flutter::EncodableMap* arguments, std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
||||
private:
|
||||
std::unique_ptr<rx::RoHelper> rohelper_;
|
||||
winrt::com_ptr<ABI::Windows::System::IDispatcherQueueController>
|
||||
|
|
Loading…
Reference in New Issue