Windows 7 Multitouch Using WPF 3.5

Update: If you’re using .NET 4.0, be sure to check out my posts about the new touch events.

Finally!  Another post about programming!  I know!  And Windows 7, too!  That ever sure is topical!  This one is for all of you developers running the Win7 beta on the HP TouchSmart (moneyhat go).

Win7 is supposed to woo and wow you with fixing Vista’s many shortcomings new features like multi-touch support.  If you’re curious on how it all works, I’d suggest you watch this great PDC 2008 video on the subject.  Windows will give you everything you need to fancify your touch application, once you’ve set it up to do so.  They’ll tell you how to get multi-touch working in unmanaged code.  There’s also some examples out there showing how to use interop to use this method in C#.  We’ve bridged the gap from unamanaged to managed code – what am I still writing this post for?

Well, WPF is a bit different.  Not only is native multi-touch not present in WPF right now (look forward to .NET 4.0 some time after Win7 releases), but you actually can’t use interop to support multi-touch in your applications.  Yeah, I know.  Something’s amiss when interop fails.

Actually, it is just that WPF doesn’t accept the WM_Touch messages that are sent to windows when the user touches the screen.  Since you don’t get this notification, you can’t capture information regarding Win7 gestures or raw data using interop.

Hold on!  Don’t run to make your shiny, new, and intuitive application in C++ just yet.

As Anson Tao alludes to in the Q&A session after the presentation in the video above, you can recieve the raw data from stylus events in WPF 3.5 SP1, which is already released.  However, you have to do just a tad bit of fidgeting to get it working.

Here’s an application that will show you how to access this information. It just moves two rectangles to the two points you touch on the window.

I’ll start with the simple XAML:

<Window x:Class="MultitouchTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="800" Width="1200">
    <Canvas>
        <Rectangle Canvas.Left="-20" Canvas.Top="0" Height="20" Name="Touch1" Stroke="Black" Fill="Black"  Width="20" />
        <Rectangle Canvas.Left="-20" Canvas.Top="0" Height="20" Name="Touch2" Stroke="Red" Width="20" Fill="Red" />
    </Canvas>
</Window>

Now, the business logic:

public partial class Window1 : Window
{
    #region Class Variables
 
    private int Touch1ID = 0;    // id for first touch contact
    private int Touch2ID = 0;    // id for second touch contact
 
    #endregion
 
    #region P/Invoke
 
    // just a little interop.  it's different this time!
    [DllImport("user32.dll")]
    public static extern bool SetProp(IntPtr hWnd, string lpString, IntPtr hData);
 
    #endregion
 
    #region Constructors/Initialization
 
    public Window1()
    {
        InitializeComponent();
 
        // here's the first thing you need to do.  upon window load, you want to set the tablet
        // property to receive multi-touch data.  you need to the window loaded to ensure the handle is created.
        this.Loaded += new RoutedEventHandler(
           delegate(object sender, RoutedEventArgs args)
           {
               var source = new WindowInteropHelper(this);
 
               SetProp(source.Handle,
                   "MicrosoftTabletPenServiceProperty", new IntPtr(0x01000000));
 
           });
 
        // then, simply subscribe to the stylus events like normal.  you'll get an event for each contact.
        // so, when you move both fingers, you get a StylusMove event for each individual finger
        this.StylusDown += new StylusDownEventHandler(Window1_StylusDown);
        this.StylusMove += new StylusEventHandler(Window1_StylusMove);
        this.StylusUp += new StylusEventHandler(Window1_StylusUp);
    }
 
    #endregion
 
    #region Touch Events
 
    void Window1_StylusDown(object sender, StylusDownEventArgs e)
    {
        Point p = e.GetPosition(this);   // get the location for this contact
 
        // attribute an id with a touch point
        if (Touch1ID == 0)
        {
            Touch1ID = e.StylusDevice.Id;
            // move the rectangle to the given location
            Touch1.SetValue(Canvas.LeftProperty, p.X - Touch1.Width / 2);
            Touch1.SetValue(Canvas.TopProperty, p.Y - Touch1.Height / 2);
        }
        else if (Touch2ID == 0)
        {
            Touch2ID = e.StylusDevice.Id;
            // move the rectangle to the given location
            Touch2.SetValue(Canvas.LeftProperty, p.X - Touch2.Width / 2);
            Touch2.SetValue(Canvas.TopProperty, p.Y - Touch2.Height / 2);
        }
    }
 
    void Window1_StylusMove(object sender, StylusEventArgs e)
    {
        Point p = e.GetPosition(this);
        // determine which contact this belongs to
        if (Touch1ID == e.StylusDevice.Id)
        {
            // move the rectangle to the given location
            Touch1.SetValue(Canvas.LeftProperty, p.X - Touch1.Width / 2);
            Touch1.SetValue(Canvas.TopProperty, p.Y - Touch1.Height / 2);
        }
        else if (Touch2ID == e.StylusDevice.Id)
        {
            // move the rectangle to the given location
            Touch2.SetValue(Canvas.LeftProperty, p.X - Touch2.Width / 2);
            Touch2.SetValue(Canvas.TopProperty, p.Y - Touch2.Height / 2);
        }
    }
 
    void  Window1_StylusUp(object sender, StylusEventArgs e)
    {
         // reinitialize touch id and hide the rectangle
        if (e.StylusDevice.Id == Touch1ID)
        {
            Touch1.SetValue(Canvas.LeftProperty, -Touch1.Width);
            Touch1ID = 0;
        }
        else if (e.StylusDevice.Id == Touch2ID)
        {
            Touch2.SetValue(Canvas.LeftProperty, -Touch2.Width);
            Touch2ID = 0;
        }
    }
 
    #endregion
}

10 thoughts on “Windows 7 Multitouch Using WPF 3.5

  1. Pingback: Windows 7 マルチタッチ イベントをWPFで使う方法 | Coded Style

  2. Pingback: Futile » links for 2009-08-11

  3. Pingback: WPF 4.0 Multitouch: Touch Points | Between the Lines

  4. Pingback: Développer WPF une application “touch enabled” sur Windows 7 Beta

  5. Pingback: Develop a WPF “touch enabled” app on Windows 7 Beta

Comments are closed.