Input Pointers

From PowerUI
Revision as of 04:10, 1 May 2017 by Bablakeluke (talk | contribs) (Virtual Reality)
Jump to: navigation, search

An input pointer is any kind of pointing device which presses, hovers, or both. A mouse, a finger and a stylus are the three main ones. They are related to the (draft) W3C Pointer Events specification. Here's some specific notes about the input pointers available in PowerUI.

Mouse Input

PowerUI assumes that only a desktop platform will have a mouse. A MousePointer is created when it's running on a desktop and PowerUI.Input.CreateSystemMouse is true (the default). If your project doesn't use a mouse pointer on a desktop platform (it's virtual reality for example), you'd remove it by setting CreateSystemMouse to false in an Awake method.

Touch and Stylus Input

PowerUI handles multi-touch input by default on any platform which supports it. It will automatically stack with a mouse input on desktops which also have touchscreens. Each time a new touch is detected, a FingerPointer or a StylusPointer is created. They fire the various touch events as well as mouse events.

All pointers are primary (which means they all fire those mouse events too).

Virtual Reality

PowerUI has a custom input pointer, a CameraPointer, for virtual reality. See the article relating to virtual reality camera's. Alternatively here's a (rough!) laser pointer input example. Just add it to your project and see the notes below on how to e.g. add it and make it click:

using System;
using UnityEngine;


/// <summary>A laser pointer which fires an input ray from e.g. a 3D hand.</summary>
public class LaserPointer : PowerUI.InputPointer{
    
    public Transform Transform;
    /// <summary>True if UI's move around.</summary>
    public bool MovingUIs; 
   

    /// <summary>Setup a laser pointer from the given transform (e.g. a hand object).</summary>
    public LaserPointer(Transform transform):this(transform,true){}
   
    /// <summary>Setup a laser pointer from the given transform (e.g. a hand object).</summary>
    /// <param name='movingUIs'>Set this to true if your WorldUI's move around.
    /// Setting it to false is a small performance saving. If you're not sure, just use true.</param>
    public LaserPointer(Transform transform, bool movingUIs){
       Transform = transform;
       MovingUIs = movingUIs;
       
       // It won't interact with the main UI so just put it offscreen to skip checking entirely:
       ScreenX = ScreenY = -1000f;
       
    }
    
    public override bool Raycast(out RaycastHit hit, Camera cam, Vector2 screenPoint){
        
        // Fire off your ray in whatever your pointers direction is; we'll use transform.forward here.
        // ('forward' is +ve z):
        Ray ray = new Ray(Transform.position, Transform.forward);

        return Physics.Raycast(theRay, out hit);
    }
    
    public override bool Relocate(out Vector2 delta){
        
        // We can just ignore delta (it's for the main UI):
        delta = Vector2.zero;
        
        if(MovingUIs){
            // Always recompute.
            return true;
        }
        
        // Transform moved?
        if(Transform!=null && Transform.hasChanged){
            Transform.hasChanged = false;
            return true;
        }
        
        // Don't bother recalculating - it's not moved.
        // (Always return true if your UI's are moving instead).
        return false;
    }
    
}

Usage:

// Fires a ray from the given hand object. If your UI's don't move around, use LaserPointer(aHandObject,false) to make a performance gain.
LaserPointer myPointer = new LaserPointer(aHandObject);

// Add it:
myPointer.Add();

// myPointer.LeftDown(); etc to click (see more below)

Define your own

If you're doing something more specialised then you can also define your own input pointer. Multiple Wii controllers, for example. This is very straight forward to do - at a minimum you must inherit from InputPointer:

public class MyCustomPointer : InputPointer{
}

Then to use it, all you need to do is create and add it:

    MyCustomPointer pointer = new MyCustomPointer();
    pointer.Add();

It can be clicked etc or have a pressure value like any other pointer. To move it around, set the Position property (Top left corner is 0,0):

    pointer.Position = new Vector2(100,100);

Alternatively you can put your position update logic inside the pointer itself by overriding the Relocate method:

public class MyCustomPointer : InputPointer{
    
    public override bool Relocate(out Vector2 positionChange){
    
        // - Get your latest coordinates here -
        Vector2 newPosition = Vector2.zero;
        
        // Try moving it (just returns false if your position wasn't different to the current one):
        return TryChangePosition(newPosition, out positionChange);
    }

}

Making it click

If you've got an input pointer and you'd like to click it (or vary its downward pressure), you can either:

  • Use the convenience method for mouse up/down events from OnGUI:
void OnGUI(){

  // Returns true if your pointer actually did something (it went down or up)
  // You can also directly pass a UnityEngine.Event too.
  bool didSomething = MyPointer.HandleEvent();

}
  • Call the MyPointer.Down and MyPointer.Up methods (Optionally specifying a mouse button ID):
// Mousedown event, left button:
MyPointer.Down(0);

// Which is also the same as:
MyPointer.LeftDown();

// Mouseup event, left button:
MyPointer.Up(0);

// Which is the same as:
MyPointer.LeftUp();
  • Use SetPressure directly - this is useful if you've got some kind of stylus (every other option is just an abstraction of SetPressure)
void Update(){
  
  // Update the pointer pressure:
  MyPointer.SetPressure(someVaryingField);

}

Accessing all pointers

PowerUI implements various standard API's for accessing pointers:

  • TouchEvent.touches
  • TouchEvent.targetTouches
  • TouchEvent.changedTouches
  • TouchEvent.identifier
  • More!

The non-standard internal ones:

  • UIEvent.trigger - MouseEvent, TouchEvent etc; The InputPointer instance this event came from
  • InputPointer.All - All active pointers (array created on use; Use AllRaw and PointerCount for better performance)
  • InputPointer.PointerCount - The number of actual pointers in the AllRaw pointer set
  • InputPointer.AllRaw - The raw set of pointers. Entries beyond PointerCount are random noise/ undefined.


Source locations

You'll find the implementations of MousePointer, FingerPointer etc here:

  • PowerUI/Source/Engine/Input/