Registering a touch screen HID with RegisterRawInputDevices does not work

1

I am trying to get raw input data from a Surface touch screen, using RAWINPUT API.

Getting the devices list works good. But when I want to register the touch screen device with RegisterRawInputDevices, I have issues : the function returns false with 87 (ERROR_INVALID_PARAMETER) in GetLastError... I have tried different things that I read online but none work.

I am using Interop on C# for very simple desktop console application, developping with Visual Studio 2013 on Windows 8.1. The target is a Surface Pro 3.

The code doing the work with the API is hereunder... (sorry for the ugly editing).

I will be so thanksful for your help :)

Pierre

CLASS for the API wrapping in C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using System.Diagnostics;


namespace ConsoleApplication3
{
    class APIWrapper
    {
        #region Properties
        private static int _vendorID=-1;
        public static int VendorID
        {
            get { return _vendorID; }
        }

        private static int _productID=-1;
        public static int ProductID
        {
            get { return _productID; }
        }
        #endregion

        #region API structs
        internal struct RAWINPUTDEVICELIST_ELMT
        {
            public IntPtr hDevice;
            public uint dwType;
        }

        public enum RawInputDeviceType : uint
        {
            RIM_TYPEMOUSE = 0,
            RIM_TYPEKEYBOARD = 1,
            RIM_TYPEHID = 2,
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTDEVICE
        {
            public ushort usUsagePage;
            public ushort usUsage;
            public int dwFlags;
            public IntPtr hwndTarget;
        }

        public enum RawInputDeviceInfoType : uint
        {
            RIDI_DEVICENAME = 0x20000007,
            RIDI_DEVICEINFO = 0x2000000b,
            RIDI_PREPARSEDDATA = 0x20000005,
        }

        public const ushort RIDEV_INPUTSINK =0x00000100;
        public const ushort RIDEV_PAGEONLY = 0x00000020;

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_HID
        {
            public int dwVendorId;
            public int dwProductId;
            public int dwVersionNumber;
            public ushort usUsagePage;
            public ushort usUsage;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_MOUSE
        {
            public int dwId;
            public int dwNumberOfButtons;
            public int dwSampleRate;
            public bool fHasHorizontalWheel;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RID_DEVICE_INFO_KEYBOARD
        {
            public int dwType;
            public int dwSubType;
            public int dwKeyboardMode;
            public int dwNumberOfFunctionKeys;
            public int dwNumberOfIndicators;
            public int dwNumberOfKeysTotal;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RID_DEVICE_INFO
        {
            [FieldOffset(0)]
            public uint cbSize;
            [FieldOffset(4)]
            public RawInputDeviceType dwType;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_MOUSE mouse;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_KEYBOARD keyboard;
            [FieldOffset(8)]
            public RID_DEVICE_INFO_HID hid;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWINPUTHEADER
        {
            public RawInputDeviceType dwType;
            public int dwSize;
            public IntPtr hDevice;
            public uint wParam;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RAWMOUSE
        {
            [FieldOffset(0)]
            public ushort usFlags;
            [FieldOffset(2)]
            public uint ulButtons;
            [FieldOffset(4)]
            public ushort usButtonFlags;
            [FieldOffset(2)]
            public ushort usButtonData;
            [FieldOffset(6)]
            public uint ulRawButtons;
            [FieldOffset(10)]
            public int lLastX;
            [FieldOffset(14)]
            public int lLastY;
            [FieldOffset(18)]
            public uint ulExtraInformation;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWKEYBOARD
        {
            public ushort MakeCode;
            public ushort Flags;
            public ushort Reserved;
            public ushort VKey;
            public uint Message;
            public uint ExtraInformation;
        }

        [StructLayout(LayoutKind.Sequential)]
        internal struct RAWHID
        {
            public int dwSizeHid;
            public int dwCount;
            //use of a pointer here for struct reason
            public IntPtr pbRawData;
        }

        [StructLayout(LayoutKind.Explicit)]
        internal struct RAWINPUT
        {
            [FieldOffset(0)]
            public RAWINPUTHEADER header;

            [FieldOffset(16 + 8)]
            public RAWMOUSE mouse;

            [FieldOffset(16 + 8)]
            public RAWKEYBOARD keyboard;

            [FieldOffset(16 + 8)]
            public RAWHID hid;
        }
        #endregion

        #region API functions
        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetRawInputDeviceList([In, Out] RAWINPUTDEVICELIST_ELMT[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetRawInputDeviceInfo([In] IntPtr hDevice, [In] RawInputDeviceInfoType uiCommand, [In, Out] IntPtr pData, [In, Out] ref  uint pcbSize);

        [DllImport("user32.dll", SetLastError = true)]
        static extern bool RegisterRawInputDevices(RAWINPUTDEVICE[] pRawInputDevices, uint uiNumDevices, uint cbSize);

        [DllImport("user32.dll")]
        static extern uint GetRegisteredRawInputDevices([In, Out] RAWINPUTDEVICE[] InputdeviceList, [In, Out] ref uint puiNumDevices, [In] uint cbSize);

        [DllImport("user32.dll", SetLastError = true)]
        static extern uint GetRawInputBuffer([In,Out] RAWINPUT[] pData, [In, Out] ref uint pcbSize, [In] uint cbSizeHeader);
        #endregion

        #region Methods for devices
        public static bool GetRawInputDeviceList()
        {
            bool res = false;
            RAWINPUTDEVICELIST_ELMT[] pRawInputDeviceList = null;
            uint puiNumDevices = 0;
            uint returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICELIST_ELMT()));
            res = (0xFFFFFFFF != returnCode);
            if (res)
            {
                //alloc array
                pRawInputDeviceList = new RAWINPUTDEVICELIST_ELMT[puiNumDevices];

                //get devices
                returnCode = GetRawInputDeviceList(pRawInputDeviceList, ref puiNumDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICELIST_ELMT))));
                res = (0xFFFFFFFF != returnCode);
                if (res)
                {
                    //look for the touchscreen.
                    bool foundTouchScreen = false;
                    foreach (RAWINPUTDEVICELIST_ELMT rawInputDevice in pRawInputDeviceList)
                    {

                        //IntPtr pData = IntPtr.Zero;
                        //uint strsize = 0;
                        //IntPtr deviceHandle = rawInputDevice.hDevice;
                        //returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
                        //pData = Marshal.AllocHGlobal((int)strsize);
                        //returnCode = GetRawInputDeviceInfo(deviceHandle, RawInputDeviceInfoType.RIDI_DEVICENAME, pData, ref strsize);
                        ////Console.WriteLine("Result = " + returnCode + " ErrorCode = " + Marshal.GetLastWin32Error());
                        //string name = Marshal.PtrToStringAnsi(pData);
                        //Console.WriteLine("Name = " + name);

                        uint structsize = (uint)Marshal.SizeOf(typeof(RID_DEVICE_INFO));
                        RID_DEVICE_INFO di = new RID_DEVICE_INFO();
                        di.cbSize = structsize;
                        IntPtr pData = Marshal.AllocHGlobal((int)structsize);
                        returnCode = GetRawInputDeviceInfo(rawInputDevice.hDevice, RawInputDeviceInfoType.RIDI_DEVICEINFO, pData, ref structsize);
                        if (0xFFFFFFF != returnCode && 0 != returnCode)
                        {
                            di = (RID_DEVICE_INFO)Marshal.PtrToStructure(pData, typeof(RID_DEVICE_INFO));
                            //Console.WriteLine("di.dwType = " + Enum.GetName(typeof(RawInputDeviceType), di.dwType));
                            switch (di.dwType)
                            {
                                case RawInputDeviceType.RIM_TYPEHID:
                                    /* Console.WriteLine("di.hid.dwVendorId = " + di.hid.dwVendorId);
                                     Console.WriteLine("di.hid.dwProductId = " + di.hid.dwProductId);
                                     Console.WriteLine("di.hid.dwVersionNumber = " + di.hid.dwVersionNumber);
                                     Console.WriteLine("di.hid.usUsagePage = " + di.hid.usUsagePage);
                                     Console.WriteLine("di.hid.usUsage = " + di.hid.usUsage);*/
                                    if (0x0D == di.hid.usUsagePage && 0x04 == di.hid.usUsage)
                                    {
                                        _vendorID = di.hid.dwVendorId;
                                        _productID = di.hid.dwProductId;
                                        foundTouchScreen = true;
                                    }
                                    break;
                                case RawInputDeviceType.RIM_TYPEKEYBOARD:
                                case RawInputDeviceType.RIM_TYPEMOUSE:
                                default:
                                    break;
                            }
                            if (foundTouchScreen)
                            {
                                RAWINPUTDEVICE[] rawInputDevicesToMonitor = new RAWINPUTDEVICE[1];
                                RAWINPUTDEVICE device = new RAWINPUTDEVICE();
                                device.dwFlags =RIDEV_INPUTSINK;
                                device.hwndTarget = Process.GetCurrentProcess().MainWindowHandle;
                                device.usUsage = di.hid.usUsage;
                                device.usUsagePage = di.hid.usUsagePage;
                                rawInputDevicesToMonitor[0] = device;

                                if (!RegisterRawInputDevices(rawInputDevicesToMonitor, (uint)1, (uint)Marshal.SizeOf(new RAWINPUTDEVICE())))
                                {
                                    Console.WriteLine("Registration of device --> NOK (error: " + Marshal.GetLastWin32Error()+")");
                                    RAWINPUTDEVICE [] pRegisteredRawInputDeviceList = null;
                                    uint puiNumRegDevices = 0;
                                    returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf(new RAWINPUTDEVICE()));
                                    res = (0xFFFFFFFF != returnCode);
                                    if (res)
                                    {
                                        //alloc array
                                        pRegisteredRawInputDeviceList = new RAWINPUTDEVICE[puiNumRegDevices];

                                        //get devices
                                        returnCode = GetRegisteredRawInputDevices(pRegisteredRawInputDeviceList, ref puiNumRegDevices, (uint)Marshal.SizeOf((typeof(RAWINPUTDEVICE))));

                                        Console.WriteLine("Registered devices nb : " + returnCode);
                                    }
                                }
                                break;
                            }
                        }
                    }                   
                }
                /*Need to set RIDEV_INPUTSINK in the dwFlags member and set hwndTarget to be able to make use of this function otherwise 
                 * GetRawInputBuffer will ALWAYS say 0 when you try to find out what size you need the buffer to be.
                 */
            }
            /*else
                int error = Marshal.GetLastWin32Error();*/
            return res;
        }
        #endregion

}
}

MAIN CLASS:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace ConsoleApplication3
{
    class Program
    {
        static void Main(string[] args)
        {
            //look for the touch screen device
            if (!APIWrapper.GetRawInputDeviceList())
            {
                Console.WriteLine("Error occured when getting RawInputDevice List.");
            }
            if (APIWrapper.VendorID == -1 && APIWrapper.ProductID == -1)
            {
                Console.WriteLine("No Touchscreen device has been found.");
            }
            else
            {
                Console.WriteLine("Touchscreen found : VendorID=" + APIWrapper.VendorID + " ProductID=" + APIWrapper.ProductID);
                //wait for rawinputdata
                Console.WriteLine("Waiting data loop : started.");
                uint dataNb = APIWrapper.ReadHIDData();
                switch (dataNb)
                {
                    case 0xFFFFFFFF:
                        Console.WriteLine("An error occured.");
                        break;
                    case 0:
                        Console.WriteLine("No data received.");
                        break;
                    default:
                        Console.WriteLine(dataNb + " rawInputData received");
                        break;
                }
                Console.WriteLine("Waiting data loop : ended.");
            }
            Console.ReadLine();
        }
    }
}
c#
windows-8.1
touchscreen
raw-input
asked on Stack Overflow Jan 9, 2015 by Pierre • edited Jan 12, 2015 by Pierre

1 Answer

0

User contributions licensed under CC BY-SA 3.0