Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

Windows 8 Touch Support

Discussion in 'Scripting' started by Dimlos, Dec 10, 2015.

  1. Dimlos

    Dimlos

    Joined:
    Aug 13, 2014
    Posts:
    51
    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 :)

    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. :)
     
  2. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
  3. Dimlos

    Dimlos

    Joined:
    Aug 13, 2014
    Posts:
    51
    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. :(

    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:
    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System;
    4. using System.Runtime.InteropServices;
    5.  
    6. //using System.Diagnostics;
    7.  
    8. [StructLayout(LayoutKind.Sequential, Pack = 1)]
    9. public class tTouchData
    10. {
    11.     public int m_x;
    12.     public int m_y;
    13.     public int m_ID;
    14.     public int m_Time;
    15. };
    16.  
    17. [StructLayout(LayoutKind.Sequential, Pack = 1)]
    18.  
    19. public class Gentil : MonoBehaviour
    20. {
    21.  
    22.     public bool m_Initialised;
    23.     [DllImport("TouchOverlay", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
    24.     public static extern int Initialise(string Str);
    25.  
    26.     [DllImport("TouchOverlay")]
    27.     public static extern int GetTouchPointCount();
    28.     [DllImport("TouchOverlay")]
    29.     public static extern void GetTouchPoint(int i, tTouchData n);
    30.  
    31.  
    32.     void Start()
    33.     {
    34.         m_Initialised = false;
    35.     }
    36.  
    37.  
    38.     void Update()
    39.     {
    40.         int test = GetTouchPointCount();
    41.         Debug.Log(test);
    42.     }

    And here is the DLL:

    Code (CSharp):
    1.  
    2. //--------------------------------------------------------------------------------------
    3. // Copyright 2011 Intel Corporation
    4. // All Rights Reserved
    5. //
    6. // Permission is granted to use, copy, distribute and prepare derivative works of this
    7. // software for any purpose and without fee, provided, that the above copyright notice
    8. // and this statement appear in all copies.  Intel makes no representations about the
    9. // suitability of this software for any purpose.  THIS SOFTWARE IS PROVIDED "AS IS."
    10. // INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
    11. // INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
    12. // INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
    13. // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  Intel does not
    14. // assume any responsibility for any errors which may appear in this software nor any
    15. // responsibility to update it.
    16. //--------------------------------------------------------------------------------------
    17.  
    18. #include "windows.h"
    19. #include "windowsx.h"
    20. #include "CommCtrl.h"
    21. #include "stdio.h"
    22.  
    23. // Avoid Name Mangling
    24. extern "C"
    25. {
    26.  
    27. // Global Handles
    28. HWND g_hRemoteWnd;
    29. HINSTANCE g_hInst;
    30. HHOOK g_HookPosted = NULL;
    31. HHOOK g_HookCalled = NULL;
    32.  
    33. #define MAX_TOUCH 128
    34.  
    35. // Storage for touch tracking
    36. struct tTouchData
    37. {
    38.    int m_x;
    39.    int m_y;
    40.    int m_ID;
    41.    int m_Time;
    42. };
    43.  
    44. tTouchData g_TouchData[MAX_TOUCH];
    45. tTouchData g_CopyTouchPoints[MAX_TOUCH];
    46.  
    47. // Clear all to -1 IDs at start
    48. void ClearData()
    49. {
    50.    for (int i=0;i<MAX_TOUCH;i++)
    51.    {
    52.      g_TouchData[i].m_ID = -1;
    53.    }
    54. }
    55.  
    56. // On Touch function - from MSDN somewhere
    57. // Added code to store touch info into global storage
    58. // WARNING - ERRORS NOT HANDLED!!!!!
    59. LRESULT OnTouch(HWND hWnd, WPARAM wParam, LPARAM lParam )
    60. {
    61.    BOOL bHandled = FALSE;
    62.    UINT cInputs = LOWORD(wParam);
    63.    PTOUCHINPUT pInputs = new TOUCHINPUT[cInputs];
    64.    if (pInputs)
    65.    {
    66.      if (GetTouchInputInfo((HTOUCHINPUT)lParam, cInputs, pInputs, sizeof(TOUCHINPUT)))
    67.      {
    68.        for (UINT i=0; i < cInputs; i++)
    69.        {
    70.          TOUCHINPUT ti = pInputs[i];
    71.  
    72.          if (ti.dwFlags & TOUCHEVENTF_DOWN)   // Add to list
    73.          {
    74.            for (int p=0;p<MAX_TOUCH;p++)
    75.            {
    76.              if (g_TouchData[p].m_ID == -1)
    77.              {
    78.                g_TouchData[p].m_ID = ti.dwID;
    79.                g_TouchData[p].m_x = ti.x;
    80.                g_TouchData[p].m_y = ti.y;
    81.                g_TouchData[p].m_Time = ti.dwTime;
    82.                break;
    83.              }
    84.            }
    85.          }
    86.          if (ti.dwFlags & TOUCHEVENTF_UP)   // Remove from list
    87.          {
    88.            for (int p=0;p<MAX_TOUCH;p++)
    89.            {
    90.              if (g_TouchData[p].m_ID == ti.dwID)
    91.              {
    92.                g_TouchData[p].m_ID = -1;
    93.                break;
    94.              }
    95.            }
    96.          }
    97.          if (ti.dwFlags & TOUCHEVENTF_MOVE)   // Move point
    98.          {
    99.            for (int p=0;p<MAX_TOUCH;p++)
    100.            {
    101.              if (g_TouchData[p].m_ID == ti.dwID)
    102.              {
    103.                g_TouchData[p].m_x = ti.x;
    104.                g_TouchData[p].m_y = ti.y;
    105.                g_TouchData[p].m_Time = ti.dwTime;
    106.                break;
    107.              }
    108.            }
    109.          }
    110.        }  
    111.        bHandled = TRUE;
    112.      }
    113.      else
    114.      {
    115.        /* handle the error here */
    116.      }
    117.      delete [] pInputs;
    118.    }
    119.    else
    120.    {
    121.      /* handle the error here, probably out of memory */
    122.    }
    123.    if (bHandled)
    124.    {
    125.      // if you handled the message, close the touch input handle and return
    126.      CloseTouchInputHandle((HTOUCHINPUT)lParam);
    127.      return 0;
    128.    }
    129.    else
    130.    {
    131.      // if you didn't handle the message, let DefWindowProc handle it
    132.      return DefWindowProc(hWnd, WM_TOUCH, wParam, lParam);
    133.    }
    134. }
    135.  
    136.  
    137. // Hook prok to capture calls to Unity Window function by System
    138. LRESULT HookProcCalled(int code, WPARAM wParam, LPARAM lParam)
    139. {
    140.    CWPSTRUCT *Msg = (CWPSTRUCT *)lParam;
    141.    if (code >= 0)
    142.    {
    143.      if (Msg->hwnd == g_hRemoteWnd)
    144.      {
    145.        switch (Msg->message)
    146.        {
    147.        case WM_TOUCH:
    148.          OnTouch(Msg->hwnd, Msg->wParam, Msg->lParam);
    149.          break;
    150.        }
    151.      }
    152.    }
    153.    // Always call this - we dont actually "Use" any of the messages
    154.    return CallNextHookEx(0, code, wParam, lParam);
    155. }
    156.  
    157.  
    158. // Hook prok to capture messages Posted to Unity Window
    159. LRESULT HookProcPosted(int code, WPARAM wParam, LPARAM lParam)
    160. {
    161.    MSG *Msg = (MSG *)lParam;
    162.    if (code >= 0)
    163.    {
    164.      if (Msg->hwnd == g_hRemoteWnd)
    165.      {
    166.        switch (Msg->message)
    167.        {
    168.        case WM_TOUCH:
    169.          OnTouch(Msg->hwnd, Msg->wParam, Msg->lParam);
    170.          break;
    171.        }
    172.      }
    173.    }
    174.    // Always call this - we dont actually "Use" any of the messages
    175.    return CallNextHookEx(0, code, wParam, lParam);
    176. }
    177. struct tWindowData
    178. {
    179.    char *pName;
    180.    HWND Handle;
    181. };
    182.  
    183. // loop through the Windows on the desktop,
    184. // Stop when we find the Unity Window
    185. BOOL CALLBACK EnumWindowsFunc(
    186.   _In_  HWND hwnd,
    187.   _In_  LPARAM lParam
    188. )
    189. {
    190.    tWindowData *pData = (tWindowData *)lParam;
    191.    char NewName[128];
    192.    GetWindowText(hwnd, NewName, 128);
    193.    if (!strcmp(pData->pName, NewName))
    194.    {
    195.      pData->Handle = hwnd;
    196.      return false;
    197.    }
    198.    return true;
    199.  
    200. }
    201.  
    202. __declspec(dllexport) void __cdecl Test(int Val)
    203. {
    204.    char Str[128];
    205.    sprintf(Str, "Test: Received %d\n", Val);
    206.    OutputDebugString(Str);
    207. }
    208. __declspec(dllexport) void __cdecl Test2(int Val)
    209. {
    210.    char Str[128];
    211.    sprintf(Str, "Test2: Received %d\n", Val);
    212.    OutputDebugString(Str);
    213. }
    214.  
    215. // exported func to set up the hook
    216. // NOTE: Currently assuming WCHAR array comming from Unity.
    217. // Earlier versions used char arrays.  For older versions of Unity convert to char * by
    218. // WindowData.pName to the parameter instead of converting
    219. // or do something cleverer!
    220. __declspec(dllexport) int __cdecl Initialise(WCHAR *PName)
    221. {
    222.    char Str[128];
    223.    int Len = lstrlenW(PName);
    224.    WideCharToMultiByte(CP_ACP, 0, PName, Len, Str, 127, NULL, NULL);
    225.    Str[Len] = 0;
    226.  
    227.    tWindowData WindowData;
    228.    WindowData.pName = Str;
    229.    WindowData.Handle = NULL;
    230.    EnumDesktopWindows(NULL, EnumWindowsFunc, (LPARAM)&WindowData);
    231.    if (WindowData.Handle == NULL)
    232.      return -1;
    233.    g_hRemoteWnd = WindowData.Handle;
    234.  
    235.    // Get thread ID for Unity window
    236.    DWORD ProcessID;
    237.    int ID = GetWindowThreadProcessId(g_hRemoteWnd, &ProcessID);  
    238.    if (ID == 0)
    239.      return -2;
    240.  
    241.    // Set the Hooks
    242.    // One for Posted Messages
    243.    g_HookPosted = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC)HookProcPosted, g_hInst, ID);
    244.    if (g_HookPosted == NULL)
    245.    {
    246.      return -3;
    247.    }
    248.  
    249.    // One hook for System calls (Win8)
    250.    g_HookCalled = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)HookProcCalled, g_hInst, ID);
    251.    if (g_HookCalled == NULL)
    252.    {
    253.      UnhookWindowsHookEx(g_HookPosted);
    254.      return -4;
    255.    }
    256.  
    257.    // Setup our data
    258.    ClearData();  
    259.  
    260.    // Register the Unity window for touch
    261.    int Res = RegisterTouchWindow(g_hRemoteWnd, TWF_WANTPALM);
    262.    if (Res == 0)
    263.    {
    264.      UnhookWindowsHookEx(g_HookPosted);
    265.      UnhookWindowsHookEx(g_HookCalled);
    266.      return -5;
    267.    }
    268.    return 0;
    269. }
    270.  
    271. __declspec(dllexport) void __cdecl ShutDown(char *PName)
    272. {
    273.    UnhookWindowsHookEx(g_HookPosted);
    274.    UnhookWindowsHookEx(g_HookCalled);
    275. }
    276.  
    277. // Fairly self explanatory exported funcs
    278.  
    279. __declspec(dllexport) void __cdecl GetTouchPoint(int i, tTouchData *p)
    280. {
    281.    *p = g_CopyTouchPoints[i];
    282. }
    283.  
    284. __declspec(dllexport) int __cdecl GetTouchPointCount()
    285. {
    286.    int NumPoints = 0;
    287.    for (int i=0;i<MAX_TOUCH;i++)
    288.    {
    289.      if (g_TouchData[i].m_ID != -1)
    290.      {
    291.        g_CopyTouchPoints[NumPoints] = g_TouchData[i];
    292.        NumPoints++;
    293.      }
    294.    }
    295.    return NumPoints;
    296. }
    297.  
    298. BOOL APIENTRY DllMain( HMODULE hModule,
    299.   DWORD  ul_reason_for_call,
    300.   LPVOID lpReserved
    301.             )
    302. {
    303.    g_hInst = hModule;
    304.    switch (ul_reason_for_call)
    305.    {
    306.    case DLL_PROCESS_ATTACH:
    307.    case DLL_THREAD_ATTACH:
    308.    case DLL_THREAD_DETACH:
    309.    case DLL_PROCESS_DETACH:
    310.      break;
    311.    }
    312.    return TRUE;
    313. }
    314.  
    315. }
    316.  
     
    Last edited: Dec 10, 2015
  4. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    You need to initialize first

    Code (CSharp):
    1.         if(!this.m_initialize) {
    2.             if(Initialise("PROJECT NAME OR ANYTHING") < 0) {
    3.                 // An error happened
    4.             } else {
    5.                 this.m_initialize = true;
    6.             }
    7.         }
    8.  
    9.         if(this.m_initialize) {
    10.             // Check inputs
    11.         }
     
  5. Polymorphik

    Polymorphik

    Joined:
    Jul 25, 2014
    Posts:
    599
    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
     
  6. Dimlos

    Dimlos

    Joined:
    Aug 13, 2014
    Posts:
    51
    I'm going to try this as soon as I can.
    Thank you for your help.

    [EDIT]
    Code (CSharp):
    1.     void Start()
    2.     {
    3.         m_Initialised = false;
    4.         StartCoroutine(Initialise());
    5.     }
    6.  
    7.     void Update()
    8.     {
    9.         if (m_Initialised)
    10.         {
    11.             int test = GetTouchPointCount();
    12.             Debug.Log(test);
    13.         }
    14.     }
    15.   private IEnumerator Initialise()
    16.   {
    17.   yield return new WaitForSeconds(2f);
    18.   string Str;
    19.   //int NumTouch = 0;
    20.       if (!m_Initialised)
    21.       {
    22.           Str = "New Unity Project";
    23.           if (Initialise(Str) < 0)    //error is here
    24.           {
    25.               // ERROR STATE
    26.           }
    27.           else
    28.           {
    29.               m_Initialised = true;
    30.           }
    31.       }
    32.   }
    33.  

    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.
     
    Last edited: Dec 11, 2015
  7. Dimlos

    Dimlos

    Joined:
    Aug 13, 2014
    Posts:
    51
    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
     
  8. Dimlos

    Dimlos

    Joined:
    Aug 13, 2014
    Posts:
    51
    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.
     
    Last edited: Dec 15, 2015