none
Touch Event responsiveness/performance/delay

    Question

  • When I manipulating a framework element with MouseEvents everything works fine and it responds instantly without any delay. But when I manipulate this element with my finger (TouchEvents) the manipulated element lags behind my finger and keep get manipulated after my finger is raised up from the screen.

    It seems that the MouseEvents are handled different in background.

    Is there any solution for this problem? Hopefully someone can help me with this.



    Thursday, March 21, 2013 4:23 PM

Answers

  • Hi Andreas,

    Thanks for the update.

    I can reproduce the same issue as you mentioned.

    It seems the touchevents are not correctly disgarded when the UI is busy. Try using the following code to ignore the intermediate events to workaround the issue.

            Point nextPosition;
            private void UIElement_OnTouchMove(object sender, TouchEventArgs e)
            {
                nextPosition = e.GetTouchPoint(this).Position;
                Dispatcher.BeginInvoke(new Action(() => moveEllipse(nextPosition)), System.Windows.Threading.DispatcherPriority.Background);
            }
            private void UIElement_MouseMove(object sender, MouseEventArgs e)
            {
                if (Mouse.LeftButton == MouseButtonState.Pressed)
                {
                    nextPosition=e.GetPosition(this);
                    Dispatcher.BeginInvoke(new Action(() => moveEllipse(nextPosition)), System.Windows.Threading.DispatcherPriority.Background);
                }
            }
            private void moveEllipse(Point p)
            {
                if (p==nextPosition)
                {
                    //Simulate harder work
                    Thread.Sleep(50);
                    Canvas.SetLeft(ellipse, p.X - 25);
                    Canvas.SetTop(ellipse, p.Y - 25);
                }
            }

    Best regards,


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, March 26, 2013 2:29 AM
    Moderator
  • Yes. I have created a ticket at the Connect site.

    Thanks for the feedback.


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, March 29, 2013 1:56 AM
    Moderator

All replies

  • Hi Andreas,

    Could you please share a minimum sample for us to reproduce this issue in house?

    Thanks,


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, March 22, 2013 4:29 AM
    Moderator
  • <Window x:Class="Tests.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:osc="clr-namespace:Tests"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
           <Canvas MouseMove="UIElement_MouseMove" TouchMove="UIElement_OnTouchMove" Background="LightGray">
               <Ellipse x:Name="ellipse" Fill="#FFC33131" Height="50" Width="50" ></Ellipse>
           </Canvas>
        </Grid>
    </Window>

    and 

    using System.Threading;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    
    
    namespace Tests
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
           
            public MainWindow()
            {
                InitializeComponent();
    
            }
    
            private void UIElement_OnTouchMove(object sender, TouchEventArgs e)
            {
                moveEllipse(e.GetTouchPoint(this).Position);
            }
           
            private void UIElement_MouseMove(object sender, MouseEventArgs e)
            {
                if (Mouse.LeftButton == MouseButtonState.Pressed)
                {
                    moveEllipse(e.GetPosition(this));
                }
            }
    
            private void moveEllipse(Point p)
            {
                //Simulate harder work
                Thread.Sleep(20);
    
                Canvas.SetLeft(ellipse, p.X - 25);
                Canvas.SetTop(ellipse, p.Y - 25);
            }
    
          
        }
    }

    Usage:

    Mouse: Press Mouse Leftbutton and move the mouse to move the object.

    Touch: Touch down on the object and move the finger to move the object.

    Result on my Setup: Mouse Events no delay, Touch Events strong delay.

    My Setup:

    - Touch Supported Dell XPS ONE 27.

    - Visual Studio 2012 .net 4.5

    - Windows 8 64 bit.




    • Edited by Andreas.Schmid Monday, March 25, 2013 10:34 AM
    • Proposed as answer by bn059 Thursday, June 12, 2014 7:23 AM
    • Unproposed as answer by bn059 Thursday, June 12, 2014 7:24 AM
    Monday, March 25, 2013 10:29 AM
  • Hi Andreas,

    Thanks for the update.

    I can reproduce the same issue as you mentioned.

    It seems the touchevents are not correctly disgarded when the UI is busy. Try using the following code to ignore the intermediate events to workaround the issue.

            Point nextPosition;
            private void UIElement_OnTouchMove(object sender, TouchEventArgs e)
            {
                nextPosition = e.GetTouchPoint(this).Position;
                Dispatcher.BeginInvoke(new Action(() => moveEllipse(nextPosition)), System.Windows.Threading.DispatcherPriority.Background);
            }
            private void UIElement_MouseMove(object sender, MouseEventArgs e)
            {
                if (Mouse.LeftButton == MouseButtonState.Pressed)
                {
                    nextPosition=e.GetPosition(this);
                    Dispatcher.BeginInvoke(new Action(() => moveEllipse(nextPosition)), System.Windows.Threading.DispatcherPriority.Background);
                }
            }
            private void moveEllipse(Point p)
            {
                if (p==nextPosition)
                {
                    //Simulate harder work
                    Thread.Sleep(50);
                    Canvas.SetLeft(ellipse, p.X - 25);
                    Canvas.SetTop(ellipse, p.Y - 25);
                }
            }

    Best regards,


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, March 26, 2013 2:29 AM
    Moderator
  • Hi Min Zhu,

    Thanks for your fast answer.

    Your solution works great for a single Touch Application. But a more realistic scenario for a Multi-Touch application would be something like this.

    <Window x:Class="Tests.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
           <Canvas Background="LightGray">
               <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="202" Canvas.Top="60" TouchMove="UIElement_OnTouchMove" />
                <Ellipse Fill="#FFC33131" Height="50" Width="50" TouchMove="UIElement_OnTouchMove" ></Ellipse>
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="100" Canvas.Top="38" TouchMove="UIElement_OnTouchMove" ></Ellipse>
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="82" Canvas.Top="122" TouchMove="UIElement_OnTouchMove" ></Ellipse>
            </Canvas>
        </Grid>
    </Window>
    


    using System.Threading;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Shapes;
    namespace Tests
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
            private void MoveEllipse(Ellipse ellipse, Point p)
            {
                //Simulate harder work
                Thread.Sleep(20);
    
                Canvas.SetLeft(ellipse, p.X - 25);
                Canvas.SetTop(ellipse, p.Y - 25);
            }
            private void UIElement_OnTouchMove(object sender, TouchEventArgs e)
            {
                MoveEllipse(sender as Ellipse,e.GetTouchPoint(this).Position);
            }
        }
    }

    I wrote a small class based on your ideas.

    using System;
    using System.Windows;
    
    namespace Tests
    {
        public class TouchEventExecution
        {
            public TouchEventExecution()
            {
                
            }
            private Action _nextAction;
            public void SubmitWorkItem(Action action)
            {
                _nextAction = action;
                Application.Current.Dispatcher.BeginInvoke(new Action(() => ProcessAction(action)), System.Windows.Threading.DispatcherPriority.Background);
            }
    
            private void ProcessAction(Action action)
            {
                if (_nextAction == action)
                {
                    action.Invoke();
                   
                }
            }
        }
    }

    The problem is you have to initialize one TouchEventExecution class per Ellipse (Touchable Object).

    Maybe there is a more intelligent (static) solution for this? Thanks for feedback in advance.

    Tuesday, March 26, 2013 3:09 PM
  • Hi Andreas,

    I suggest to use a dictionary to store nextAction for each different Touchable object. Then you only need to have one TouchEventExecution.

    Best regards,


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, March 27, 2013 6:16 AM
    Moderator
  • Hi Min,

    ok thanks. This issue is possibly also something for a bug report sector!

    Thursday, March 28, 2013 11:24 AM
  • Yes. I have created a ticket at the Connect site.

    Thanks for the feedback.


    Min Zhu
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, March 29, 2013 1:56 AM
    Moderator
  • Thank you very much.
    Tuesday, April 02, 2013 9:28 AM
  • Hello Min Zhu,

    I am exactly in teh same situation where I have a WPF control that I manipulate on a WPF touch application. While I am using mouse to move the map or use single touch point, i am able to move it and behave quite normaly during a manipulation operation.

    But in opposite as long as I strt to Zoom in or Out with 2 touch point, as soon as release the touch, the map still keep on zoom in or out with big latency

    In my touch handler I have the follwoing :

     private void _LayoutRoot_PreviewTouchMove(object sender, System.Windows.Input.TouchEventArgs e)
            {
                if (Microsoft.Surface.SurfaceEnvironment.IsSurfaceEnvironmentAvailable)
                {
                    if (e.Device.GetIsTagRecognized()) e.Handled = true;
                    if (!e.Device.GetIsFingerRecognized()) e.Handled = true;
                }
                else
                {
                    e.Handled = false;
                    log.Debug("_LayoutRoot_PreviewTouchMove : e.Handled :" + e.Handled.ToString());
                }
            }

    So when I am runing my application under win7 or 8, I ame simply setting e.Handle = true

    What would be the trick to do in my case to work around that wierd behaviour discribe here ?


    Your knowledge is enhanced by that of others.

    Wednesday, July 03, 2013 1:09 PM
  • Hi Serge,

    I'm experiencing similar - and very annoying - behaviour.

    After a full day of debugging we started to notice the strange delay only occurs on the first finger on screen... I know, its odd.

    So lets assume i place first my left finger on the screen and secondly the right: now i can move my right finger and get good performance, but as soon as i move my left finger all goes wrong and performance drops badly.

    Debugging such a scenario is difficult, because simulated input doesn't show the same problems; it's somewhere deep down in the framework.

    When I pause execution during one of these delays, I notice that I have a very very very deep callstack, mostly involving (unnecessary) hittesting and input handling. I am also under the impression that the touch events for the first finger still all get upgraded to stylus and mouse events and back, even though I maked them as handled or even just exceptioned out of them. Maybe it's the touch processing thread that's doing something wrong... I don't know.

    Best regards,

    Joep


    Friday, July 05, 2013 12:43 PM
  • After the WPF-Team is not very ambitious to fix this issue I tried to write my own responsive touchdevice and ended up with this. 

    public class ResponsiveTouchDevices : TouchDevice { #region static private static readonly Dictionary<int, ResponsiveTouchDevices> deviceDictionary = new Dictionary<int, ResponsiveTouchDevices>(); public static void Register(FrameworkElement root) { root.PreviewTouchDown += (sender, args) => { if (!deviceDictionary.Keys.Contains(args.TouchDevice.Id)) { var device = new ResponsiveTouchDevices(args.TouchDevice.Id); deviceDictionary.Add(args.TouchDevice.Id, device); } }; root.PreviewTouchDown += (sender, args) => { if (args.TouchDevice is ResponsiveTouchDevices) return; var device = deviceDictionary[args.TouchDevice.Id]; device.PreviewTouchDown(sender, args); args.Handled = true; }; root.PreviewTouchMove += (sender, args) => { if (args.TouchDevice is ResponsiveTouchDevices) return; var device = deviceDictionary[args.TouchDevice.Id]; device.PreviewTouchMove(sender, args); args.Handled = true; }; root.PreviewTouchMove += (sender, args) => { if (args.TouchDevice is ResponsiveTouchDevices) return; var device = deviceDictionary[args.TouchDevice.Id]; device.PreviewTouchUp(sender, args); args.Handled = true; }; } #endregion private readonly DisgardWhenUIisBusyHandler _disgardWhenUIisBusyHandler = new DisgardWhenUIisBusyHandler(); private Point Position { get; set; } private ResponsiveTouchDevices(int deviceId) : base(deviceId) { Position = new Point(); } private void PreviewTouchDown(object sender, TouchEventArgs e) { if (IsActive) { ReportUp(); Deactivate(); } SetActiveSource(e.TouchDevice.ActiveSource); Position = e.GetTouchPoint(null).Position; Activate(); ReportDown(); e.Handled = true; } private void PreviewTouchMove(object sender, TouchEventArgs e) { if (IsActive) { _disgardWhenUIisBusyHandler.SubmitWorkItem(() => { Position = e.GetTouchPoint(null).Position; ReportMove(); }); e.Handled = true; } } private void PreviewTouchUp(object sender, TouchEventArgs e) { if (IsActive) { Position = e.GetTouchPoint(null).Position; ReportUp(); Deactivate(); e.Handled = true; } } public override TouchPoint GetTouchPoint(IInputElement relativeTo) { Point point = Position; if (relativeTo != null) { point = ActiveSource.RootVisual.TransformToDescendant((Visual)relativeTo).Transform(Position); } var rect = new Rect(point, new Size(1, 1)); return new TouchPoint(this, point, rect, TouchAction.Move); } public override TouchPointCollection GetIntermediateTouchPoints(IInputElement relativeTo) { return new TouchPointCollection(); } }

        public class DisgardWhenUIisBusyHandler
        {
            private readonly DispatcherPriority _priority;
            private Action _nextAction;

            public DisgardWhenUIisBusyHandler(DispatcherPriority priority = DispatcherPriority.Input)
            {
                _priority = priority;
            }

            public void SubmitWorkItem(Action action)
            {
                _nextAction = action;
                Application.Current.Dispatcher.BeginInvoke(new Action(() => ProcessAction(action)), _priority);
            }

            private void ProcessAction(Action action)
            {
                if (_nextAction == action)
                {
                    action.Invoke();
                }
            }
        }


    Usage:

    public partial class MainWindow { public MainWindow() { InitializeComponent();

    //Enable ResponsiveDevices ResponsiveTouchDevices.Register(this); } private void MoveEllipse(Ellipse ellipse, Point p) { //Simulate harder work Thread.Sleep(20); Canvas.SetLeft(ellipse, p.X - 25); Canvas.SetTop(ellipse, p.Y - 25); } private void UIElement_OnTouchMove(object sender, TouchEventArgs e) { MoveEllipse(sender as Ellipse,e.GetTouchPoint(this).Position); } private void UIElement_OnTouchDown(object sender, TouchEventArgs e) { e.TouchDevice.Capture(sender as UIElement); } private void UIElement_OnTouchUp(object sender, TouchEventArgs e) { //e.TouchDevice.Synchronize(); } }


    <Window x:Class="Tests.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid x:Name="Layoutroot">
            <Canvas Background="LightGray" >
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="202" Canvas.Top="60" TouchMove="UIElement_OnTouchMove" TouchDown="UIElement_OnTouchDown" TouchUp="UIElement_OnTouchUp" />
                <Ellipse Fill="#FFC33131" Height="50" Width="50" TouchMove="UIElement_OnTouchMove" TouchDown="UIElement_OnTouchDown" TouchUp="UIElement_OnTouchUp"  />
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="100" Canvas.Top="38" TouchMove="UIElement_OnTouchMove" TouchDown="UIElement_OnTouchDown" TouchUp="UIElement_OnTouchUp"  />
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="82" Canvas.Top="122" TouchMove="UIElement_OnTouchMove" TouchDown="UIElement_OnTouchDown" TouchUp="UIElement_OnTouchUp"  />
            </Canvas>
        </Grid>
    </Window>

    This class is not tested and is not even considered in being in alpha status. 

    In this very special test case it works better with as without the class. But I'm not very happy with the result. Maybe some of you guys can help me tweaking it or suggest a better solution for this issue. 



    Wednesday, November 27, 2013 2:04 PM
  • I would suggest using the Manipulation events for mulit-touch scenarios.

    <Window x:Class="TouchEventPerf.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            ManipulationDelta="Window_ManipulationDelta"
            ManipulationStarting="Window_ManipulationStarting">
        <Window.Resources>
            <!--The movement, rotation, and size of the Rectangle is 
            specified by its RenderTransform.-->
            <MatrixTransform x:Key="InitialMatrixTransform">
                <MatrixTransform.Matrix>
                    <Matrix OffsetX="0" OffsetY="0"/>
                </MatrixTransform.Matrix>
            </MatrixTransform>
        </Window.Resources>
        
        <Grid>
            <Canvas Background="LightGray">
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="202" Canvas.Top="60" RenderTransform="{StaticResource InitialMatrixTransform}" IsManipulationEnabled="True"/>
                <Ellipse Fill="#FFC33131" Height="50" Width="50" RenderTransform="{StaticResource InitialMatrixTransform}" IsManipulationEnabled="True"></Ellipse>
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="100" Canvas.Top="38" RenderTransform="{StaticResource InitialMatrixTransform}" IsManipulationEnabled="True"></Ellipse>
                <Ellipse Fill="#FFC33131" Height="50" Width="50" Canvas.Left="82" Canvas.Top="122" RenderTransform="{StaticResource InitialMatrixTransform}" IsManipulationEnabled="True"></Ellipse>
            </Canvas>
        </Grid>
    
    </Window>
    

       public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
            {
                //Thread.Sleep(200);
                if (e.OriginalSource.GetType() == typeof(Ellipse))
                {
                    UIElement ellipseToMove;
                    ellipseToMove = e.OriginalSource as Ellipse;
                    Matrix ellipseMatrix = ((MatrixTransform)ellipseToMove.RenderTransform).Matrix;
                    // Move the ellipse.
                    ellipseMatrix.Translate(e.DeltaManipulation.Translation.X,
                                          e.DeltaManipulation.Translation.Y);
                    // Apply the changes to the Rectangle.
                    ellipseToMove.RenderTransform = new MatrixTransform(ellipseMatrix);
                }
            }
    
            private void Window_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
            {
                e.ManipulationContainer = this;
                e.Handled = true;
            }
    
    
        }

    Wednesday, April 16, 2014 5:28 PM
  • Hi there,

    For better performance, don't use the Stylus & TouchEvent but ManipulationEvent, the interface response is better. So, the solution with is now:

    <Window x:Class="Tests.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:osc="clr-namespace:Tests"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Canvas x:Name="canvas" Background="LightGray">
                <Ellipse x:Name="ellipse" Fill="#FFC33131" Height="50" Width="50" IsManipulationEnabled="true">
                    <Ellipse.RenderTransform>
                        <MatrixTransform/>
                    </Ellipse.RenderTransform>
                </Ellipse>
            </Canvas>
        </Grid>
    </Window>
    

    Don't forget the IsManipulationEnabled="true" in your XAML code.

    using System.Text;
    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;
    using System.Windows.Media.Animation;
    
    namespace Tests
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            private UIElement _last;
            private int _countMove=0;
    
            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
            }
    
            void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                canvas.ManipulationStarting += new EventHandler<ManipulationStartingEventArgs>(Ellipse_ManipulationStarting);
                canvas.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(Ellipse_ManipulationDelta);
                canvas.MouseMove += UIElement_MouseMove;
            }
    
            private void Ellipse_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
            {
                var uie = e.OriginalSource as UIElement;
                if (uie != null)
                {
                    if (_last != null)
                        Canvas.SetZIndex(_last, 0);
                    _last = uie;
                }
                e.ManipulationContainer = canvas;
                e.Handled = true;
            }
    
            private void Ellipse_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
            {
                MoveTest();
                var element = e.Source as FrameworkElement;
                if (element != null)
                {
                    var deltaManipulation = e.DeltaManipulation;
                    var matrix = ((MatrixTransform)element.RenderTransform).Matrix;
                    //Thread.Sleep(10);
                    Point center = new Point(element.ActualWidth / 2, element.ActualHeight / 2);
    
                    center = matrix.Transform(center);
    
                    matrix.Translate(e.DeltaManipulation.Translation.X, e.DeltaManipulation.Translation.Y);
    
                    ((MatrixTransform)element.RenderTransform).Matrix = matrix;
    
                    e.Handled = true;
                }
            }
    
            private void UIElement_MouseMove(object sender, MouseEventArgs e)
            {
                if (Mouse.LeftButton == MouseButtonState.Pressed)
                {
                    MoveTest();
                    moveEllipse(e.GetPosition(this));
                }
            }
    
            private void moveEllipse(Point p)
            {
                //Simulate harder work
                Thread.Sleep(20);
    
                Canvas.SetLeft(ellipse, p.X - 25);
                Canvas.SetTop(ellipse, p.Y - 25);
            }
    
            private int MoveTest()
            {
                System.Diagnostics.Debug.WriteLine(_countMove + " : You Move");
                return _countMove++;
            }
    
        }
    }

    I hope it will help you!

    Thursday, June 12, 2014 7:32 AM
  • There is a bug deep inside the .Net API stack which causes unreliable touch behavior.  All WPF applications which use touch events are affected by this bug:

    https://connect.microsoft.com/VisualStudio/feedback/details/903760/wpf-touch-services-are-badly-broken

    Until this is fixed, WPF touch services cannot be used reliably.  WPF, when touch is throttled, will stop responding to touch altogether because of this bug.

    Tuesday, June 24, 2014 2:02 PM