dotnet / wpf

WPF is a .NET Core UI framework for building Windows desktop applications.
MIT License
7.04k stars 1.17k forks source link

Touch/Stylus pen drawing on WPF InkCanvas is not DPI Aware. #6859

Open ivoryguard opened 2 years ago

ivoryguard commented 2 years ago

Per Monitor DPI Awareness works well with touch/stylus pen for button click, element dragging on Canvas, and so on. However, InkCanvas may not aware DPI change and follow primay screen scale.

Actual behavior:

Mouse drawing works correctly but, Inks with Touch/stylus pen are drawn to incorrect position/size after MainWindow is moved to extended monitor with different scale.

Expected behavior:

Inks with Touch/stylus pen must be drawn to correct position/size after MainWindow is moved to extended monitor with different scale.

Minimal repro:

The issue can be reproduce as the following step (two monitors are required).

  1. Create a WPF application (.NET Framework 4.0~4.8)
  2. Add a InkCanvas control in MainWindow.
  3. Set Per Monitor DPI Awareness setting as https://github.com/microsoft/WPF-Samples/tree/main/PerMonitorDPI
  4. Set the scale of each monitor with different value like 100% for Display1 and 125% for Display2.
  5. Run the application and move window to extended monitor.
  6. Draw inks with mouse/touch/stylus pen.
  7. Mouse strokes are correct but touch/stylue pen strokes are not correct (the stroke points may be scaled according to the difference between monitor scales.
singhashish-wpf commented 2 years ago

@ivoryguard Could you please attach a minimal repro to check this further?

ivoryguard commented 2 years ago

Reproducing the issue is very simple, if you have a monitor and a laptop with touchscreen.

MainWindow.xaml

<Window x:Class="InkCanvasTest.MainWindow"
        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"
        xmlns:local="clr-namespace:InkCanvasTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="900">
    <Grid>
        <InkCanvas/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace InkCanvasTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

app.manifest

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
      </requestedPrivileges>
    </security>
  </trustInfo>

  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
    <application>
    </application>
  </compatibility>

  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <!-- The combination of below two tags have the following effect : 
      1) Per-Monitor for >= Windows 10 Anniversary Update
      2) System < Windows 10 Anniversary Update -->
      <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitor</dpiAwareness>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
    </windowsSettings>
  </application>

</assembly>

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>

  <runtime>
    <AppContextSwitchOverrides value = "Switch.System.Windows.DoNotScaleForDpiChanges=false"/>
  </runtime>

</configuration>

You can download the sample project - WPF InkCanvas Per Monitor DPI Aware Issue.zip

You can see the issue recording video at the following link; Issue Recording Video

Left Screen - 32 inch 2560x1440 100% Right Screen - 13.3 inch 1366x768 125%

As the recording video, mouse drawing works well after moving to secondary monitor, but touch and stylus pen input are drawn at wrong position.

When the scale of two monitor is same (e.g. 100%+100%, 125%+125%, and so on), the issue does not occur. However, the scale of two monitor is not same( e.g. 100%+125%, 125%+ 100% and so), it occurs when the current screen DPI is changed by moving to another monitor and so on.

When I turn off per monitor DPI awareness settings, Inkcanvas works well for touch/stylus pen inputs. However, I have to give up other functions related to monitor DPI awareness features and actual monitor resolution. For examples, Visual.PointFromScreen returns wrong value and the properties and method of Forms.Screen class also return wrong values and does not work correctly.

lindexi commented 2 years ago

@ivoryguard Looks like I fixed it in https://github.com/dotnet/wpf/pull/6428

jheraldP commented 1 year ago

Hello @lindexi , Good Day. Is the fix will be merged on .Net Framework 4.8?

@ivoryguard Looks like I fixed it in #6428

lindexi commented 1 year ago

@jheraldP Sorry, I don't know.

@singhashish-wpf Could I ask you it will be merged on .NET Framework 4.8?

pchaurasia14 commented 1 year ago

@lindexi - Fixes on .NET Framework will be limited to security vulnerabilities or bugs that are filed as DTS issues.