flutter-webview-windows
flutter-webview-windows copied to clipboard
Can not open keyboard when using touch screen
I make a app run on Windows 10. when I click on input form in the webview. keyboard is showing and close right away. Anyone face same issue
Yes, we are facing the same issue.
Yes, we are facing the same issue.
@gmuehlenberg Can you fix it, I only face issue in touch device
We're facing the the same sort of issue on touch devices: -we're not able to focus input/textarea fields -the targeted element is active (check via document.activeElement) but the cursor doesn't appear and the keyboard doesn't pop up -with the mouse it works, but not with the touch We have found a workaround --> the user touches the input/textarea for more than 1-2 seconds and then the focus & cursor are set to the field. On desktop works perfectly.
terms: flutter app -> the flutter window, where the app is running webview -> the webview widget inside the flutter app
I noticed that for a very brief moment the webview gets the focus but immediately loses it to the parent/flutter app right after the touch input. This must be the reason why it does not work, but i could not look deeper into it yet.
@jnschulze you have any idea how to "not lose" the focus of the webview when tapping with a touch input?
@jnschulze maybe it has to do with this handling? I'm new to this, but I found it here:
File:
webview.cc
https://github.com/jnschulze/flutter-webview-windows/blob/main/windows/webview.cc
composition_controller_->add_CursorChanged(
Callback<ICoreWebView2CursorChangedEventHandler>(
[this](ICoreWebView2CompositionController* sender,
IUnknown* args) -> HRESULT {
HCURSOR cursor;
if (cursor_changed_callback_ &&
sender->get_Cursor(&cursor) == S_OK) {
cursor_changed_callback_(cursor);
}
return S_OK;
})
.Get(),
&event_registrations_.cursor_changed_token_);
webview_controller_->add_GotFocus(
Callback<ICoreWebView2FocusChangedEventHandler>(
[this](ICoreWebView2Controller* sender, IUnknown* args) -> HRESULT {
if (focus_changed_callback_) {
focus_changed_callback_(true);
}
return S_OK;
})
.Get(),
&event_registrations_.got_focus_token_);
webview_controller_->add_LostFocus(
Callback<ICoreWebView2FocusChangedEventHandler>(
[this](ICoreWebView2Controller* sender, IUnknown* args) -> HRESULT {
if (focus_changed_callback_) {
focus_changed_callback_(false);
}
return S_OK;
})
.Get(),
&event_registrations_.lost_focus_token_);
Hm, my guess is that some e.g. touchUp
-Event might bubble up to the flutter parent window. @jnschulze the touchDown
-Event seems to work perfectly. I need to take a closer look but might this be the cause?
Another point of interest:
webview.cc
line 515++
host_->CreateWebViewPointerInfo(
[this, pointer, event, pointerFlags, point, rect, pressure](
wil::com_ptr<ICoreWebView2PointerInfo> pointerInfo,
std::unique_ptr<WebviewCreationError> error) {
if (pointerInfo) {
ICoreWebView2PointerInfo* pInfo = pointerInfo.get();
pInfo->put_PointerId(pointer);
pInfo->put_PointerKind(PT_TOUCH);
pInfo->put_PointerFlags(pointerFlags);
pInfo->put_TouchFlags(TOUCH_FLAG_NONE);
pInfo->put_TouchMask(TOUCH_MASK_CONTACTAREA | TOUCH_MASK_PRESSURE);
pInfo->put_TouchPressure(
std::clamp((UINT32)(pressure == 0.0 ? 1024 : 1024 * pressure),
(UINT32)0, (UINT32)1024));
pInfo->put_PixelLocationRaw(point);
pInfo->put_TouchContactRaw(rect);
composition_controller_->SendPointerInput(event, pInfo);
}
});
}
Here's a very plain workaround-widget for the issue.
Keep in mind that this should be seen as a workaround hack
and not as a solution.
Usage:
WebviewTouchWrapper(
child: Webview(ctrl),
),
webview_touch_wrapper.dart
(copy or create own file)
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class WebviewTouchWrapper extends StatelessWidget {
const WebviewTouchWrapper({required this.child, Key? key}) : super(key: key);
final Widget child;
static Offset oldPosition = Offset.zero;
void simulatePress(TapUpDetails details) {
const kind = PointerDeviceKind.touch;
final currentPosition = details.globalPosition;
if ((details.kind == kind) && (oldPosition != currentPosition)) {
oldPosition = currentPosition;
WidgetsBinding.instance.addPostFrameCallback((_) async {
try {
await Future.delayed(Duration(milliseconds: 36));
final tOffset = details.globalPosition;
GestureBinding.instance.handlePointerEvent(PointerMoveEvent(
position: tOffset,
kind: kind,
size: 70,
));
await Future.delayed(Duration(milliseconds: 36));
GestureBinding.instance.handlePointerEvent(PointerDownEvent(
position: tOffset,
kind: kind,
size: 70,
));
await Future.delayed(Duration(milliseconds: 36));
GestureBinding.instance.handlePointerEvent(PointerUpEvent(
position: tOffset,
kind: kind,
size: 70,
));
} catch (e, s) {
print(e);
print(s);
}
});
}
}
@override
Widget build(BuildContext context) => GestureDetector(
onTapUp: simulatePress,
child: child,
);
}
Here's a very plain workaround-widget for the issue. Keep in mind that this should be seen as a
workaround hack
and not as a solution.Usage:
WebviewTouchWrapper( child: Webview(ctrl), ),
webview_touch_wrapper.dart
(copy or create own file)import 'package:flutter/gestures.dart'; ...
@Eerey many thanks for this hack-like solution. We have tried this but after a while we noticed every tap/touch event ends with double tap/touch so that two events are forwarded to webview widget and then to the DOM where it causes various problems - e.g. open/close of UI components at the same time etc. Is there a way to make it work only on input/textarea elements? I think there is no way to know what exactly has been touched by webview event.
@maciola as you suggest I don't think that you're able to detect it beforehand. Please let us know if you find a good or better solution for it. Thanks for exploring my hacky solution!
@jnschulze any updates about this issue ?