やる気駆動型エンジニアの備忘録

WPF(XAML+C#)の話題を中心に.NET/Android/CI やたまに趣味に関するブログです

Windows10 + WPF でタッチ フィードバックを無効化する(※)

Windows10 上のWPF アプリケーションでタッチ フィードバックを無効化する方法にいてメモ

※まず最初に、この記事で紹介する方法はあるパターン(後述)に対応できていません。
 そのパターンでの対応方法が見つかれば追記 or あらたに記事を書きます。

タッチ フィードバックとは?

Windows8 以降(?)に登場したタッチパネル向けの視覚的表現です。
下の白い円状のインジケータがそれです。
f:id:iyemon018:20170525223659p:plain

このタッチ フィードバックは、以下の設定で表現のレベルを変更することができます。
[Windowsの設定] - [簡単操作] - [その他のオプション] - [タッチ フィードバック]
f:id:iyemon018:20170525224213p:plain

or
[コントロールパネル] - [ペンとタッチ] - [タッチ]
f:id:iyemon018:20170525224224p:plain

この設定は同期しているのでどちらかを変更すればもう片方も変わります。

無効化するには

上記の設定をOFFにすればデスクトップやエクスプローラ、ブラウザなどを操作している感じでは、無効化することができます。
ただし、独自に作成したWPFなどのアプリケーションは、この設定の影響を受けないようです。
Visual Studioもこの影響を受けません。
(UWPならこの設定の影響を受けるのかもしれませんが未検証です。)

ということでタッチ フィードバックを無効化する方法について色々調べてみた結果、完成したコードがこちら↓↓↓



[動作環境]

< MainWindow.xaml.cs >

        private void TouchFeedbackStatus(bool enable)
        {
            Stylus.SetIsTouchFeedbackEnabled(this, enable);
            Stylus.SetIsTapFeedbackEnabled(this, enable);
            Stylus.SetIsPressAndHoldEnabled(this, enable);
            Cursor = enable ? Cursors.Arrow : Cursors.None;
        }

視覚的フィードバックの見た目は、以下の方法で無効化することができました。

Stylus.SetIsTouchFeedbackEnabled(this, enable);
Stylus.SetIsTapFeedbackEnabled(this, enable);
Stylus.SetIsPressAndHoldEnabled(this, enable);

また、これだけでは小さい十字のカーソルが残ってしまうので、

Cursor = enable ? Cursors.Arrow : Cursors.None;

とすることで対応しています。

全体のコードはこちら。< MainWindow.xaml >

<Window
    x:Class="TouchFeedbackDisable.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:local="clr-namespace:TouchFeedbackDisable"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="525"
    Height="350"
    Background="#FF292929"
    WindowStartupLocation="CenterScreen"
    WindowState="Maximized"
    mc:Ignorable="d">
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border Grid.Row="0">
            <CheckBox
                Checked="TouchFeedback_OnChecked"
                Content="Touch Feedback"
                Foreground="GhostWhite"
                IsChecked="True"
                Unchecked="TouchFeedback_OnUnchecked" />
        </Border>
        <Canvas
            Grid.Row="1"
            Background="Black"
            PreviewTouchDown="DrawLinePanel_OnPreviewTouchDown"
            PreviewTouchMove="DrawLinePanel_OnPreviewTouchMove" />
    </Grid>
</Window>

< MainWindow.xaml.cs >

namespace TouchFeedbackDisable
{
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Shapes;

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        #region Fields

        private TouchPoint _point;

        #endregion

        #region Ctor

        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion

        #region Methods

        private void DrawLinePanel_OnPreviewTouchDown(object sender, TouchEventArgs e)
        {
            Canvas drawLinePanel = sender as Canvas;
            if (drawLinePanel != null)
            {
                _point = e.GetTouchPoint(drawLinePanel);
            }
        }

        private void DrawLinePanel_OnPreviewTouchMove(object sender, TouchEventArgs e)
        {
            Canvas drawLinePanel = sender as Canvas;
            if (drawLinePanel != null)
            {
                TouchPoint currentPoint = e.GetTouchPoint(drawLinePanel);
                Line line = new Line();
                line.Stroke = Brushes.White;
                line.StrokeThickness = 1;
                line.X1 = _point.Position.X;
                line.Y1 = _point.Position.Y;
                line.X2 = currentPoint.Position.X;
                line.Y2 = currentPoint.Position.Y;
                drawLinePanel.Children.Add(line);
                _point = currentPoint;
            }
        }

        private void TouchFeedback_OnChecked(object sender, RoutedEventArgs e)
        {
            TouchFeedbackStatus(true);
        }

        private void TouchFeedback_OnUnchecked(object sender, RoutedEventArgs e)
        {
            TouchFeedbackStatus(false);
        }

        private void TouchFeedbackStatus(bool enable)
        {
            Stylus.SetIsTouchFeedbackEnabled(this, enable);
            Stylus.SetIsTapFeedbackEnabled(this, enable);
            Stylus.SetIsPressAndHoldEnabled(this, enable);
            Cursor = enable ? Cursors.Arrow : Cursors.None;
        }

        #endregion
    }
}

左上のチェックボックスをON/OFFすることでタッチ フィードバックの有効・無効を切り替えています。

解決できていない問題

最初に書いたとおり、これだけではタッチ フィードバックを完全に無効化することはできません。
これには大きな落とし穴があります。

タッチ フィードバックのオプションに"より濃くて大きい視覚的フィードバックを使う(プレゼンテーション向き)"という項目があります。
これをONにすると、上記のコードを実行しているにも関わらずタッチ フィードバックが表示されてしまいます。
OSの設定としてはこちらが上位で優先されてしまうのでしょう。
現在のところ回避策はありません。
(通常この設定はOFFになっているので、ユーザーが手動でONにしない限りは今回の内容で対応可能です。)

今回使用したサンプルはこちら↓↓↓
github.com