Simulating Touch Input in Windows 8 Using Touch Injection API

Simulating Touch Input in Windows 8 Using Touch Injection API

 

Introduction

Windows 8 comes with multiple input types. Windows 8 devices often have multi-touch screens that enable users to use multiple fingers simultaneously to produce different input interactions such as tapping, dragging, or pinching. The Windows Runtime has a number of different mechanisms for handling touch input, enabling us to create an immersive experience that we can explore with confidence. This Article covers the basics of using touch input (simulating the touch input via VC++ code) in Windows Developer Preview using C++ by Touch Injection API. For other (consumer preview and release preview) you may need to enable UI access permission( check references for this).

Using this article will help all to create application that will help in simulating the Touch inputs like Tap, Drag, Rotate etc. , Consider an application that will convert users mouse event to touch event for those users who does not have Touch screen monitor. Also this will be of great use for Automating any touch based application on windows 8.

Prerequisites

This Article assumes that Reader is updated with these basics requirements

  • Understandings of Microsoft Visual C++
  • Using the code on Windows developer preview
  • Using Visual studio 11 developer preview to compile the code
  • Reader has knowledge of Touch Injection API structure and flags. If not please refer doc1, doc2 or read the references

 

Touch Interactions

Touch Interactions are a high-level way of interpreting touch input data into a set of common motions such as tapping, dragging, and pinching. Lets Understand some of the common interactions used in Windows Developer Preview which are as follow:

Interaction

  Input Type 

Description

Tap Single Input One finger touches the screen and lifts up.
Hold Single Input One finger touches the screen and stays in place.
Drag Single Input One or more fingers touch the screen and move in the same direction.
Pinch/Pan Multiple Input Two or more fingers touch the screen and move closer together (Zoom -out) or farther apart (Zoom-in).
Rotate Multiple Input Two or more fingers touch the screen and move in a clockwise or counter-clockwise arc.
Cross-slide Multiple Input  Two finger touches an object and drags it at a right angle to the panning direction.

For windows 8 developer preview this will work as it is but for other windows 8 versions you may need to change UI access permission. Lets see how to simulate these Touch interaction via VC++ code using Touch Injection API.

 

Simulating Tap

By Tap we mean that it has simply touched any portion of screen. In this use case actor takes two action
 

  1. Touch down on screen co-ordinate input
  2. Lifts Up Touch input

To get above done you need to following 5 steps.

1] Create a Win32 application using visual studio 2011 developer preview. ( with No CLR support and without ATL support)

2] In the WinMain Method Initialize the Touch Injection API refer code below.
POINTER_TOUCH_INFO contact;
InitializeTouchInjection(1, TOUCH_FEEDBACK_DEFAULT); // Here number of contact point is declared as 1.
memset(&contact, 0, sizeof(POINTER_TOUCH_INFO));

 

3] Define the contact Point, this definition contains contact type, contact location ,contact area, pressure and orientation .
contact.pointerInfo.pointerType = PT_TOUCH;
contact.pointerInfo.pointerId = 0;          //contact 0
contact.pointerInfo.ptPixelLocation.y = 200; // Y co-ordinate of touch on screen
contact.pointerInfo.ptPixelLocation.x = 300; // X co-ordinate of touch on screen
     
contact.touchFlags = TOUCH_FLAG_NONE;
contact.touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
contact.orientation = 90; // Orientation of 90 means touching perpendicular to screen.
contact.pressure = 32000;

// defining contact area (I have taken area of 4 x 4 pixel)
contact.rcContact.top = contact.pointerInfo.ptPixelLocation.y - 2;
contact.rcContact.bottom = contact.pointerInfo.ptPixelLocation.y + 2;
contact.rcContact.left = contact.pointerInfo.ptPixelLocation.x  - 2;
contact.rcContact.right = contact.pointerInfo.ptPixelLocation.x  + 2;

 

4] Implementing use case 1 , Injecting Touching down on screen.
contact.pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
InjectTouchInput(1, &contact); // Injecting the touch down on screen

 

5] Implementing use case 2 , Injecting Touching Up from screen.
contact.pointerInfo.pointerFlags = POINTER_FLAG_UP;
InjectTouchInput(1, &contact); // Injecting the touch Up from screen

Simulating Hold

 By Hold it mean that Touch is continuously in contact to the screen. In this use case actor takes two action

  • Touches the screen
  • Keep holding the touch at same  place

    To follow the above scenario repeat all 4 steps mentioned in TAP Simulation and then add the below code as last steps

  • Implementing Use case 2 , holding the touch for few second and then lifting the touch up.
    //POINTER_FLAG_UPDATE when use with POINTER_FLAG_INRANGE and POINTER_FLAG_INCONTACT keeps the touch in drag mode with respect to last down Input.

    contact.pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    for(int i=0;i<100000;i++){        //loops for approx. 1 second causing 1 second HOLD effect
    InjectTouchInput(1, &contact);
    }
    contact.pointerInfo.pointerFlags = POINTER_FLAG_UP;       // Moving the touch Up after Hold Complete
    InjectTouchInput(1, &contact);

     

    Simulating Drag

     By Drag it mean that the user has touched down at any Screen co-ordinate and has moved his finger to another co-ordinate. In this use case the actor has three actions.

    1. Touch down at desired co-ordinate
    2. Dragging from last down co-ordinate to some other.
    3. Lifts Touch Up.

    To follow above scenario repeat all 4 steps of TAP Simulation and then add the below code as last step.

  • Implementing use case 2 and 3, wherein we are dragging from one co-ordinate to another and lifting up the touch input. 
    //Setting the Pointer Flag to Drag
    contact.pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    for(int i=0;i<100;i++){
    contact.pointerInfo.ptPixelLocation.x--; // updating the X Co-ordinate to x-100 pixels
    InjectTouchInput(1, &contact);
    }
    // Lifts the touch input UP
    contact.pointerInfo.pointerFlags = POINTER_FLAG_UP;
    InjectTouchInput(1, &contact);

     

    Simulating Pinch/Pan

    By Pinch it means that we inject two contact point and drag both towards each other( Zoom-out) or drag both the contact point apart (Zoom-in). In this use case  actor has to following three actions

    1. Injecting two Touch down contact point simultaneously on the screen.
    2. Drag both points inward/outward with respect to each other.
    3. Lifts up both the touch contact point.

    To get the above scenario done follow the following steps.

    1] Initializing the Touch injection API for implementing multiple(in our case two) contact points
    //Taking two contact points and initializing the Touch API accordingly
    POINTER_TOUCH_INFO contact[2];
    InitializeTouchInjection(2, TOUCH_FEEDBACK_DEFAULT);
    memset(&contact[0], 0, sizeof(POINTER_TOUCH_INFO));
    memset(&contact[1], 0, sizeof(POINTER_TOUCH_INFO));
     
    //Check Pointer Id is taken as 0 for contact 0
    contact[0].pointerInfo.pointerType = PT_TOUCH;
    contact[0].pointerInfo.pointerId = 0;          //Id 0 for contact 0
    contact[0].pointerInfo.ptPixelLocation.y = 200;
    contact[0].pointerInfo.ptPixelLocation.x = 300;
    //Defining Touch flag and touchmask for contact 0
    contact[0].touchFlags = TOUCH_FLAG_NONE;
    contact[0].touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
    contact[0].orientation = 90;
    contact[0].pressure = 32000;
    contact[0].rcContact.top = contact[0].pointerInfo.ptPixelLocation.y - 2;
    contact[0].rcContact.bottom = contact[0].pointerInfo.ptPixelLocation.y + 2;
    contact[0].rcContact.left = contact[0].pointerInfo.ptPixelLocation.x  - 2;
    contact[0].rcContact.right = contact[0].pointerInfo.ptPixelLocation.x  + 2;
     
    //Check Pointer Id is taken as 1 for contact 1
    contact[1].pointerInfo.pointerType = PT_TOUCH;
    contact[1].pointerInfo.pointerId = 1;          //Id 0 for contact 1
    contact[1].pointerInfo.ptPixelLocation.y = 200;
    contact[1].pointerInfo.ptPixelLocation.x = 180;
    //Defining Touch flag and touchmask for contact 1
    contact[1].touchFlags = TOUCH_FLAG_NONE;
    contact[1].touchMask = TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION | TOUCH_MASK_PRESSURE;
    contact[1].orientation = 90;
    contact[1].pressure = 32000;
    contact[1].rcContact.top = contact[1].pointerInfo.ptPixelLocation.y - 2;
    contact[1].rcContact.bottom = contact[1].pointerInfo.ptPixelLocation.y + 2;
    contact[1].rcContact.left = contact[1].pointerInfo.ptPixelLocation.x  - 2;
    contact[1].rcContact.right = contact[1].pointerInfo.ptPixelLocation.x  + 2;

     

    2] Injecting both contact point to Down, Implementing use case 1
    //Implementing two touch down for both array of contact point in one go
    contact[0].pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    contact[1].pointerInfo.pointerFlags = POINTER_FLAG_DOWN | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    InjectTouchInput(2, contact);

     

    3] Dragging both the contact point apart causing he zoom-in , implementing use case 2
    //Setting both the contact point for Drag
    contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    for(int i=0; i<100;i++)
    {
    contact[0].pointerInfo.ptPixelLocation.x =300+i;//Zooming in by dragging apart both contact points w.r.t each other
    contact[1].pointerInfo.ptPixelLocation.x =180-i;
    InjectTouchInput(2, contact);
    }

     

    4] Lifts Up both the contact both contact point to Up, Implementing use case 3
    contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UP;
    contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UP;
    InjectTouchInput(2, contact);

     

    Simulating Rotate

    By rotate it mean that two contact points will be dragged in clock wise or anti-clock wise direction with respect to each other. In this use case again actor has three actions.
    1. Injecting two Touch down contact point simultaneously on the screen.
    2. Drag both points clock wise/ anti-clock wise with respect to each other.
    3. Lifts up both the touch contact points.

    To implement the above scenario repeat all the steps in shown in Pinch Simulation , but change the step 3 to the code shown below.

  • In this step we will rotate the both the touch points to anti-clock wise direction. implementing use case 2
    contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    for(int i=0; i<100;i++)
    {
        // implementing the rotation
        if(i%3==0)
        {
        contact[0].pointerInfo.ptPixelLocation.x -= 3;
        contact[1].pointerInfo.ptPixelLocation.x += 3;
         
        contact[0].pointerInfo.ptPixelLocation.y = 200+i;
        contact[1].pointerInfo.ptPixelLocation.y = 200-i;
        }
        InjectTouchInput(2, contact);
    }

     

    Simulating Cross-Slide

    By Cross-Slide we mean two contact points moves in any one direction with respect to screen, simulating a situation where use puts both his figure to touch any picture and drag it to any direction using both of his fingure. In this use case actor has three action.
    1. Injecting two Touch down contact point simultaneously on the screen.
    2. Drag both points to any 1 direction.
    3. Lifts up both the touch contact points.

    To implement the above scenario repeat all the steps in shown in Pinch Simulation , but change the step 3 to the code shown below

  • Drag Both Touch points to any one direction, implementing use case 2.
    contact[0].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    contact[1].pointerInfo.pointerFlags = POINTER_FLAG_UPDATE | POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT;
    for(int i=0; i<100;i++)
    {   
        contact[0].pointerInfo.ptPixelLocation.y = 200+i;
        contact[1].pointerInfo.ptPixelLocation.y = 200+i;
        InjectTouchInput(2, contact);
    }

     

    References

     

Sort by: Published Date | Most Recent | Most Useful
Comments
  • Wonderful article, I have tried each snippet practically, and have found the successful outputs. Great Work Sanjay. Happy new year :)

  • Thanks nabarun.. happy new year :D

  • Simply awesome!!! More power to you!!!

  • Or you can use MultiTouchVista HID driver to emulate touch input and interact directly.

    multitouchvista.codeplex.com

  • I am surprised that this works.  According to the POINTER_INFO documentation ( msdn.microsoft.com/.../hh454907(v=vs.85).aspx ) in the "sourceDevice" section, it says "The POINTER_INFO source can never be NULL for any form of injected input."  However, you are leaving the sourceDevice as NULL which is against the guidelines of the MSDN documentation.  Is this a bug in the documentation or in your code?

  • Hi Adam,

                   Even in the start when I 1st tried to develop this code, I was having the same confusion, but when i worked out with Reference-1 of this article ( Touch Injection sample at code.msdn.microsoft.com/.../Touch-Injection-Sample-444d9bf7 ), I found the we can comfortably proceed with leaving sourceDevice to unassigned/null.  

    Hmmmm.. I guess the MSDN documents are according to the specs defined prior but the same check is not implemented in the TouchInjection API....  anyways :D

  • Thanks for the response Sanjay.  I found that after you call InitializeTouchInjection, a touch device does show up that advertises the same number of touch points that I pass in to InitializeTouchInjection.  Even if it doesn't matter much, maybe you could change your code to use GetPointerDevices to retrieve a handle to the device so you can inject into it.  That would be more consistent with what MSDN advertises.

  • ya.. we can of course use GetPointerDevices  and use that as input to source device.. but that will be only to please msdn doc ..:D , thanks for your suggestions ;)

  • Great!

    I am working on writing UI automation tool for metro style app (record/playback style). This article would help in playback. Do you have any for recording touch based inputs??

  • Hi Ijazs,

                 Currently I am a bit busy to post other article, but you can tryout yourself by capturing user input and create a link list something like..

    struct TouchCaptured

    {

    int x;

    int y;

    long timeSpan;

    };

    Keep Adding nodes in the link list until you want to record and once recording is completed, log those captured link list in binary format to a text file.

    Now once user clicks the play button simulate the Touch action by reading that text file back and passing the value of "x" and "y" to Touch injection function based on above code and simulation speed based on "timespan" value."

    Try this out.. :D all the best

Page 1 of 3 (29 items) 123