Adding Touch Support to Desktop Applications for Ultrabook™ Running on Windows* 8

Touch has become the most important input type for handheld devices. It has many useful use cases in real life. While driving a car, a touch-based GPS navigation system and give you quick access to required information.

Window* OSs have offered limited single finger touch capability for years. Starting with Windows 7, Microsoft added multi-touch support like pinch and zoom. Windows 8 brings more enhanced touch support. Especially, Windows Store Apps have built-in support for frequently used touch gestures such as cross sliding, dragging, etc. But the traditional Windows desktop application development API has limited support for ready-to-use touch gestures. It provides necessary touch inputs that can be used to recognize a specific touch gesture. In this article, we demonstrate how to implement several touch gestures in your Windows 8 desktop applications.

Windows Presentation Foundation (WPF) manipulation provides support to recognize frequently used touch gestures like swipe, zoom and pinch, etc. In this article, we discuss a couple of most frequently used gestures.

Manipulation Events

During manipulation processes, different manipulation events are raised that provide useful information. In this section, we discuss different manipulation events and details about them. ManipulationStarting and ManipulationStarted events are used during initialization. Then, these two events are followed by many ManipulationDelta events, which consolidate the action of one, two, or more fingers into translation, scaling, and rotation information. When all the fingers have lifted from the element being manipulated, a ManipulationIntertiaStarting event occurs that is immediately followed by ManipulationCompleted event. ManipulationCompleted event provides an opportunity to decide the recent manipulation pattern.

Swipe Gesture

Swipe is one of the very frequently used touch gestures, especially for moving to the next or previous item. Look at any photo album-type application and you can see how left-to-right and right-to-left swipe to view the previous and next pictures, respectively, provides a better user experience. In this article, we demonstrate how to implement this gesture in a Windows 8 desktop application for Ultrabooks. For example, users of the photo application can swipe to see the next or previous image from the collection of displayed images.

Implementation

Swipe gestures can be recognized using several events provided by WPF manipulation. ManipulationStarting is used during initialization or while resetting values. ManipulationDelta is of most importance as it provides many useful touch details, e.g., horizontal and vertical touch movements and cumulative delta. Almost all WPF elements provide manipulation support. By default, manipulation events are disabled for any element. To enable, we need to set IsManipulationEnable to "True" in XAML file. Then, we need to register for interested manipulation events.

Step: 1

Enable manipulation for the element by setting its IsManipulationEnable attribute to "True".

<Image Name="centerImageView" IsManipulationEnable="True" />

Step: 2

Register for interested manipulation events on the element in the XAML file. Let Visual Studio* create an event handler for each event.

 <Image Name=”centerImageView” IsManipulationEnable=”True” ManipulationStarting=”centerImageView_ManipulationStarting” ManipulationDelta=”centerImageView_ManipulationDelta” ManipulationCompleted=”centerImageView_ManipulationCompleted” ManipulationInertiaStarting=”centerImageView_ManipulationInertiaStarting” /> 

Step: 3

Utilize the ManipulationStarting event to set values for ManipulationContainer and Handled property. ManipulationContainer allows specifying that the position should be relative to another element. Handled allows specifying how the event is handled by the class handler.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationStarting(object sender, System.Windows.Input.ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;
            e.Handled = true;
        }
    }

Step: 4

ManipulationDelta event occurs multiple times when the user drags a finger over the screen during manipulation. CumulativeManipulation property contains the total changes that occurred for the current manipulation. It further provides more details of the type of manipulation, e.g., translation, scaling, rotation, etc. The Velocities property give details on the current speed of manipulation and direction.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            //store values of horizontal & vertical cumulative translation
            cumulativeDeltaX = e.CumulativeManipulation.Translation.X;
            cumulativeDeltaY = e.CumulativeManipulation.Translation.Y;
            //store value of linear velocity into horizontal direction  
            linearVelocity = e.Velocities.LinearVelocity.X
        }
    }

Step: 5

Use the ManipulationInertiaStarting event to set the desired deceleration value for the given manipulation behavior, e.g., ExpansionBehaviour and RotationBehaviour. After the ManipulationInertiaStarting is called, it will call ManipulationDelta until velocity becomes zero.

Set initial velocity of the expansion behavior and desired deceleration here.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationDelta(object sender, System.Windows.Input.ManipulationInertiaStartingEventArgs e)
        {
            e.ExpansionBehaviour = new InertialExpansionBehaviour()
            {
                InitialVelocity = e.InitialVelocities.ExpansionVelocity;
                DesiredDecelerartion = 10.0 * 96.0 / 1000000.0
            }
        }
    }

Step: 6

Use the ManipulationCompleted event to determine the total amount the position of the manipulation changed. Use the stored value cumulativeDeltaX to determine if the movement is from left-to-right or right-to-left. Also call the isSwipeGesture function to determine if the manipulation formed a Swipe gesture or not.

We need to show the next image when the photo app recognizes a swipe from right-to-left. So set the current index of the list view to next image. Similarly, when the photo app recognizes a swipe from left-to-right, it should set the current index of the list view to the previous image.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
        {
            bool isRightToLeftSwipe = false; //to determine swipe direction
            If(cumulativeDeltaX < 0)
            {
                //moving from right to left
                isRightToLeftSwipe = true;
            }
            //check if this is swipe gesture
            If(isSwipeGesture(deltaX, deltaY, linearVelocity)
            {
                If(isRightToLeftSwipe)
                {
                    //show previous image
                    this.imagesListBox.SelectedIndex = currentIndex -1;
                }
                Else
                {
                    //show next image
                    this.imagesListBox.SelectedIndex = currentIndex +1;
                }
            }
        }
        .....
    }    

Step: 7

isSwipeGesture is a method to determine the characteristics of a swipe gesture. Consider deltaX, deltaY, and velocity to decide the swipe gesture’s characteristics.

Here, AppConstants.DeltaX and AppConstants.DeltaY are defined as constant values that define the maximum allowed horizontal and vertical movement, respectively. AppConstants.LinearVelocityX is defined as a constant value that defines the maximum allowed velocity.

   public partial class MainWindow : Window
    {
        .....
        private bool isSwipeGesture(double deltaX, double deltaY, double linearVelocity)    
        {
            bool result = false;
            if(deltaY <= AppConstants.DeltaX && deltaX >= AppConstants.DeltaY && linearVelocity >= AppConstants.LinearVelocityX)
            result = true; 
        }
        return result;
    }

Zoom and Pinch Gesture

Pinch/Zoom is another important and frequently used touch gesture. Zoom and pinch provide a better user experience by allowing users to zoom in or out of an image. The rest of the article talks about the aspects involved in supporting this gesture on a Windows 8 desktop application.

Implementation

WPF manipulations provide different events that can be used to recognize the zoom and pinch gesture. ManipulationStarting is used for initialization or while resetting values. ManipulationDelta is most important as it provides several useful touch details, e.g., DeltaManipulation.Scale. Matrix is a core part of this gesture, which actually scales the element up and down by changing its x and y values. By default, manipulation events are disabled for any element. To enable, we need to set IsManipulationEnable to "True" in the XAML file. Then, we need to register for required manipulation events.

Step: 1

Enable manipulation for the element by setting its IsManipulationEnable attribute to "True" in the XAML file.

<Image Name="centerImageView" IsManipulationEnable="True" />

Step: 2

Register for interested manipulation events on the element in the XAML file. Let Visual Studio create an event handler for each event.

 <Image Name=”centerImageView” IsManipulationEnable=”True” ManipulationStarting=”centerImageView_ManipulationStarting” ManipulationDelta=”centerImageView_ManipulationDelta” ManipulationCompleted=”centerImageView_ManipulationCompleted” /> 

Step: 3

Utilize the ManipulationStarting event to set values for ManipulationContainer and Handled property. ManipulationContainer allows specifying that the position should be relative to another element. Handled allows specifying the event is handled by the class handler.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationStarting(object sender, System.Windows.Input.ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = this;
            e.Handled = true;
        }
    }

Step: 4

ManipulationDelta event occurs multiple times when the user drags a finger over the screen during manipulation. The DeltaManipulation property provides DeltaManipulation.Scale.X and DeltaManipulation.Scale.Y values which help to determine if the maximum scale value is horizontal or vertical, and based on that we can decide if the action is zoom or pinch.

You can get the current matrix of the element using RenderTransform and Matrix properties. Scale it using the ScaleAt method of matrix by recently changed deltaX and deltaY values. Apply the new scaled matrix to the element by calling RenderTransform. Here, AppConstants.MinimumZoom and AppConstants.MaximumZoom are defined as constant values that define the allowed minimum and maximum zoom.

The code snippet below shows how we support zoom and pinch in the photo application.

    Public partial class MainWindow : Window
    {
        .....
        private void centerImageView_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            /get current matrix of the element.
            Matrix borderMatrix = ((MatrixTransformation)centerImgBorder.RenderTransform).Matrix;
            //determine if action is zoom or pinch
            var maxScale = Math.Max(e.DeltaManipulation.Scale.X, e.DeltaManipulation.Scale.Y);
            //check if not crossing minimum and maximum zoom limit
            if((maxScale <  1 && borderMatrix.M11 *maxScale >  AppConstants.MinimumZoom) ||
            (maxScale >  1 && borderMatrix.M11 *maxScale <  AppConstants.MaximumZoom)
        {
            //scale to most recent change (delta) in X & Y 
            borderMatrix.ScaleAt(e.DeltaManipulation.Scale.X,
                    e.DeltaManipulation.Scale.Y,
                    centerImgBorder.ActualWidth/2
                    centerImgBorder.ActualHeight/2);
            //render new matrix
            centerImgBorder.RenderTransform = new MatrixTransform(borderMatrix));
        }

        }
    }   

Remarks

Windows supports touch input in addition to basic keyboard and mouse inputs. Windows provides built-in touch support for standard Windows control. For example, ListBox has built-in touch-enabled scroll support.

Windows supports the following default gestures:

  • Press and Tap
  • Two Finger Tap
  • Press and Hold
  • Selection and Drag
  • Pan

Additional Resources

The Human Touch: Building Ultrabook™ Applications in a Post-PC Age

Ultrabook™ Desktop Applications Development on Windows* 8: Photo Application with Touch and Sensors

Notices

INFORMATION IN THIS DOCUMENT IS PROVIDED IN CONNECTION WITH INTEL PRODUCTS. NO LICENSE, EXPRESS OR IMPLIED, BY ESTOPPEL OR OTHERWISE, TO ANY INTELLECTUAL PROPERTY RIGHTS IS GRANTED BY THIS DOCUMENT. EXCEPT AS PROVIDED IN INTEL'S TERMS AND CONDITIONS OF SALE FOR SUCH PRODUCTS, INTEL ASSUMES NO LIABILITY WHATSOEVER AND INTEL DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY, RELATING TO SALE AND/OR USE OF INTEL PRODUCTS INCLUDING LIABILITY OR WARRANTIES RELATING TO FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR INFRINGEMENT OF ANY PATENT, COPYRIGHT OR OTHER INTELLECTUAL PROPERTY RIGHT.

UNLESS OTHERWISE AGREED IN WRITING BY INTEL, THE INTEL PRODUCTS ARE NOT DESIGNED NOR INTENDED FOR ANY APPLICATION IN WHICH THE FAILURE OF THE INTEL PRODUCT COULD CREATE A SITUATION WHERE PERSONAL INJURY OR DEATH MAY OCCUR.

Intel may make changes to specifications and product descriptions at any time, without notice. Designers must not rely on the absence or characteristics of any features or instructions marked "reserved" or "undefined." Intel reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The information here is subject to change without notice. Do not finalize a design with this information.

The products described in this document may contain design defects or errors known as errata which may cause the product to deviate from published specifications. Current characterized errata are available on request.

Contact your local Intel sales office or your distributor to obtain the latest specifications and before placing your product order.

Copies of documents which have an order number and are referenced in this document, or other Intel literature, may be obtained by calling 1-800-548-4725, or go to: http://www.intel.com/design/literature.htm

Software and workloads used in performance tests may have been optimized for performance only on Intel microprocessors. Performance tests, such as SYSmark and MobileMark, are measured using specific computer systems, components, software, operations, and functions. Any change to any of those factors may cause the results to vary. You should consult other information and performance tests to assist you in fully evaluating your contemplated purchases, including the performance of that product when combined with other products.

Any software source code reprinted in this document is furnished under a software license and may only be used or copied in accordance with the terms of that license.

Intel, Ultrabook, and the Intel logo are trademarks of Intel Corporation in the US and/or other countries.

Copyright © 2012 Intel Corporation. All rights reserved.

*Other names and brands may be claimed as the property of others.

For more complete information about compiler optimizations, see our Optimization Notice.

Comments

's picture

In the following code, it would be good to have Math.Abs() around the deltas and velocity. Otherwise, this only detects left to right as a swipe, not right to left.

01 public partial class MainWindow : Window
02 {
03 .....
04 private bool isSwipeGesture(double deltaX, double deltaY, double linearVelocity)
05 {
06 bool result = false;
07 if(deltaY <= AppConstants.DeltaX && deltaX >= AppConstants.DeltaY && linearVelocity >= AppConstants.LinearVelocityX)
08 result = true;
09 }
10 return result;
11 }

Amit Gajjar.'s picture

When i ManipulationDelta event called many times i found UI Freeze problem. i am using canvas to change graphics. i am using multitouch and on changing of slider using touch some change occur on canvas. but that cause other motion stop/freeze. to move other object i am using DispatcherTimer.

Please help me to resolve such issue.

thanks
-amit gajjar

Thanks Amit Gajjar