Windows 8 introduces input via multiple touch points. In the DrawIt sample of my book “Modern C++ and Windows Store apps”, I show how to add free form drawing on a XAML SwapChainBackgroundPanel using either touch, mouse or pen inputs. The sample restricted input to a single pointer i.e. you could draw using a finger or with left mouse button down or with a stylus if your device supported one. In today’s post, I will show how to move from a single pointer to supporting multiple pointers (restricted only by the number of touch points supported by the underlying hardware).
The DrawIt sample has two main classes: MainPage and ShapeRenderer. All of the changes I am about to make below are in the ShapeRenderer class.
- The only change to MainPage is to add support for the PointerEntered event which in turn calls the corresponding method from ShapeRenderer.
- I will also add an overlay to the code to show Pointer touch point properties like PointerId, the point where the touch occurs etc. These changes are also in ShapeRenderer
- In the sample I enclose below, I have removed support for erasing. You are free to add it back as an exercise.
Handling Multiple Pointers
Open the ShapeRenderer header file. Add a private member variable of type Platform::Collections::Map.
Platform::Collections::Map<UINT, Windows::UI::Xaml::Input::Pointer^>^ m_PointerContact;
Add another private variable of type UINT.
- These two variables will be used to keep track of the multiple pointers that can be used to draw on screen.
Add a function declaration for OnPointerEntered in the ShapeRenderer class. The ShapeRenderer class already has methods for OnPointerPressed, OnPointerReleased etc.
void OnPointerEntered(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args);
In the ShapeRenderer constructor, initialize the map as follows:
m_PointerContact = ref new Map<UINT, Pointer^>();
- In the implementation for OnPointerEntered method, we will use the following logic. If the pointer that fires the “Entered” event exists in our map, we do nothing. Else we store the new pointer details in the map, increment the number of active pointer count and begin drawing.
- Next we call the Render method of the SwapChain.
- Similarly in the OnPointerPressed event handler, we check if the pointer exists in our saved collection. If yes, do nothing. Else proceed to drawing.
- In the OnPointerReleased event handler, call EndStroke of the InkManager and then Render the strokes.
- After the Render call, remove the released pointer details from the collection and decrement the active pointer count.
- That is all there is to handling multiple pointers.
Creating an overlay while drawing
Add three new methods to the ShapeRenderer header file.
void UpdateInfoPop(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
void DestroyInfoPop(Windows::UI::Xaml::Input::Pointer^ ptr);
void CreateInfoPop(Windows::UI::Xaml::Input::PointerRoutedEventArgs^ e);
- The logic to create the popup is simple. In the CreateInfoPop method, we create a TextBlock. Get the current touch point details and add the pointer details to the TextBlock. Apply a RenderTransform on the TextBlock by creating a TranslateTransform and offset the TextBlock position by 20 pixels from the point where the pointer is on screen. This allows the TextBlock to be visible and display contents.
- The UpdateInfoPop is used to move the TextBlock as the pointer moves on the screen. Check for all children of the SwapChain that matches the TextBlock control type and then use the name property to zero on the right pointer. Once the right pointer is identified, update the TextBlock position to the new position as determined by the pointer point.
That is all there is to adding information overlay to a pointer move event. The sample code is attached. Download the code and let me know your thoughts!