2

In case multiple screens are connected to a computer, I'd like to show an application on a touchscreen. By iterating over System.Windows.Forms.Screen.AllScreens I can get the WorkingArea in order to move the window. However, Screen doesn't provide a IsTouchscreen method.

On the other hand by iterating over all System.Windows.Input.Tablet.TabletDevices I am unable to find the corresponding Screen, because Screen.DeviceName doesn't match TabletDevice.Name.

So is there a way to somehow match a Screenwith a TabletDevice or is there another workaround I could use?

Pedro
  • 4,100
  • 10
  • 58
  • 96
  • possible duplicate of [Is it possible to let my c# wpf program know if the user has a touchscreen or not?](http://stackoverflow.com/questions/5673556/is-it-possible-to-let-my-c-sharp-wpf-program-know-if-the-user-has-a-touchscreen) – Liam Mar 23 '15 at 16:11
  • Or [Is there a way to programmatically tell if a system is touch enabled?](http://stackoverflow.com/questions/5957751/is-there-a-way-to-programmatically-tell-if-a-system-is-touch-enabled) – Liam Mar 23 '15 at 16:13
  • 1
    I don't think it's a duplicate of either, @Pedro doesn't just want to know if there are touch screens available. He wants to know which, if any of the connected screens are touch screens. – James MacGilp Mar 23 '15 at 16:18

2 Answers2

7

This information is available, the low-level COM interfaces that WPF uses are documented in this MSDN article. A disclaimer is however appropriate, Microsoft doesn't like you to use them. The interface documentation warns "Developers should not use this interface", otherwise without any obvious reason why that's good advice. If Microsoft really wants to prevent us from using it then it would be much simpler to just not document them.

And there's something funky going on with the ITablet2::GetMatchingScreenRect() function, the one you are looking for, the documentation for it missing. In itself a possible reason that this info is not exposed by WPF. So caution is necessary, you do need to test it thoroughly on the hardware you want to use it on. I don't have any to verify.

I wrote some code that uses these interfaces. Add a new class to your project and paste the code shown below. You need to add a reference to System.Drawing.

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Text;

public enum TouchDeviceKind { Mouse, Pen, Touch }

public class TouchTabletCollection {
    public TouchTabletCollection() {
        Guid CLSID_TabletManager = new Guid("A5B020FD-E04B-4e67-B65A-E7DEED25B2CF");
        var manager = (ITabletManager)Activator.CreateInstance(Type.GetTypeFromCLSID(CLSID_TabletManager));
        int count = 0;
        manager.GetTabletCount(out count);
        Count = count;
        tablets = new List<TouchTablet>(count);
        for (int index = 0; index < count; index++) {
            tablets.Add(new TouchTablet(manager, index));
        }
    }
    public int Count { get; private set; }
    public TouchTablet this[int index] {
        get { return tablets[index]; }
    }
    private List<TouchTablet> tablets;
}

public class TouchTablet {
    internal TouchTablet(ITabletManager mgr, int index) {
        ITablet itf;
        mgr.GetTablet(index, out itf);
        device1 = itf;
        device2 = (ITablet2)itf;
        device3 = (ITablet3)itf;
    }
    public bool IsMultiTouch {
        get {
            bool multi;
            device3.IsMultiTouch(out multi);
            return multi;
        }
    }
    public TouchDeviceKind Kind {
        get {
            TouchDeviceKind kind;
            device2.GetDeviceKind(out kind);
            return kind;
        }
    }
    public string Name {
        get {
            IntPtr pname;
            device1.GetName(out pname);
            return Marshal.PtrToStringUni(pname);
        }
    }
    public Rectangle InputRectangle {
        get {
            RECT rc;
            device1.GetMaxInputRect(out rc);
            return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom);
        }
    }
    public Rectangle ScreenRectangle {
        get {
            RECT rc;
            device2.GetMatchingScreenRect(out rc);
            return Rectangle.FromLTRB(rc.Left, rc.Top, rc.Right, rc.Bottom);
        }
    }
    private ITablet device1;
    private ITablet2 device2;
    private ITablet3 device3;
}

// COM declarations
[ComImport, Guid("764DE8AA-1867-47C1-8F6A-122445ABD89A")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITabletManager {
    void GetDefaultTablet(out ITablet table);
    void GetTabletCount(out int count);
    void GetTablet(int index, out ITablet tablet);
    // rest omitted...
}
[ComImport, Guid("1CB2EFC3-ABC7-4172-8FCB-3BC9CB93E29F")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITablet {
    void Dummy1();
    void Dummy2();
    void GetName(out IntPtr pname);
    void GetMaxInputRect(out RECT inputRect);
    void GetHardwareCaps(out uint caps);
    // rest omitted
}
[ComImport, Guid("C247F616-BBEB-406A-AED3-F75E656599AE")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITablet2 {
    void GetDeviceKind(out TouchDeviceKind kind);
    void GetMatchingScreenRect(out RECT rect);
}
[ComImport, Guid("AC0E3951-0A2F-448E-88D0-49DA0C453460")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface ITablet3 {
    void IsMultiTouch(out bool multi);
    void GetMaximumCursors(out int cursors);
}

internal struct RECT { public int Left, Top, Right, Bottom; }

A sample program that uses it:

using System;

class Program {
    static void Main(string[] args) {
        var tablets = new TouchTabletCollection();
        for (int ix = 0; ix < tablets.Count; ++ix) {
            Console.WriteLine("Found tablet {0} named {1}", ix + 1, tablets[ix].Name);
            Console.WriteLine("  Type = {0}, Multi-touch supported = {1}", tablets[ix].Kind, tablets[ix].IsMultiTouch);
            Console.WriteLine("  Input rectangle  = {0}", tablets[ix].InputRectangle);
            Console.WriteLine("  Screen rectangle = {0}", tablets[ix].ScreenRectangle);
        }
        Console.ReadLine();
    }
}

Note that Windows 7 or higher is required. The output on my touch-ignorant laptop:

Found tablet 1 named \\.\DISPLAY1
  Type = Mouse, Multi-touch supported = False
  Input rectangle  = {X=0,Y=0,Width=1440,Height=900}
  Screen rectangle = {X=0,Y=0,Width=1440,Height=900}
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
1

have you tried.

 public bool HasTouchInput()
    {
        foreach (TabletDevice tabletDevice in Tablet.TabletDevices)
        {
            //Only detect if it is a touch Screen 
            if(tabletDevice.Type == TabletDeviceType.Touch)
                return true;
        }

        return false;
    }

Try this Link

Or try This

var isTouchDevice = Tablet.TabletDevices.Cast<TabletDevice>().Any(dev => dev.Type == TabletDeviceType.Touch);

this is might also help

Daniel Frausto
  • 113
  • 1
  • 1
  • 15