Detecting if using touchscreen or not

Is it possible to detect if the user is using a touchscreen or a regular mouse interface?

This isn’t mobile specific, as there are Win/Mac hardware that lets you use a touchscreen.

What i did for my game was this. I have made the game for PC \ MAC. On the objects that i have to press \ release i’ve made a script with OnMouseDown \ OnMouseUp functions. Then when i switch to iOS i’ve made script to check, which object is touched and it sends message to that object SendMessage(“OnMouseDown”).

This way i can play the game on the MAC \ PC (cuz there it cares on the OnMouseDown \ Up functions) and when i switch to Touch devide it executes the script for the Touch and calling the OnMouseDown \ Up functions from the touch script.

This was for a puzzle game where you only have to touch \ release, if you have to move objects i’m pretty sure it can be extended in the same way…

I don’t believe there is a trivial way to detect touch based input hardware.

This is a hack - but it results in platform agnostic code. It’s an incomplete segment of the code, but you should get the idea.

Instead of #if #def on platform, you could check if touches are null - if touches are null, fall back to the mouse.

	public static readonly PrimaryInput leftMouse = new PrimaryInput(KeyCode.Mouse0);
	public static readonly PrimaryInput rightMouse = new PrimaryInput(KeyCode.Mouse1);
	public static readonly PrimaryInput middleMouse = new PrimaryInput(KeyCode.Mouse2);


public sealed class PrimaryInput : KeyInput{
	
	public PrimaryInput(KeyCode k) : base(k){
		switch(k){
			case KeyCode.Mouse0:
				inputSource = 0;
				break;
			case KeyCode.Mouse1:
				inputSource = 1;
				break;
			case KeyCode.Mouse2:
				inputSource = 2;
				break;
			case KeyCode.Mouse3:
				inputSource = 3;
				break;
			case KeyCode.Mouse4:
				inputSource = 4;
				break;	
			default:
				throw new System.ArgumentOutOfRangeException("Key code must be one of the 5 touches");
				
				
		}
	}

private Vector2 InputPosition{
		get{
			#if UNITY_IPHONE || UNITY_ANDROID
				return Input.GetTouch(inputSource).position;
			#else
				return Input.mousePosition;
			#endif	
				
		}	
	}

Simply put your whole update function of the mouse look script in this if statement

if(Input.touchCount == 0)
{
	//Everything in the update portion of the mouse look script inside this
}

What this does is if there is a finger on the screen it disables the mouse moving the camera and it must be done by a pysical or virtual joystick

As soon as you lift your finger the mouse is enabled again so you can be using a touchpad on the screen and start using a mouse with no problems

The Whole Mouse Look Script

using UnityEngine;
using System.Collections;

/// MouseLook rotates the transform based on the mouse delta.
/// Minimum and Maximum values can be used to constrain the possible rotation

/// To make an FPS style character:
/// - Create a capsule.
/// - Add a rigid body to the capsule
/// - Add the MouseLook script to the capsule.
///   -> Set the mouse look to use LookX. (You want to only turn character but not tilt it)
/// - Add FPSWalker script to the capsule

/// - Create a camera. Make the camera a child of the capsule. Reset it's transform.
/// - Add a MouseLook script to the camera.
///   -> Set the mouse look to use LookY. (You want the camera to tilt up and down like a head. The character already turns.)
[AddComponentMenu("Camera-Control/Mouse Look")]
public class MouseLook : MonoBehaviour {

	public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
	public RotationAxes axes = RotationAxes.MouseXAndY;
	public float sensitivityX = 15F;
	public float sensitivityY = 15F;

	public float minimumX = -360F;
	public float maximumX = 360F;

	public float minimumY = -60F;
	public float maximumY = 60F;

	float rotationX = 0F;
	float rotationY = 0F;
	
	Quaternion originalRotation;

	void Update ()
	{
		//This Checks if there is no finger on screen and if not then continues on as if nothing is different
		//If there is a finger touching the screen nothing is done in this update cycle
		if(Input.touchCount == 0)
		{
			if(Input.mousePosition.x < 0 || Input.mousePosition.y < 0 || Input.mousePosition.x > Screen.width || Input.mousePosition.y > Screen.height)
			{
    			return;
			}
			
			if (axes == RotationAxes.MouseXAndY)
			{
				// Read the mouse input axis
				rotationX += Input.GetAxis("Mouse X") * sensitivityX;
				rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
				
				rotationX = ClampAngle (rotationX, minimumX, maximumX);
				rotationY = ClampAngle (rotationY, minimumY, maximumY);
					
				Quaternion xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up);
				Quaternion yQuaternion = Quaternion.AngleAxis (rotationY, -Vector3.right);
					
				transform.localRotation = originalRotation * xQuaternion * yQuaternion;
			}
			else if (axes == RotationAxes.MouseX)
			{
				rotationX += Input.GetAxis("Mouse X") * sensitivityX;
				rotationX = ClampAngle (rotationX, minimumX, maximumX);
				
				Quaternion xQuaternion = Quaternion.AngleAxis (rotationX, Vector3.up);
				transform.localRotation = originalRotation * xQuaternion;
			}
			else
			{
				rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
				rotationY = ClampAngle (rotationY, minimumY, maximumY);
				
				Quaternion yQuaternion = Quaternion.AngleAxis (-rotationY, Vector3.right);
				transform.localRotation = originalRotation * yQuaternion;
			}
		}
	}
	
	void Start ()
	{
		// Make the rigid body not change rotation
		if (rigidbody)
			rigidbody.freezeRotation = true;
		originalRotation = transform.localRotation;
	}
	
	public static float ClampAngle (float angle, float min, float max)
	{
		if (angle < -360F)
			angle += 360F;
		if (angle > 360F)
			angle -= 360F;
		return Mathf.Clamp (angle, min, max);
	}
}

I think Zachary’s answer is good, as well as some other info here, but wanted to point out one other idea that is probably practical in a lot of cases.

If you can design your game so that the first screen doesn’t need to know… like maybe just a simple “click here to start” or maybe your “main menu” screen doesn’t care. Then, in that screen you can detect if the user clicked the “play” or “start” button by using touch input, or a mouse… then you can use that info for the main part of your game.

Of course, better if you can design to handle either/both in the same way and not need to care… but not knowing your game design I’m not going to try to say “you SHOULD do it this way or that way”.

Following lines of code will detect whether it is touchInput or not.

#if ( UNITY_EDITOR || UNITY_EDITOR_64 || UNITY_EDITOR_OSX)
            touchInput = false;
#else
            touchInput = true;

#endif

Is there a way to do a project wide define based on an #if evaluation? I’ve been searching the C# forums and they all there is no way to do a define that affects all files unless you put something in your project settings. However, the project settings (Project/Properties) don’t have a way to add conditions to the define.

So this… does NOT work…

MyDefines.cs

#if ((UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR)
#define HAS_TOUCH
#endif

Which is unfortunate… I hate to have to copy and paste “#if ((UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR)” all over the place.

One solution I came up with is:

static class Constants
{
#if ((UNITY_IOS || UNITY_ANDROID) && !UNITY_EDITOR)
    public const bool HAS_TOUCH = true;
#else
    public const bool HAS_TOUCH = false;
#endif
}

However, this is not really what I want either… if we add if (Contants.HAS_TOUCH) { } inside of an Update(), the “if” statement will get evaluated at 60 times per second so we lose efficiency.

Surely there has to be better way to do this??!