Microsoft introduced the InkCanvas into the Universal Windows Platform as a way of apps leveraging the power of ink with devices like the Surface Pro’s and Surface Hub being quite well-known for their use of the pen.

When it comes to devices like the Surface Hub, these are capable of multi-user interactions using touch and pen meaning that a user can be doing something at the left hand side of the screen while another is working on the right, such as, annotating using pen on a map or a OneNote collaboration.

For developers, this is not an out-of-the-box property that you can just turn on in the InkCanvas control however. You need to go a little deeper and start customizing the properties of the InkPresenter which is used to render the ink you see on the InkCanvas.

How to enable multi-user input on the InkCanvas

When your page loads, you’re going to want to change a couple of properties on your InkCanvas’s InkPresenter to get started with this.

First, enable the input types you want your drawing canvas to support as follows:

I’ve provided two options to show how this works, you don’t have to use both in your own code.

So now we have a way of manipulating ink on the InkCanvas. Now it’s time to enable multi-user input inking.

To do this, we need to enable custom drying first. We do this so that we can overwrite the default drying method used by the InkPresenter which turns the wet ink that you’re currently drawing into dry ink when you’ve stopped. Doing this will allow us to set the property that allows multi-user input. You can do this as follows:

And there you go. If you now run your application, you can start using multiple fingers to draw on the InkCanvas if you have touch enabled, or if you’re working with the Surface Hub, you can now pick up both pens and start drawing simultaneously!

Join the discussion 5 Comments

  • Michael White says:

    This used to work back at the end of 2016 in a application I created based on the Windows SimpleInk sample, but after several Windows updates (1607 to 1709) whenever I touch down with a finger followed by a pen the pen is “lost”, i.e. I get a PointerLost callback from the CoreInkIndependentInputSource. I then see the stylus input cursor floating about over the canvas making no lines. When I lift the stylus I receive a PointerReleasing callback as expected. Is there something else I need to do to re-enable simultaneous pen & touch?

  • Kruthi M says:

    This works, I am able to support multiple pens in my UWP app.
    However, what would I need to do if I need each pen to have its own unique settings in a “Paint”-like app? Something like one pen draws with a black ink setting, and another one draws with a pink ink setting. Can I do that using a single InkCanvas?

    • James Croft says:

      It is possible to do this on the Surface Hub because it is possible to get unique identifiers for each of the Surface Hub pens. However, on a Surface tablet/laptop, I’m still yet to find a way to retrieve a unique identifier for the pens which makes it a little more difficult to track the ink for both. I can write up another blog post on how to do this for Hub though.

      Apologies for the delay in response!

      • Christina says:

        So how to do this on Surface Hub? How can i get an unique identifier for every pen?

        • James Croft says:

          The below extension method will allow you to check whether your input pointer is from a Surface Hub pen.

          /// <summary>
          /// Detects whether the given <see cref="PointerPoint"/> is a Surface Hub pen.
          /// </summary>
          /// <param name="pointerPoint">
          /// The pointer point to check.
          /// </param>
          /// <returns>
          /// Returns true if is a Surface Hub pen; else false.
          /// </returns>
          public static bool IsSurfaceHubPen(this PointerPoint pointerPoint)
              return pointerPoint.Properties.HasUsage(0x0D, 0x5b);

          Calling the below code will get you the pen ID.

          int pointerId = pointerPoint.Properties.GetUsageValue(0x0D, 0x5b);

          I’ll make sure to write up a post on this.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.