MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
440 stars 52 forks source link

Use touch to drag window #2243

Open hbl917070 opened 2 years ago

hbl917070 commented 2 years ago

I use webview2 to make the entire UI of the program, including the title bar of the window is also HTML. Electron can use --webkit-app-region: drag; in CSS, but webview2 does not support it.

https://github.com/MicrosoftEdge/WebView2Feedback/issues/200#issuecomment-633061172 I tried to use this method to implement window dragging, but this method only works with the mouse, and the touch screen will not respond.

Microsoft Teams on Windows 11 also uses webview2, I use a surface laptop 3 and I can't drag Microsoft Teams on the touch screen.

If possible, would like to be able to support CSS like --webkit-app-region: drag-top; so that the window can be resized.

AB#38450196

champnic commented 2 years ago

Thanks for the feature request @hbl917070! I've added this as a scenario on our backlog.

champnic commented 2 years ago

Looking at the solution in #200, it looks like they are only listening to the mousedown event. Can you try using pointerdown and other pointer events instead and see if that works for touch?

hbl917070 commented 2 years ago

JavaScript event pointerdown, touchstart, mousedown cannot drag the window under the touch screen.

I use it in C#

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool ReleaseCapture();

public const int WM_SYSCOMMAND = 0x0112;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);

public void Drag(){
    ReleaseCapture();
    SendMessage(handle, WM_SYSCOMMAND, (int)0xF009, 0);
}

In WPF or winForm, I can drag the window by calling Drag() in MouseDown. In webview2 or cef, I can use the mouse to trigger mousedown, thereby dragging the window. In webview2 or cef, I use touchscreen to trigger touchstart, and make sure Drag() is executed, but I can't drag the window.

This is just my guess. When Chromium receives a touch command, Chromium will intercept the touch command, so that touch does not hold for Windows systems.

champnic commented 2 years ago

Just to be clear, my suggestion was to change the code in #200 from this:

window.addEventListener('DOMContentLoaded', () => {
    document.body.addEventListener('mousedown', evt => {
        const { target } = evt;
        const appRegion = getComputedStyle(target)['-webkit-app-region'];

        if (appRegion === 'drag') {
            chrome.webview.hostObjects.sync.eventForwarder.MouseDownDrag();
            evt.preventDefault();
            evt.stopPropagation();
        }
    });
});

to this:

window.addEventListener('DOMContentLoaded', () => {
    document.body.addEventListener('pointerdown', evt => {
        const { target } = evt;
        const appRegion = getComputedStyle(target)['-webkit-app-region'];

        if (appRegion === 'drag') {
            chrome.webview.hostObjects.sync.eventForwarder.MouseDownDrag();
            evt.preventDefault();
            evt.stopPropagation();
        }
    });
});

By changing mousedown to pointerdown. I don't think anything else needs to change. Is that not working for you?

hbl917070 commented 2 years ago

Yes, after my testing, this doesn't work with touchscreens.

Under normal circumstances, when using touch on a touch screen, the mouse cursor will move with the touch.

But in the case of web page, using touch doesn't make the mouse cursor move, If the mouse coordinates have not changed, then the SendMessage of C# cannot drag the window.

https://youtu.be/ZIOraK74Png In the first 15 seconds of the video, touch in the webpage will not change the coordinates of the mouse. In the second half of the video, I dragged the title bar of the browser directly, and the mouse followed the touch.

champnic commented 2 years ago

Oh I see what you are saying. That's unfortunate, but good info for our scenario that there isn't a workaround available.

nishitha-burman commented 1 year ago

Hi @hbl917070,

Can you provide details on the customizations you are looking to do for resize regions?

Thanks!

hbl917070 commented 1 year ago

I hope that all UI of the program can be presented through WebView2, including the window title bar. But WebView2 can be embedded in WinForm, WPF, UWP… Therefore, the solution needed may be a new window object or a new C# project?

For example

WebView2Window window = new WebView2Window();
window.Style = WebView2WindowStyle.NoTitleBar;
window.Show();
WebView2 wv2 = window.Webview;
wv2.CoreWebView2.Navigate("https://www.bing.com");

WebView2Window is a window object that is similar to Form, except that it only contains one WebView2 object inside and can remove the window title bar. The window also supports full transparency. Then, following Electron’s approach, you can use CSS --webkit-app-region:drag to enable a DIV to drag the window.

champnic commented 1 year ago

You should now be able to use app-region: drag in window-hosted scenarios (Win32, .NET WPF/Winforms - NOT UWP or WinAppSDK yet), and have that work for touch as well. Can you give that a try and let me know if it's not working?

hbl917070 commented 1 year ago

I opened a new project to test it, and neither the mouse nor the touch can drag the window.

GIF 2023-3-1 上午 05-54-45

Project: net 4.7 WinForm OS: Windows 10 (19045.2673) WebView2 version: 1.0.1587.40 WebView2 userAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.57

C#

public partial class Form1 : Form {
    public Form1() {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e) {
        webView21.Source = new Uri("file:///C:/Users/u1/Desktop/moveTest.html");
    }
}

moveTest.html

<!DOCTYPE html>
<html>
<body>
    <style>
        #move {
            width: 300px;
            height: 300px;
            background-color: rgb(100, 200, 200);

            --app-region: drag;
            -app-region: drag;
            app-region: drag;
            --webkit-app-region: drag;
            -webkit-app-region: drag;
            webkit-app-region: drag;
        }
    </style>
    <div id="move"> </div>
</body>
</html>
champnic commented 1 year ago

@hbl917070 Sorry for the confusion - looks like it requires a flag to enable it currently. Can you try setting this additional browser argument? --enable-features=msWebView2EnableDraggableRegions

hbl917070 commented 1 year ago

It worked, mouse and touch can drag the window!

In addition, if there is a solution to drag the border to change the size of the window, then everything will be perfect.

C#

public partial class Form1 : Form {
        WebView2 webView21;

        public Form1() {
            InitializeComponent();
            this.FormBorderStyle = FormBorderStyle.None;
            InitWebview();
        }

        private async void InitWebview() {
            webView21 = new WebView2();
            this.Controls.Add(webView21);
            webView21.Dock = DockStyle.Fill;
            string arg = @"--enable-features=""msWebView2EnableDraggableRegions""";
            var opts = new CoreWebView2EnvironmentOptions { AdditionalBrowserArguments = arg };
            var webView2Environment = await CoreWebView2Environment.CreateAsync(null, null, opts);
            await webView21.EnsureCoreWebView2Async(webView2Environment);
            webView21.Source = new Uri("file:///C:/Users/u1/Desktop/moveTest.html");
        }
}

moveTest.html

<!DOCTYPE html>
<html>
<body>
    <style>
        #move {
            app-region: drag;
            width: 300px;
            height: 300px;
            background-color: rgb(100, 200, 200);
        }
    </style>
    <div id="move"></div>
</body>
</html>
nishitha-burman commented 1 year ago

Hi @hbl917070,

Glad that worked for you! Can you please expand on the ask to have support for dragging the border to change the size of the window? What properties are you looking to customize for the resize regions? The OS has non client area resize regions, is there a reason you are expanding your app to the OS's non client area in the left, right, bottom sides? Also, if WebView2 by default support the borders as resize regions, does that address your needs or are you looking to configure dimensions of the divs for the resize regions?

Thanks!

hbl917070 commented 1 year ago

My requirement is to use HTML to draw the whole UI, including TitleBar, window border, and window support translucent background color. I released an open source project, Tiefsee4, which implements the above features. In Tiefsee4, I use WinForm to place WebView2. After processing WinForm into a state without TitleBar and window border, WinForm also lost the ability to drag the border to change the size of the window. So I need a solution that can be triggered inside the WebView2 to change the window size, similar to CSS app-region:drag;.

Maybe can extend the app-region properties like this image, e.g. app-region:drag-top-right means drag the top-right corner of the window to change the window size

nishitha-burman commented 1 year ago

@hbl917070 thank you for the context! Are you looking to configure dimensions of the drag regions or are you okay with an option where WV2 by default provides those regions?

Thanks!

hbl917070 commented 1 year ago

It is of course the best solution to allow developers to configure freely. For example, I usually design the drag regions in the corner to be larger. And different apps may need different size of drag regions. image

nishitha-burman commented 1 year ago

@hbl917070 thank you for the context! So in addition to the dimensions do you also want to configure other factors such as color, transparency, opacity, etc.?

hbl917070 commented 1 year ago

If the CSS app-region is used to bind the drag regions, then I think the style should not be a problem. However, binding a DIV to a drag regions will prevent the DIV from being clicked, which will result in the CSS cursor not being triggered. So need to switch the cursor shape according to the type of dragging For example When the cursor enters the app-region:drag-bottom-right region, the cursor will appear as cursor:nw-resize image

rsegner commented 1 year ago

This post has been very helpful. I didn't realize that WebView2 now supported --app-region: drag.

@nishitha-burman @champnic I have the same issue with resizing the window. The problem is that I use WindowChrome class in WPF to create a 'frameless' WebView window. The WebView does not respect the ResizeBorderThickness property of this class.

In order to get around it I added a border around the WebView which has provided users with a very unforgiving 2 pixels for resizing. I don't really need the same level of customization as described above, however, being able to resize the window from a frameless WebView window would be amazing.

nishitha-burman commented 1 year ago

Hi @rsegner,

Thank you for the feedback! Can you please provide details on how you are adding a border around the WebView and how you are making it draggable?

Thanks, Nishitha

rsegner commented 1 year ago

Hi @nishitha-burman,

Sure thing.

This is the XAML for my frameless webview window.

`<Window x:Class="WebView.WebViewWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
Title="Window" Height="450" Width="800" WindowStartupLocation="CenterScreen">

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="../Resources/Styles.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

<WindowChrome.WindowChrome>
    <WindowChrome CaptionHeight="40" ResizeBorderThickness="8"/>
</WindowChrome.WindowChrome>

<Border Background="{StaticResource primaryColor}"
        BorderBrush="{StaticResource primaryColor}"
        BorderThickness="2">

    <Grid>
        <ContentPresenter x:Name="webViewPresenter" Visibility="Hidden"/>
        <ContentPresenter x:Name="loaderPresenter" Visibility="Visible"></ContentPresenter>
    </Grid>

</Border>

`

The content presenter webViewPresenter contains a WebView that is originally hidden, and then shown once the page is fully loaded.

Before the WebView is shown we are able to resize the window from anywhere inside the 8 pixels denoted by ResizeBorderThickness property on the WindowChrome class.

However, after the WebView is made visible we can only resize from the 2px border surrounding the WebView. Ideally, I would like to remove this border and retain the 8px resize border.

bmathwig commented 1 year ago

Discussing for standardization in https://github.com/w3c/csswg-drafts/issues/7017

PoetaKodu commented 1 year ago

I'd like this feature too. I'm using WebView2 in my native Win32 application and it captures WM_NCHITTEST event, so I cannot even override the dragging behavior in borderless mode. Having any way of achieving this effect would be incredibly useful, because right now we cannot even customize what events are passed to the webview.

champnic commented 1 year ago

You should now be able to use app-region: drag CSS attribute when WebView2 is using HWND hosting (Win32, .NET WPF/Winforms - NOT UWP or WinAppSDK yet), and have that work for touch as well.

You also need to set the additional browser arg --enable-features=msWebView2EnableDraggableRegions.

sc-bai commented 1 year ago

Hi, @champnic , I User WebView2 With Win32. it can drag window with --enable-features=msWebView2EnableDraggableRegions, but it can be work in WebView2 runtim version 103.xxx. with runtime version 100.xx, it can not work, you know how to fix it? thanks

PoetaKodu commented 1 year ago

@champnic It doesn't work for me at all. Have I missed something? This is pretty much the simplest example of a webview running in native Win32 app: https://pastebin.com/4KhVbAMK

I went to C:\Program Files (x86)\Microsoft\EdgeWebView\Application and it seems that I have version 113: image

I use the latest WebView2 library downloaded from NuGet (1.0.1774.30).

The HTML document I'm navigating to is just a fully red page that has --app-region: drag set to body CSS:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>

    <style>
        html, body, #root {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }

        body {
            background-color: red;
            --app-region: drag;
        }
    </style>
</head>
<body>

</body>
</html>
PoetaKodu commented 1 year ago

Oh my god, I managed to get it working by changing this:

body {
  background-color: red;
  --app-region: drag;
}

to this:

body {
  background-color: red;
  --app-region: drag;
  -webkit-app-region: drag;
}

:eyes:

I think that this should be definitely mentioned somewhere in the docs (or maybe it is documented and I missed it?). I searched the web really thoroughly before and experimented with various options but this changes everything.

champnic commented 1 year ago

Aha - I'm really sorry, the CSS should be app-region: drag, not --app-region: drag. I'm updating this thread to fix everywhere I wrote that erroneously.

champnic commented 1 year ago

Hi, @champnic , I User WebView2 With Win32. it can drag window with --enable-features=msWebView2EnableDraggableRegions, but it can be work in WebView2 runtim version 103.xxx. with runtime version 100.xx, it can not work, you know how to fix it? thanks

This support requires runtime 110+, so I wouldn't expect it to work on 103 or 100.

sc-bai commented 1 year ago

Hi, @champnic , I User WebView2 With Win32. it can drag window with --enable-features=msWebView2EnableDraggableRegions, but it can be work in WebView2 runtim version 103.xxx. with runtime version 100.xx, it can not work, you know how to fix it? thanks

This support requires runtime 110+, so I wouldn't expect it to work on 103 or 100.

yeah, I got it. i made a mistake,103+ and 100+ is sdk version. Now, less than 110, Move the window by passing the mouse position to drag the window and 110++ by msWebView2EnableDraggableRegions flag. thanks for your replay.

leaanthony commented 1 year ago

I just tried this and noticed a really weird side-effect: right clicking on an app-region: drag element pops up the default window caption menu! The non-draggable regions will present the standard webview2 context menu when right clicked. Windows 11 / 114.0.1823.43 / win32 image

wangqiang871104 commented 1 year ago

I try msWebView2EnableDraggableRegions in the WinUI3 C# unpackaged app, it can not work, but it can work in c++ WinUI3 project, is it a bug of WinUI3?

champnic commented 1 year ago

@leaanthony Ah - it may be the default behavior expects it to be a title bar. Can you open that as a new issue?

@wangqiang871104 Draggable regions are only working for Windowed/CoreWebView2Controller scenarios at the moment. The WinUI 2 and WinUI 3 controls are built upon visual hosting/CoreWebView2CompositionController, and so don't have support yet. We are working on enabling that support, but it will require a WinUI update before that happens.

leaanthony commented 1 year ago

@leaanthony Ah - it may be the default behavior expects it to be a title bar. Can you open that as a new issue?

Thanks @champnic - Ticket opened if anyone else is interested: https://github.com/MicrosoftEdge/WebView2Feedback/issues/3565

wangqiang871104 commented 1 year ago

I just tried this and noticed a really weird side-effect: right clicking on an app-region: drag element pops up the default window caption menu! The non-draggable regions will present the standard webview2 context menu when right clicked. Windows 11 / 114.0.1823.43 / win32 image

you can try remove WS_SYSMENU, sample code : SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & (0xFFFFFFFF ^ WS_SYSMENU));

wangqiang871104 commented 1 year ago

@leaanthony Ah - it may be the default behavior expects it to be a title bar. Can you open that as a new issue?

@wangqiang871104 Draggable regions are only working for Windowed/CoreWebView2Controller scenarios at the moment. The WinUI 2 and WinUI 3 controls are built upon visual hosting/CoreWebView2CompositionController, and so don't have support yet. We are working on enabling that support, but it will require a WinUI update before that happens.

thanks,does this update on the roadmap, when can I get this update or any workaround can work now?

leaanthony commented 1 year ago

you can try remove WS_SYSMENU, sample code : SetWindowLong(hwnd, GWL_STYLE,\nGetWindowLong(hwnd, GWL_STYLE) & (0xFFFFFFFF ^ WS_SYSMENU));

Thanks, that works to remove the menu, but then the default menu doesn't work either

champnic commented 6 months ago

@hbl917070 Sorry for the confusion - looks like it requires a flag to enable it currently. Can you try setting this additional browser argument? --enable-features=msWebView2EnableDraggableRegions

FYI - We now have a setting available in our prerelease SDKs (should be in the next release SDK as well) for enabling drag regions, so you won't need to use the command line flag moving forwards: https://learn.microsoft.com/en-us/dotnet/api/microsoft.web.webview2.core.corewebview2settings.isnonclientregionsupportenabled?view=webview2-dotnet-1.0.2415-prerelease&preserve-view=true

EarzuChan commented 5 months ago

@champnic Hey, the app-region: drag; and the additional browser args work well. I can now drag and double-click to maximize like a regular window. However, could you add an attribute or API to enable resizing the window by dragging the borders? Also, when I double-click the div title bar to maximize/restore, can I get a callback or access the current maximize/restore state in JavaScript (I want to display the button icon in my custom title bar)? Much appreciated!

champnic commented 5 months ago

Hey @EarzuChan - for border resize, typically the easiest way to accomplish this is to resize the WebView2 to not go all the way to the border of the parent window. This allows the regular parent window to hit-test and handle the border for resizing behaviors.

For an event on maximize/restore, you should be able to detect the state change in the host app, and then send that into the JS (for example, using ExecuteScript) to display your button.

Noahs007 commented 1 month ago

hello,I'm implementing a title bar in html,Now whether there is a good way to hide the menu,When I right-click, I do not want to see the system default menu items.:“Restore”、"Move"、"Size"、"Minimize"、"Maximize"、"Close"

champnic commented 1 month ago

@Noahs007 Right now that's expected behavior. To achieve dragging like a normal titlebar we tell Windows that this is a titlebar when it does hit-testing. Default Windows behavior is to show those menu items when right-clicking on a titlebar.

EarzuChan commented 1 month ago

Hey honey, is the problem of webview2 blocking my stretching of my title-bar-less window border solved?

Noahs007 commented 1 month ago

@Noahs007 Right now that's expected behavior. To achieve dragging like a normal titlebar we tell Windows that this is a titlebar when it does hit-testing. Default Windows behavior is to show those menu items when right-clicking on a titlebar.

Ok thanks for your answer, I'm looking forward to a future update of webview2 to have a good way to hide the menu item showing the expected behavior, since the default design of this menu is different from my html page design style.