daily pastebin goal
4%
SHARE
TWEET

RawInput Wrapper for Unity3d

PeterSvP Aug 23rd, 2016 (edited) 1,030 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Unity PINVOKE interface for pastebin.com/0Szi8ga6
  2. // Handles multiple cursors
  3. // License: CC0
  4.  
  5. using UnityEngine;
  6. using System.Collections;
  7. using System.Runtime.InteropServices;
  8. using System;
  9. using System.Collections.Generic;
  10. using UnityEngine.UI;
  11.  
  12. public class MouseInputManager : MonoBehaviour
  13. {
  14.     public static MouseInputManager instance;
  15.  
  16.     [DllImport("LibRawInput")]
  17.     private static extern bool init();
  18.  
  19.     [DllImport("LibRawInput")]
  20.     private static extern bool kill();
  21.  
  22.     [DllImport("LibRawInput")]
  23.     private static extern IntPtr poll();
  24.  
  25.     public const byte RE_DEVICE_CONNECT = 0;
  26.     public const byte RE_MOUSE = 2;
  27.     public const byte RE_DEVICE_DISCONNECT = 1;
  28.     public string getEventName(byte id)
  29.     {
  30.         switch (id)
  31.         {
  32.             case RE_DEVICE_CONNECT: return "RE_DEVICE_CONNECT";
  33.             case RE_DEVICE_DISCONNECT: return "RE_DEVICE_DISCONNECT";
  34.             case RE_MOUSE: return "RE_MOUSE";
  35.         }
  36.         return "UNKNOWN(" + id + ")";
  37.     }
  38.  
  39.     public GameObject cursor;
  40.     public Color[] colors;
  41.     public float defaultMiceSensitivity = 1f;
  42.     public float accelerationThreshold = 40;
  43.     public float accelerationMultiplier = 2;
  44.     public int screenBorderPixels = 16;
  45.  
  46.     [StructLayout(LayoutKind.Sequential)]
  47.     public struct RawInputEvent
  48.     {
  49.         public int devHandle;
  50.         public int x, y, wheel;
  51.         public byte press;
  52.         public byte release;
  53.         public byte type;
  54.     }
  55.  
  56.     public class MousePointer
  57.     {
  58.         public GameObject obj;
  59.         public Vector2 position;
  60.         public int deviceID;
  61.         public int playerID;
  62.         public float sensitivity;
  63.     }
  64.     Dictionary<int, MousePointer> pointersByDeviceId = new Dictionary<int, MousePointer>();
  65.     Dictionary<int, MousePointer> pointersByPlayerId = new Dictionary<int, MousePointer>();
  66.     int nextPlayerId = 1;
  67.     int miceCount = 0;
  68.  
  69.     Canvas canvas;
  70.     RectTransform canvasRect;
  71.     float width, height;
  72.  
  73.     void Start()
  74.     {
  75.         instance = this;
  76.         bool res = init();
  77.         Debug.Log("Init() ==> " + res);
  78.         Debug.Log(Marshal.SizeOf(typeof(RawInputEvent)));
  79.         canvas = GetComponent<Canvas>();
  80.         canvasRect = GetComponent<RectTransform>();
  81.         //enterSingleMode();
  82.     }
  83.  
  84.     public void OnDestroy()
  85.     {
  86.         instance = null;
  87.     }
  88.  
  89.     int addCursor(int deviceId)
  90.     {
  91.         if(!isInit)
  92.         {
  93.             Debug.LogError("Not initialized");
  94.             return -1;
  95.         }
  96.  
  97.         MousePointer mp = null;
  98.         pointersByDeviceId.TryGetValue(deviceId, out mp);
  99.         if(mp != null)
  100.         {
  101.             Debug.LogError("This device already has a cursor");
  102.             return -1;
  103.         }
  104.  
  105.         Debug.Log("Adding DeviceID " + deviceId);
  106.         mp = new MousePointer();
  107.         mp.playerID = nextPlayerId++;
  108.         pointersByDeviceId[deviceId] = mp;
  109.         pointersByPlayerId[mp.playerID] = mp;
  110.         mp.position = new Vector3(width / 2, height / 2, 0);
  111.        
  112.         mp.obj = Instantiate(cursor, transform) as GameObject;
  113.         var rt = mp.obj.GetComponent<RectTransform>();
  114.         rt.position = mp.position;
  115.  
  116.         var spriteComp = mp.obj.GetComponent<Image>();
  117.         if (spriteComp) spriteComp.color = colors[mp.playerID % colors.Length];
  118.  
  119.         ++miceCount;
  120.         return mp.playerID;
  121.     }
  122.  
  123.     void deleteCursor(int deviceId)
  124.     {
  125.         --miceCount;
  126.         var mp = pointersByDeviceId[deviceId];
  127.         pointersByDeviceId.Remove(mp.deviceID);
  128.         pointersByPlayerId.Remove(mp.playerID);
  129.         Destroy(mp.obj);
  130.     }
  131.  
  132.     bool _isMultiplayer = true;
  133.     MousePointer _spPointer;
  134.  
  135.     [SerializeField]
  136.     public bool isMultiplayer
  137.     {
  138.         set
  139.         {
  140.             if (!value) enterSingleMode(); else enterMultipleMode();
  141.             _isMultiplayer = value;
  142.         }
  143.         get { return _isMultiplayer; }
  144.     }
  145.  
  146.     void enterSingleMode()
  147.     {
  148.         clearCursorsAndDevices();
  149.         --nextPlayerId;
  150.         addCursor(0);
  151.         _spPointer = pointersByDeviceId[0];
  152.         Cursor.lockState = CursorLockMode.None;
  153.         Cursor.visible = false;
  154.     }
  155.  
  156.     void enterMultipleMode()
  157.     {
  158.         _spPointer = null;
  159.         nextPlayerId = 0;
  160.         clearCursorsAndDevices();
  161.         Cursor.lockState = CursorLockMode.Locked;
  162.         Cursor.visible = false;
  163.     }
  164.  
  165.     void clearCursorsAndDevices()
  166.     {
  167.         pointersByDeviceId.Clear();
  168.         pointersByPlayerId.Clear();
  169.         nextPlayerId = 1;
  170.         miceCount = 0;
  171.         foreach (Transform t in transform) Destroy(t.gameObject);
  172.     }
  173.  
  174.     public MousePointer getByPlayerId(int id)
  175.     {
  176.         MousePointer res = null;
  177.         pointersByPlayerId.TryGetValue(id, out res);
  178.         return res;
  179.     }
  180.  
  181.     // Update is called once per frame
  182.     int lastEvents = 0;
  183.     bool isInit = true;
  184.     void Update()
  185.     {
  186.         // Keyboard controls debug
  187.         if (Input.GetKeyDown(KeyCode.R))
  188.         {
  189.             if (isInit)
  190.             {
  191.                 clearCursorsAndDevices();
  192.                 kill();
  193.                 isInit = false;
  194.             }
  195.             else
  196.             {
  197.                 init();
  198.                 isInit = true;
  199.             }
  200.         }
  201.  
  202.         if (Input.GetKeyDown(KeyCode.M))
  203.         {
  204.             isMultiplayer = !isMultiplayer;
  205.         }
  206.  
  207.         // SP
  208.         if (!_isMultiplayer)
  209.         {
  210.             var rt = _spPointer.obj.GetComponent<RectTransform>();
  211.             rt.position = Input.mousePosition;
  212.         }
  213.         else
  214.         {
  215.             // MP
  216.             width = canvasRect.rect.width;
  217.             height = canvasRect.rect.height;
  218.             var left = -width / 2;
  219.             var right = width / 2;
  220.             var top = -height / 2;
  221.             var bottom = height / 2;
  222.             //Debug.Log("left=" + left + ", right=" + right + ", top=" + top + ", bottom=" + bottom);
  223.  
  224.             // Poll the events and properly update whatever we need
  225.             IntPtr data = poll();
  226.             int numEvents = Marshal.ReadInt32(data);
  227.             if (numEvents > 0) lastEvents = numEvents;
  228.             for (int i = 0; i < numEvents; ++i)
  229.             {
  230.                 var ev = new RawInputEvent();
  231.                 long offset = data.ToInt64() + sizeof(int) + i * Marshal.SizeOf(ev);
  232.                 ev.devHandle = Marshal.ReadInt32(new IntPtr(offset + 0));
  233.                 ev.x = Marshal.ReadInt32(new IntPtr(offset + 4));
  234.                 ev.y = Marshal.ReadInt32(new IntPtr(offset + 8));
  235.                 ev.wheel = Marshal.ReadInt32(new IntPtr(offset + 12));
  236.                 ev.press = Marshal.ReadByte(new IntPtr(offset + 16));
  237.                 ev.release = Marshal.ReadByte(new IntPtr(offset + 17));
  238.                 ev.type = Marshal.ReadByte(new IntPtr(offset + 18));
  239.                 //Debug.Log(getEventName(ev.type) + ":  H=" + ev.devHandle + ";  (" + ev.x + ";" + ev.y + ")  Down=" + ev.press + " Up=" + ev.release);
  240.  
  241.                 if (ev.type == RE_DEVICE_CONNECT) addCursor(ev.devHandle);
  242.                 else if (ev.type == RE_DEVICE_DISCONNECT) deleteCursor(ev.devHandle);
  243.                 else if (ev.type == RE_MOUSE)
  244.                 {
  245.                     MousePointer pointer = null;
  246.                     if (pointersByDeviceId.TryGetValue(ev.devHandle, out pointer))
  247.                     {
  248.                         float dx = ev.x * defaultMiceSensitivity;
  249.                         float dy = ev.y * defaultMiceSensitivity;
  250.                         if (Mathf.Abs(dx) > accelerationThreshold) dx *= accelerationMultiplier;
  251.                         if (Mathf.Abs(dy) > accelerationThreshold) dy *= accelerationMultiplier;
  252.                         pointer.position = new Vector2(
  253.                             Mathf.Clamp(pointer.position.x + dx, screenBorderPixels, width - screenBorderPixels),
  254.                             Mathf.Clamp(pointer.position.y - dy, screenBorderPixels, height - screenBorderPixels));
  255.                         RectTransform rt = pointer.obj.GetComponent<RectTransform>();
  256.                         rt.position = pointer.position;
  257.                     }
  258.                     else
  259.                     {
  260.                         Debug.Log("Unknown device found");
  261.                         addCursor(ev.devHandle);
  262.                     }
  263.                 }
  264.             }
  265.             Marshal.FreeCoTaskMem(data);
  266.         }
  267.     }
  268.  
  269.     void OnApplicationQuit()
  270.     {
  271.         kill();
  272.     }
  273. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top