Looking-Glass / JoyconLib

Joy-Con library for Unity.
MIT License
467 stars 91 forks source link

Connecting Joycon to android #29

Open Albond87 opened 4 years ago

Albond87 commented 4 years ago

After much annoyance with Unity complaining about various things, and after digging through other issues, I managed to get a simple scene working, with two cuboids representing Joycon that rotate to match my two Joycon connected to my laptop. I then built the scene for android and ran it on my phone, with my two Joycon already connected and working, and... nothing. Just two lifeless cuboids staring back at me. Tried disconnecting and reconnecting the Joycon, tried restarting the app... nothing. I noticed someone else already raised an issue about android support, but it got no response. Is there some other plugin needed to be able to use this on android? (like a BLE plugin) Or is there some other way to get Unity to recognise them when they are connected to Android? (when connected to my phone the names are the exact same as on my Laptop (Joy-Con (L) and Joy-Con (R)) and they show the same controller icon)

TheBricktop commented 4 years ago

For me it's an interesting issue, as I want to connect Joy cons to Android and raspberry pi enabled device's

Albond87 commented 4 years ago

@TheBricktop So I actually found a (kind of) solution. Instead of connecting the Joy Con to my phone, I made a simple exe for my laptop which takes input from them, and then sends the data I need in packets to a receiver application on my phone, where I can then use the input. It works pretty well with not much latency (and I never tried to optimise it as I never went any further with that project). The only downside is you need to have a pc/laptop so it's not exactly a portable solution. I can give you the code if you want (not sure how to incorporate a raspi though, maybe by connecting that to the laptop as well?)

TheBricktop commented 4 years ago

Yea i was thinking about osc or some kind of a translator from hid to raw data, but intended way of using this was to make some kind of a better daydream controller out of existing superior joystics (and far cheaper in comparision)

Northernside commented 3 years ago

@TheBricktop So I actually found a (kind of) solution. Instead of connecting the Joy Con to my phone, I made a simple exe for my laptop which takes input from them, and then sends the data I need in packets to a receiver application on my phone, where I can then use the input. It works pretty well with not much latency (and I never tried to optimise it as I never went any further with that project). The only downside is you need to have a pc/laptop so it's not exactly a portable solution. I can give you the code if you want (not sure how to incorporate a raspi though, maybe by connecting that to the laptop as well?)

Heya! Can you drop a download link to the code?

Albond87 commented 2 years ago

@TheBricktop So I actually found a (kind of) solution. Instead of connecting the Joy Con to my phone, I made a simple exe for my laptop which takes input from them, and then sends the data I need in packets to a receiver application on my phone, where I can then use the input. It works pretty well with not much latency (and I never tried to optimise it as I never went any further with that project). The only downside is you need to have a pc/laptop so it's not exactly a portable solution. I can give you the code if you want (not sure how to incorporate a raspi though, maybe by connecting that to the laptop as well?)

Heya! Can you drop a download link to the code?

Hi, sorry for the late response but here is some code you might find useful! (Modified from https://forum.unity.com/threads/simple-udp-implementation-send-read-via-mono-c.15900/ to send Joycon data)

Sending packets of data (for the desktop application):

/*

    -----------------------
    UDP-Send
    -----------------------
    // [url]http://msdn.microsoft.com/de-de/library/bb979228.aspx#ID0E3BAC[/url]

    CODE TAKEN FROM: https://forum.unity.com/threads/simple-udp-implementation-send-read-via-mono-c.15900/

    // > gesendetes unter
    // 127.0.0.1 : 8050 empfangen

    // nc -lu 127.0.0.1 8050

        // todo: shutdown thread at the end
*/
using UnityEngine;
using UnityEngine.UI;

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Linq;
using System.Collections;

public class IPManager
{
    public static string GetIP(ADDRESSFAM Addfam)
    {
        //Return null if ADDRESSFAM is Ipv6 but Os does not support it
        if (Addfam == ADDRESSFAM.IPv6 && !Socket.OSSupportsIPv6)
        {
            return null;
        }

        string output = "";

        foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
        {
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
            NetworkInterfaceType _type1 = NetworkInterfaceType.Wireless80211;
            NetworkInterfaceType _type2 = NetworkInterfaceType.Ethernet;

            if ((item.NetworkInterfaceType == _type1 || item.NetworkInterfaceType == _type2) && item.OperationalStatus == OperationalStatus.Up)
#endif 
            {
                foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
                {
                    //IPv4
                    if (Addfam == ADDRESSFAM.IPv4)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
                        {
                            output = ip.Address.ToString();
                        }
                    }

                    //IPv6
                    else if (Addfam == ADDRESSFAM.IPv6)
                    {
                        if (ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
                        {
                            output = ip.Address.ToString();
                        }
                    }
                }
            }
        }
        return output;
    }
}

public enum ADDRESSFAM
{
    IPv4, IPv6
}

public class UDPSend : MonoBehaviour
{
    private static int localPort;

    // prefs
    private string IP;  // define in init
    public int port;  // define in init

    // "connection" things
    IPEndPoint remoteEndPoint;
    UdpClient client;

    [Serializable]
    public class DataPacket
    {
        public Quaternion lo; // left orientation
        public Quaternion ro; // right orientation
        public bool zl;
        public bool zr;
    }

    public DataPacket sendPacket = new DataPacket();

    public InputField input;
    public JoyconController joyconL;
    public JoyconController joyconR;

    // start from unity3d
    public void Start()
    {
        Init();
        Debug.Log(IPManager.GetIP(ADDRESSFAM.IPv4));
    }

    public void Update()
    {
        sendPacket.lo = joyconL.orientation;
        sendPacket.ro = joyconR.orientation;
        sendPacket.zl = joyconL.joycon.GetButton(Joycon.Button.SHOULDER_2);
        sendPacket.zr = joyconR.joycon.GetButton(Joycon.Button.SHOULDER_2);
        string json = JsonUtility.ToJson(sendPacket);
        SendString(json);
    }

    // init
    public void Init()
    {
        // Endpunkt definieren, von dem die Nachrichten gesendet werden.
        print("UDPSend.init()");

        // define
        IP = input.text;
        port = 8051;

        // ----------------------------
        // Senden
        // ----------------------------
        remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), port);
        client = new UdpClient();

        // status
        print("Sending to " + IP + " : " + port);
        print("Testing: nc -lu " + IP + " : " + port);

    }

    // sendData
    private void SendString(string message)
    {
        try
        {
            //if (message != "")
            //{

            // Daten mit der UTF8-Kodierung in das Binärformat kodieren.
            byte[] data = Encoding.UTF8.GetBytes(message);

            // Den message zum Remote-Client senden.
            client.Send(data, data.Length, remoteEndPoint);
            //}
        }
        catch (Exception err)
        {
            print(err.ToString());
        }
    }
}

Receiving packets of data (for the mobile application):

/*

    -----------------------
    UDP-Receive (send to)
    -----------------------
    // [url]http://msdn.microsoft.com/de-de/library/bb979228.aspx#ID0E3BAC[/url]

    CODE TAKEN FROM: https://forum.unity.com/threads/simple-udp-implementation-send-read-via-mono-c.15900/

    // > receive
    // 127.0.0.1 : 8051

    // send
    // nc -u 127.0.0.1 8051

*/
using UnityEngine;

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;

public class UDPReceive : MonoBehaviour
{

    // receiving Thread
    Thread receiveThread;

    // udpclient object
    UdpClient client;

    // public
    //public string IP = "127.0.0.1";
    public int port; // define > init

    // infos
    public string lastReceivedUDPPacket = "";
    //public string allReceivedUDPPackets = ""; // clean up this from time to time!

    [Serializable]
    public class DataPacket
    {
        public Quaternion lo; // left orientation
        public Quaternion ro; // right orientation
        public bool zl;
        public bool zr;
    }

    public bool isAlive = false;

    public Transform joyconL;
    public Transform joyconR;
    public Transform zl;
    public Transform zr;

    public Vector3 unpressedPos;
    public Vector3 pressedPos;

    // start from shell
    private static void Main()
    {
        UDPReceive receiveObj = new UDPReceive();
        receiveObj.Init();

        string text = "";
        do
        {
            text = Console.ReadLine();
        }
        while (!text.Equals("exit"));
    }
    // start from unity3d
    public void Start()
    {

        Init();
    }

    public void Update()
    {
        string packet = GetLatestUDPPacket();
        DataPacket receivePacket = JsonUtility.FromJson<DataPacket>(packet);
        joyconL.localRotation = receivePacket.lo;
        joyconR.localRotation = receivePacket.ro;
        if (receivePacket.zl)
        {
            zl.localPosition = pressedPos;
        }
        else
        {
            zl.localPosition = unpressedPos;
        }
        if (receivePacket.zr)
        {
            zr.localPosition = pressedPos;
        }
        else
        {
            zr.localPosition = unpressedPos;
        }
    }

    // OnGUI
    /*void OnGUI()
    {
        Rect rectObj = new Rect(40, 10, 200, 400);
        GUIStyle style = new GUIStyle();
        style.alignment = TextAnchor.UpperLeft;
        GUI.Box(rectObj, "# UDPReceive\n127.0.0.1 " + port + " #\n"
                    + "shell> nc -u 127.0.0.1 : " + port + " \n"
                    + "\nLast Packet: \n" + lastReceivedUDPPacket
                    + "\n\nAll Messages: \n" + allReceivedUDPPackets
                , style);
    }*/

    // init
    private void Init()
    {
        // Endpunkt definieren, von dem die Nachrichten gesendet werden.
        print("UDPSend.init()");

        // define port
        port = 8051;

        // status
        print("Sending to 127.0.0.1 : " + port);
        print("Test-Sending to this Port: nc -u 127.0.0.1  " + port + "");

        // ----------------------------
        // Abhören
        // ----------------------------
        // Lokalen Endpunkt definieren (wo Nachrichten empfangen werden).
        // Einen neuen Thread für den Empfang eingehender Nachrichten erstellen.
        isAlive = true;
        receiveThread = new Thread(
            new ThreadStart(ReceiveData));
        receiveThread.IsBackground = true;
        receiveThread.Start();

    }

    private void OnApplicationQuit()
    {
        isAlive = false;
        receiveThread.Abort();
    }

    // receive thread
    public void ReceiveData()
    {
        client = new UdpClient(port);
        //client.Client.Blocking = false;
        while (isAlive)
        {
            try
            {
                // Bytes empfangen.
                IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
                byte[] data = client.Receive(ref anyIP);

                // Bytes mit der UTF8-Kodierung in das Textformat kodieren.
                string text = Encoding.UTF8.GetString(data);

                // Den abgerufenen Text anzeigen.
                //print(">> " + text);

                // latest UDPpacket
                lastReceivedUDPPacket = text;

                // ....
                //allReceivedUDPPackets = allReceivedUDPPackets + text;

            }
            catch (Exception err)
            {
                print(err.ToString());
            }
        }
    }

    // getLatestUDPPacket
    // cleans up the rest
    public string GetLatestUDPPacket()
    {
        //allReceivedUDPPackets = "";
        return lastReceivedUDPPacket;
    }
}