flutter-webview-windows icon indicating copy to clipboard operation
flutter-webview-windows copied to clipboard

Can not open keyboard when using touch screen

Open dattran-pt19 opened this issue 1 year ago • 11 comments

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

dattran-pt19 avatar Aug 24 '22 08:08 dattran-pt19

Yes, we are facing the same issue.

gmuehlenberg avatar Sep 07 '22 13:09 gmuehlenberg

Yes, we are facing the same issue.

@gmuehlenberg Can you fix it, I only face issue in touch device

dattran-pt19 avatar Sep 12 '22 07:09 dattran-pt19

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.

maciola avatar Sep 29 '22 08:09 maciola

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?

Eerey avatar Oct 19 '22 13:10 Eerey

@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_);

Eerey avatar Oct 19 '22 13:10 Eerey

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?

Eerey avatar Oct 19 '22 16:10 Eerey

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);
        }
      });
}

Eerey avatar Oct 19 '22 19:10 Eerey

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,
      );
}

Eerey avatar Oct 20 '22 13:10 Eerey

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 avatar Dec 01 '22 10:12 maciola

@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!

Eerey avatar Dec 01 '22 12:12 Eerey

@jnschulze any updates about this issue ?

UnluckyY1 avatar Feb 19 '24 20:02 UnluckyY1