Windows 8 Touch Support

Hello;
In a near future I’ll need to make a small game for Windows 8.1 with a Touch Monitor plugged in,
for exemple the Iiyama ProLite T2435MSC.
It seems that Unity does not recognize multitouch at all in that case.

I would like to use things like Input.touchCount or Input.GetTouch(0) because I want to be able to create those little bits by myself :slight_smile:

I hope somebody can give me some information on that, otherwise I’ll need to install BlueStacks on those computers and try to compile for Android to support Unity’s Touch.

Thank you. :slight_smile:

Multi-Touch

I’m trying really hard to understand how to make this work but it seems that I can’t.
He used an older version of Visual Studio and I can’t find a way to create a project like he did.
I tried to get his files but Unity said that it expected 64 bit but found IMAGE_FILE_MACHINEI386.

I’m used to code logic in Unity, I have to admit that I’m lost outside of it.
It’s the last day I have to test the Touch Monitor. I need to make it work.
I need some guidance. :frowning:

Thank you.

[EDIT] I think I made the DLL correctly, but Unity does not seem to find it (I put it in Plugins folder).
When I copy it in the root folder it fixes it but I get a “EntryPointNotFoundException: GetTouchPointCount”.

Here is the script, based on the script made by the guy from your link:
C# Script

using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;

//using System.Diagnostics;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class tTouchData
{
    public int m_x;
    public int m_y;
    public int m_ID;
    public int m_Time;
};

[StructLayout(LayoutKind.Sequential, Pack = 1)]

public class Gentil : MonoBehaviour
{

    public bool m_Initialised;
    [DllImport("TouchOverlay", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    public static extern int Initialise(string Str);

    [DllImport("TouchOverlay")]
    public static extern int GetTouchPointCount();
    [DllImport("TouchOverlay")]
    public static extern void GetTouchPoint(int i, tTouchData n);


    void Start()
    {
        m_Initialised = false;
    }


    void Update()
    {
        int test = GetTouchPointCount();
        Debug.Log(test);
    }

And here is the DLL:

DLL

//--------------------------------------------------------------------------------------
// Copyright 2011 Intel Corporation
// All Rights Reserved
//
// Permission is granted to use, copy, distribute and prepare derivative works of this
// software for any purpose and without fee, provided, that the above copyright notice
// and this statement appear in all copies.  Intel makes no representations about the
// suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
// assume any responsibility for any errors which may appear in this software nor any
// responsibility to update it.
//--------------------------------------------------------------------------------------

#include "windows.h"
#include "windowsx.h"
#include "CommCtrl.h"
#include "stdio.h"

// Avoid Name Mangling
extern "C"
{

// Global Handles
HWND g_hRemoteWnd;
HINSTANCE g_hInst;
HHOOK g_HookPosted = NULL;
HHOOK g_HookCalled = NULL;

#define MAX_TOUCH 128

// Storage for touch tracking
struct tTouchData
{
   int m_x;
   int m_y;
   int m_ID;
   int m_Time;
};

tTouchData g_TouchData[MAX_TOUCH];
tTouchData g_CopyTouchPoints[MAX_TOUCH];

// Clear all to -1 IDs at start
void ClearData()
{
   for (int i=0;i<MAX_TOUCH;i++)
   {
     g_TouchData[i].m_ID = -1;
   }
}

// On Touch function - from MSDN somewhere
// Added code to store touch info into global storage
// WARNING - ERRORS NOT HANDLED!!!!!
LRESULT OnTouch(HWND hWnd, WPARAM wParam, LPARAM lParam )
{
   BOOL bHandled = FALSE;
   UINT cInputs = LOWORD(wParam);
   PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
   if (pInputs)
   {
     if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT)))
     {
       for (UINT i=0; i < cInputs; i++)
       {
         TOUCHINPUT ti = pInputs[i];

         if (ti.dwFlags & TOUCHEVENTF_DOWN)   // Add to list
         {
           for (int p=0;p<MAX_TOUCH;p++)
           {
             if (g_TouchData[p].m_ID == -1)
             {
               g_TouchData[p].m_ID = ti.dwID;
               g_TouchData[p].m_x = ti.x;
               g_TouchData[p].m_y = ti.y;
               g_TouchData[p].m_Time = ti.dwTime;
               break;
             }
           }
         }
         if (ti.dwFlags & TOUCHEVENTF_UP)   // Remove from list
         {
           for (int p=0;p<MAX_TOUCH;p++)
           {
             if (g_TouchData[p].m_ID == ti.dwID)
             {
               g_TouchData[p].m_ID = -1;
               break;
             }
           }
         }
         if (ti.dwFlags & TOUCHEVENTF_MOVE)   // Move point
         {
           for (int p=0;p<MAX_TOUCH;p++)
           {
             if (g_TouchData[p].m_ID == ti.dwID)
             {
               g_TouchData[p].m_x = ti.x;
               g_TouchData[p].m_y = ti.y;
               g_TouchData[p].m_Time = ti.dwTime;
               break;
             }
           }
         }
       }   
       bHandled = TRUE;
     }
     else
     {
       /* handle the error here */
     }
     delete [] pInputs;
   }
   else
   {
     /* handle the error here, probably out of memory */
   }
   if (bHandled)
   {
     // if you handled the message, close the touch input handle and return
     CloseTouchInputHandle((HTOUCHINPUT)lParam);
     return 0;
   }
   else
   {
     // if you didn't handle the message, let DefWindowProc handle it
     return DefWindowProc(hWnd, WM_TOUCH, wParam, lParam);
   }
}


// Hook prok to capture calls to Unity Window function by System
LRESULT HookProcCalled(int code, WPARAM wParam, LPARAM lParam)
{
   CWPSTRUCT *Msg = (CWPSTRUCT *)lParam;
   if (code >= 0)
   {
     if (Msg->hwnd == g_hRemoteWnd)
     {
       switch (Msg->message)
       {
       case WM_TOUCH:
         OnTouch(Msg->hwnd, Msg->wParam, Msg->lParam);
         break;
       }
     }
   }
   // Always call this - we dont actually "Use" any of the messages
   return CallNextHookEx(0, code, wParam, lParam);
}


// Hook prok to capture messages Posted to Unity Window
LRESULT HookProcPosted(int code, WPARAM wParam, LPARAM lParam)
{
   MSG *Msg = (MSG *)lParam;
   if (code >= 0)
   {
     if (Msg->hwnd == g_hRemoteWnd)
     {
       switch (Msg->message)
       {
       case WM_TOUCH:
         OnTouch(Msg->hwnd, Msg->wParam, Msg->lParam);
         break;
       }
     }
   }
   // Always call this - we dont actually "Use" any of the messages
   return CallNextHookEx(0, code, wParam, lParam);
}
struct tWindowData
{
   char *pName;
   HWND Handle;
};

// loop through the Windows on the desktop,
// Stop when we find the Unity Window
BOOL CALLBACK EnumWindowsFunc(
  _In_  HWND hwnd,
  _In_  LPARAM lParam
)
{
   tWindowData *pData = (tWindowData *)lParam;
   char NewName[128];
   GetWindowText(hwnd, NewName, 128);
   if (!strcmp(pData->pName, NewName))
   {
     pData->Handle = hwnd;
     return false;
   }
   return true;

}

__declspec(dllexport) void __cdecl Test(int Val)
{
   char Str[128];
   sprintf(Str, "Test: Received %d\n", Val);
   OutputDebugString(Str);
}
__declspec(dllexport) void __cdecl Test2(int Val)
{
   char Str[128];
   sprintf(Str, "Test2: Received %d\n", Val);
   OutputDebugString(Str);
}

// exported func to set up the hook
// NOTE: Currently assuming WCHAR array comming from Unity.
// Earlier versions used char arrays.  For older versions of Unity convert to char * by
// WindowData.pName to the parameter instead of converting
// or do something cleverer!
__declspec(dllexport) int __cdecl Initialise(WCHAR *PName)
{
   char Str[128];
   int Len = lstrlenW(PName);
   WideCharToMultiByte(CP_ACP, 0, PName, Len, Str, 127, NULL, NULL);
   Str[Len] = 0;

   tWindowData WindowData;
   WindowData.pName = Str;
   WindowData.Handle = NULL;
   EnumDesktopWindows(NULL, EnumWindowsFunc, (LPARAM)&WindowData);
   if (WindowData.Handle == NULL)
     return -1;
   g_hRemoteWnd = WindowData.Handle;

   // Get thread ID for Unity window
   DWORD ProcessID;
   int ID = GetWindowThreadProcessId(g_hRemoteWnd, &ProcessID);  
   if (ID == 0)
     return -2;

   // Set the Hooks
   // One for Posted Messages
   g_HookPosted = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProcPosted, g_hInst, ID);
   if (g_HookPosted == NULL)
   {
     return -3;
   }

   // One hook for System calls (Win8)
   g_HookCalled = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)HookProcCalled, g_hInst, ID);
   if (g_HookCalled == NULL)
   {
     UnhookWindowsHookEx(g_HookPosted);
     return -4;
   }

   // Setup our data
   ClearData();   

   // Register the Unity window for touch
   int Res = RegisterTouchWindow(g_hRemoteWnd, TWF_WANTPALM);
   if (Res == 0)
   {
     UnhookWindowsHookEx(g_HookPosted);
     UnhookWindowsHookEx(g_HookCalled);
     return -5;
   }
   return 0;
}

__declspec(dllexport) void __cdecl ShutDown(char *PName)
{
   UnhookWindowsHookEx(g_HookPosted);
   UnhookWindowsHookEx(g_HookCalled);
}

// Fairly self explanatory exported funcs

__declspec(dllexport) void __cdecl GetTouchPoint(int i, tTouchData *p)
{
   *p = g_CopyTouchPoints[i];
}

__declspec(dllexport) int __cdecl GetTouchPointCount()
{
   int NumPoints = 0;
   for (int i=0;i<MAX_TOUCH;i++)
   {
     if (g_TouchData[i].m_ID != -1)
     {
       g_CopyTouchPoints[NumPoints] = g_TouchData[i];
       NumPoints++;
     }
   }
   return NumPoints;
}

BOOL APIENTRY DllMain( HMODULE hModule,
  DWORD  ul_reason_for_call,
  LPVOID lpReserved
            )
{
   g_hInst = hModule;
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:
   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
   case DLL_PROCESS_DETACH:
     break;
   }
   return TRUE;
}

}

You need to initialize first

        if(!this.m_initialize) {
            if(Initialise("PROJECT NAME OR ANYTHING") < 0) {
                // An error happened
            } else {
                this.m_initialize = true;
            }
        }

        if(this.m_initialize) {
            // Check inputs
        }

You want to wait before you initialize the DLL so I suggest you put it into a Coroutine and wait 0.5 seconds then try to initialze it

I’m going to try this as soon as I can.
Thank you for your help.

[EDIT]
Script

    void Start()
    {
        m_Initialised = false;
        StartCoroutine(Initialise());
    }

    void Update()
    {
        if (m_Initialised)
        {
            int test = GetTouchPointCount();
            Debug.Log(test);
        }
    }
  private IEnumerator Initialise()
  {
  yield return new WaitForSeconds(2f);
  string Str;
  //int NumTouch = 0;
      if (!m_Initialised)
      {
          Str = "New Unity Project";
          if (Initialise(Str) < 0)    //error is here
          {
              // ERROR STATE
          }
          else
          {
              m_Initialised = true;
          }
      }
  }

I must have done something really dumb at some point… I don’t know what, I allways get that error. Maybe I didn’t make the Dll correctly? This is my first time having to deal with them.

I tried to follow what was said here:
https://software.intel.com/en-us/blogs/2013/05/01/the-unity-multi-touch-source-finally
I did not reference UnityEngine.Dll I just created a new empty project, placed the DLLMAIN.cppn prefer 32 bit is not ticked and I have visual studio set for release.
I tried to copy paste the dll alone, dll + pdb. In Plugins and in root.

[EDIT 2]
I have a suggestion, if you build the dll, upload it and explain how you did it step by step, that would get out of the way any error that I could have done in Visual Studio.
I know that sounds like asking too much but I need to see if I did a mistake in order to avoid doing it again. I keep searching everywhere but I am lost.

I’ll explain what this problem implies for me IRL.
I’ve been working with a company multiple time and they want to work with me again to make some apps.

Now they need big touch monitors and multitouch. I make games around specific jobs to help the youth discover them through funny games and activities.

If I can’t make Unity support multitouch, I’ll surely lose the job and those that are coming behind it.
I know how to code into Unity, but I can’t even go to that point because of this problem.

I really need help.
I’m thankful for any help provided

Hello.
I took a little break and tried again.
I was doing a lot of mistakes with the Dll build.
Everything should work fine now in Unity, but I can’t test it because I do not have the touchscreen anymore.
When I get the confirmation that it works or not, I’ll come back.

[Edit]
It is working very well on windows 10 but not on win 8.1.
My main win10 computer works with both builds (I made a 32bits dll and a 64 and made 2 unity builds one in x86 with the dll set up in unity as x84 and the other one x86_x64 with the dll set up in unity as x86_x86).

Fallback handler could not load library.
I’m really close to have everything working. Any idea?

[Edit 2]

Everything is working correctly.
I’ll probably make a new thread explaining how I did it. I’m sure some people had trouble with that before me.