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
|
return _methodChannel
|
||||||
.invokeMethod('setSize', [size.width, size.height, scaleFactor]);
|
.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 {
|
class CustomPlatformView extends StatefulWidget {
|
||||||
|
@ -273,8 +283,11 @@ class _CustomPlatformViewState extends State<CustomPlatformView> {
|
||||||
},
|
},
|
||||||
arguments: widget.creationParams);
|
arguments: widget.creationParams);
|
||||||
|
|
||||||
// Report initial surface size
|
// Report initial surface size and widget position
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) => _reportSurfaceSize());
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
_reportSurfaceSize();
|
||||||
|
_reportWidgetPosition();
|
||||||
|
});
|
||||||
|
|
||||||
_cursorSubscription = _controller._cursor.listen((cursor) {
|
_cursorSubscription = _controller._cursor.listen((cursor) {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
@ -301,6 +314,7 @@ class _CustomPlatformViewState extends State<CustomPlatformView> {
|
||||||
return NotificationListener<SizeChangedLayoutNotification>(
|
return NotificationListener<SizeChangedLayoutNotification>(
|
||||||
onNotification: (notification) {
|
onNotification: (notification) {
|
||||||
_reportSurfaceSize();
|
_reportSurfaceSize();
|
||||||
|
_reportWidgetPosition();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
child: SizeChangedLayoutNotifier(
|
child: SizeChangedLayoutNotifier(
|
||||||
|
@ -316,6 +330,9 @@ class _CustomPlatformViewState extends State<CustomPlatformView> {
|
||||||
_controller._setCursorPos(ev.localPosition);
|
_controller._setCursorPos(ev.localPosition);
|
||||||
},
|
},
|
||||||
onPointerDown: (ev) {
|
onPointerDown: (ev) {
|
||||||
|
_reportSurfaceSize();
|
||||||
|
_reportWidgetPosition();
|
||||||
|
|
||||||
if (!_focusNode.hasFocus) {
|
if (!_focusNode.hasFocus) {
|
||||||
_focusNode.requestFocus();
|
_focusNode.requestFocus();
|
||||||
Future.delayed(const Duration(milliseconds: 50), () {
|
Future.delayed(const Duration(milliseconds: 50), () {
|
||||||
|
@ -401,6 +418,17 @@ class _CustomPlatformViewState extends State<CustomPlatformView> {
|
||||||
await _controller.ready;
|
await _controller.ready;
|
||||||
unawaited(_controller._setSize(
|
unawaited(_controller._setSize(
|
||||||
box.size, widget.scaleFactor ?? window.devicePixelRatio));
|
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 kErrorInvalidArgs = "invalidArguments";
|
||||||
|
|
||||||
constexpr auto kMethodSetSize = "setSize";
|
constexpr auto kMethodSetSize = "setSize";
|
||||||
|
constexpr auto kMethodSetPosition = "setPosition";
|
||||||
constexpr auto kMethodSetCursorPos = "setCursorPos";
|
constexpr auto kMethodSetCursorPos = "setCursorPos";
|
||||||
constexpr auto kMethodSetPointerUpdate = "setPointerUpdate";
|
constexpr auto kMethodSetPointerUpdate = "setPointerUpdate";
|
||||||
constexpr auto kMethodSetPointerButton = "setPointerButton";
|
constexpr auto kMethodSetPointerButton = "setPointerButton";
|
||||||
|
@ -299,8 +300,20 @@ namespace flutter_inappwebview_plugin
|
||||||
}
|
}
|
||||||
return result->Error(kErrorInvalidArgs);
|
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())) {
|
if (const auto value = std::get_if<int32_t>(method_call.arguments())) {
|
||||||
texture_bridge_->SetFpsLimit(*value == 0 ? std::nullopt
|
texture_bridge_->SetFpsLimit(*value == 0 ? std::nullopt
|
||||||
: std::make_optional(*value));
|
: std::make_optional(*value));
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "../utils/strconv.h"
|
#include "../utils/strconv.h"
|
||||||
#include "../utils/string.h"
|
#include "../utils/string.h"
|
||||||
#include "in_app_webview.h"
|
#include "in_app_webview.h"
|
||||||
|
|
||||||
#include "in_app_webview_manager.h"
|
#include "in_app_webview_manager.h"
|
||||||
|
|
||||||
namespace flutter_inappwebview_plugin
|
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)
|
void InAppWebView::setCursorPos(double x, double y)
|
||||||
{
|
{
|
||||||
if (!webViewCompositionController) {
|
if (!webViewCompositionController) {
|
||||||
|
@ -999,92 +1032,16 @@ namespace flutter_inappwebview_plugin
|
||||||
|
|
||||||
auto offset = static_cast<short>(delta * kScrollMultiplier);
|
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) {
|
if (horizontal) {
|
||||||
webViewCompositionController->SendMouseInput(
|
webViewCompositionController->SendMouseInput(
|
||||||
COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, virtual_keys_.state(),
|
COREWEBVIEW2_MOUSE_EVENT_KIND_HORIZONTAL_WHEEL, virtualKeys_.state(),
|
||||||
offset, point);
|
offset, lastCursorPos_);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
webViewCompositionController->SendMouseInput(COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL,
|
webViewCompositionController->SendMouseInput(COREWEBVIEW2_MOUSE_EVENT_KIND_WHEEL,
|
||||||
virtual_keys_.state(), offset,
|
virtualKeys_.state(), offset,
|
||||||
point);
|
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)
|
void InAppWebView::setScrollDelta(double delta_x, double delta_y)
|
||||||
|
|
|
@ -112,6 +112,7 @@ namespace flutter_inappwebview_plugin
|
||||||
return surface_.get();
|
return surface_.get();
|
||||||
}
|
}
|
||||||
void setSurfaceSize(size_t width, size_t height, float scale_factor);
|
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 setCursorPos(double x, double y);
|
||||||
void setPointerUpdate(int32_t pointer, InAppWebViewPointerEventKind eventKind,
|
void setPointerUpdate(int32_t pointer, InAppWebViewPointerEventKind eventKind,
|
||||||
double x, double y, double size, double pressure);
|
double x, double y, double size, double pressure);
|
||||||
|
|
|
@ -56,7 +56,7 @@ namespace flutter_inappwebview_plugin
|
||||||
|
|
||||||
if (string_equals(methodName, "createInAppWebView")) {
|
if (string_equals(methodName, "createInAppWebView")) {
|
||||||
if (isSupported()) {
|
if (isSupported()) {
|
||||||
createInAppBrowser(arguments, std::move(result));
|
createInAppWebView(arguments, std::move(result));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
result->Error("0", "Creating an InAppWebView instance is not supported! Graphics Context is not valid!");
|
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));
|
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 initialDataMap = get_optional_fl_map_value<flutter::EncodableMap>(*arguments, "initialData");
|
||||||
auto initialUserScriptList = get_optional_fl_map_value<flutter::EncodableList>(*arguments, "initialUserScripts");
|
auto initialUserScriptList = get_optional_fl_map_value<flutter::EncodableList>(*arguments, "initialUserScripts");
|
||||||
|
|
||||||
auto hwnd = CreateWindowEx(0, windowClass_.lpszClassName, L"", 0, CW_DEFAULT,
|
RECT bounds;
|
||||||
CW_DEFAULT, 0, 0, HWND_MESSAGE, nullptr,
|
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);
|
windowClass_.hInstance, nullptr);
|
||||||
|
|
||||||
InAppWebView::createInAppWebViewEnv(hwnd, true,
|
InAppWebView::createInAppWebViewEnv(hwnd, true,
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace flutter_inappwebview_plugin
|
||||||
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
const flutter::MethodCall<flutter::EncodableValue>& method_call,
|
||||||
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result);
|
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:
|
private:
|
||||||
std::unique_ptr<rx::RoHelper> rohelper_;
|
std::unique_ptr<rx::RoHelper> rohelper_;
|
||||||
winrt::com_ptr<ABI::Windows::System::IDispatcherQueueController>
|
winrt::com_ptr<ABI::Windows::System::IDispatcherQueueController>
|
||||||
|
|
Loading…
Reference in New Issue