using UnityEngine; using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using com.rfilkov.kinect; namespace com.rfilkov.components { /// /// This interface has to be implemented by all interaction listeners. /// public interface InteractionListenerInterface { /// /// Invoked when hand grip is detected. /// /// User ID /// User index /// Whether it is the right hand or not /// Whether this hand is the interacting one or not /// Hand screen position, including depth (Z) void HandGripDetected(ulong userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos); /// /// Invoked when hand release is detected. /// /// User ID /// User index /// Whether it is the right hand or not /// Whether this hand is the interacting one or not /// Hand screen position, including depth (Z) void HandReleaseDetected(ulong userId, int userIndex, bool isRightHand, bool isHandInteracting, Vector3 handScreenPos); /// /// Invoked when hand click is detected. /// /// true, if the click detection must be restarted, false otherwise. /// User ID /// User index /// Whether it is the right hand or not /// Hand screen position, including depth (Z) bool HandClickDetected(ulong userId, int userIndex, bool isRightHand, Vector3 handScreenPos); } /// /// InteractionManager is the component that controls the hand cursor and manages the hand interactions. /// public class InteractionManager : MonoBehaviour { /// /// The hand event types. /// public enum HandEventType : int { None = 0, Grip = 1, Release = 2 } [Tooltip("Index of the player, tracked by this component. 0 means the 1st player, 1 - the 2nd one, 2 - the 3rd one, etc.")] public int playerIndex = 0; [Tooltip("Whether the left hand interaction is allowed.")] public bool leftHandInteraction = true; [Tooltip("Whether the right hand interaction is allowed.")] public bool rightHandInteraction = true; [Tooltip("The image that may be used to show the hand-moved cursor on the screen or not. The sprite textures below need to be set too.")] public Image guiHandCursor; [Tooltip("Hand-cursor sprite texture, for the hand-grip state.")] public Sprite gripHandTexture; [Tooltip("Hand-cursor sprite texture, for the hand-release state.")] public Sprite releaseHandTexture; [Tooltip("Hand-cursor sprite texture, for the non-tracked state.")] public Sprite normalHandTexture; [Tooltip("Whether the hand cursor should overlay user's hand on color camera image, or not.")] public bool handOverlayCursor = false; [Tooltip("Depth sensor index used for color camera overlay - 0 is the 1st one, 1 - the 2nd one, etc.")] public int sensorIndex = 0; [Tooltip("Smooth factor for cursor movement.")] public float smoothFactor = 10f; [Tooltip("Whether the hand clicks (i.e. hand staying in place for ~2 seconds) are enabled or not.")] public bool allowHandClicks = true; [Tooltip("Whether the hand pushes need to be considered as clicks or not.")] public bool allowPushToClick = true; [Tooltip("Whether the hand cursor and interactions control the mouse cursor or not.")] public bool controlMouseCursor = false; [Tooltip("Whether the hand grips and releases control mouse dragging or not.")] public bool controlMouseDrag = false; // Bool to specify whether to convert Unity screen coordinates to full screen mouse coordinates //public bool convertMouseToFullScreen = false; [Tooltip("List of the interaction listeners in the scene. If the list is empty, the available interaction listeners will be detected at scene start up.")] public List interactionListeners; [Tooltip("UI-Text to display the interaction-manager debug messages.")] public Text debugText; // tracked userId private ulong playerUserID = 0; private ulong lastUserID = 0; // hand press properties private bool isLeftHandPrimary = false; private bool isRightHandPrimary = false; private bool isLeftHandPress = false; private bool isRightHandPress = false; private float lastLeftHandPressTime = 0f; private float lastRightHandPressTime = 0f; private float leftHandPressProgress = 0f; private float rightHandPressProgress = 0f; // cursor properties private Vector3 cursorScreenPos = Vector3.zero; private bool dragInProgress = false; private Image cursorProgressBar; private float cursorClickProgress = 0f; // hand states private KinectInterop.HandState leftHandState = KinectInterop.HandState.Unknown; private KinectInterop.HandState rightHandState = KinectInterop.HandState.Unknown; // left hand properties private HandEventType leftHandEvent = HandEventType.None; private HandEventType lastLeftHandEvent = HandEventType.Release; private Vector3 leftHandPos = Vector3.zero; private Vector3 leftHandScreenPos = Vector3.zero; private Vector3 leftIboxLeftBotBack = Vector3.zero; private Vector3 leftIboxRightTopFront = Vector3.zero; private bool isleftIboxValid = false; private bool isLeftHandInteracting = false; private float leftHandInteractingSince = 0f; // left hand click properties private Vector3 lastLeftHandPos = Vector3.zero; private float lastLeftHandClickTime = 0f; private bool isLeftHandClick = false; private float leftHandClickProgress = 0f; // left hand properties private HandEventType rightHandEvent = HandEventType.None; private HandEventType lastRightHandEvent = HandEventType.Release; private Vector3 rightHandPos = Vector3.zero; private Vector3 rightHandScreenPos = Vector3.zero; private Vector3 rightIboxLeftBotBack = Vector3.zero; private Vector3 rightIboxRightTopFront = Vector3.zero; private bool isRightIboxValid = false; private bool isRightHandInteracting = false; private float rightHandInteractingSince = 0f; // right hand click properties private Vector3 lastRightHandPos = Vector3.zero; private float lastRightHandClickTime = 0f; private bool isRightHandClick = false; private float rightHandClickProgress = 0f; // Bool to keep track whether Kinect and Interaction library have been initialized private bool interactionInited = false; // The single instance of FacetrackingManager //private static InteractionManager instance; // hand states private float lHandState = 0f; private float rHandState = 0f; ///// ///// Gets the single InteractionManager instance. ///// ///// The InteractionManager instance. //public static InteractionManager Instance //{ // get // { // return instance; // } //} /// /// Gets the proper instance of InteractionManager, or null if no proper IM is found. /// /// Player index, tracked by the IM. /// Whether the IM tracks left-hand interactions or not. /// Whether the IM tracks right-hand interactions or not. /// public static InteractionManager GetInstance(int playerIndex, bool leftHandInteraction, bool rightHandInteraction) { // find the proper interaction manager MonoBehaviour[] monoScripts = FindObjectsOfType(typeof(MonoBehaviour)) as MonoBehaviour[]; foreach (MonoBehaviour monoScript in monoScripts) { if ((monoScript is InteractionManager) && monoScript.enabled) { InteractionManager intManager = (InteractionManager)monoScript; if (intManager.playerIndex == playerIndex && (!leftHandInteraction || intManager.leftHandInteraction) && (!rightHandInteraction || intManager.rightHandInteraction)) { return intManager; } } } // not found return null; } /// /// Determines whether the InteractionManager was successfully initialized. /// /// true if InteractionManager was successfully initialized; otherwise, false. public bool IsInteractionInited() { return interactionInited; } /// /// Gets the current user ID, or 0 if no user is currently tracked. /// /// The user ID public ulong GetUserID() { return playerUserID; } /// /// Gets the current left hand event (none, grip or release). /// /// The current left hand event. public HandEventType GetLeftHandEvent() { return leftHandEvent; } /// /// Gets the last detected left hand event (grip or release). /// /// The last left hand event. public HandEventType GetLastLeftHandEvent() { return lastLeftHandEvent; } /// /// Gets the current normalized viewport position of the left hand, in range [0, 1]. /// /// The left hand viewport position. public Vector3 GetLeftHandScreenPos() { return leftHandScreenPos; } /// /// Determines whether the left hand is primary for the user. /// /// true if the left hand is primary for the user; otherwise, false. public bool IsLeftHandPrimary() { return isLeftHandPrimary; } /// /// Determines whether the left hand is pressing. /// /// true if the left hand is pressing; otherwise, false. public bool IsLeftHandPress() { return isLeftHandPress; } /// /// Determines whether a left hand click is detected, false otherwise. /// /// true if a left hand click is detected; otherwise, false. public bool IsLeftHandClickDetected() { if (isLeftHandClick) { isLeftHandClick = false; cursorClickProgress = leftHandClickProgress = 0f; lastLeftHandPos = Vector3.zero; lastLeftHandClickTime = Time.realtimeSinceStartup; lastLeftHandPressTime = Time.realtimeSinceStartup; return true; } return false; } /// /// Gets the left hand click progress, in range [0, 1]. /// /// The left hand click progress. public float GetLeftHandClickProgress() { return leftHandClickProgress; } /// /// Gets the current right hand event (none, grip or release). /// /// The current right hand event. public HandEventType GetRightHandEvent() { return rightHandEvent; } /// /// Gets the last detected right hand event (grip or release). /// /// The last right hand event. public HandEventType GetLastRightHandEvent() { return lastRightHandEvent; } /// /// Gets the current normalized viewport position of the right hand, in range [0, 1]. /// /// The right hand viewport position. public Vector3 GetRightHandScreenPos() { return rightHandScreenPos; } /// /// Determines whether the right hand is primary for the user. /// /// true if the right hand is primary for the user; otherwise, false. public bool IsRightHandPrimary() { return isRightHandPrimary; } /// /// Determines whether the right hand is pressing. /// /// true if the right hand is pressing; otherwise, false. public bool IsRightHandPress() { return isRightHandPress; } /// /// Determines whether a right hand click is detected, false otherwise. /// /// true if a right hand click is detected; otherwise, false. public bool IsRightHandClickDetected() { if (isRightHandClick) { isRightHandClick = false; cursorClickProgress = rightHandClickProgress = 0f; lastRightHandPos = Vector3.zero; lastRightHandClickTime = Time.realtimeSinceStartup; lastRightHandPressTime = Time.realtimeSinceStartup; return true; } return false; } /// /// Gets the right hand click progress, in range [0, 1]. /// /// The right hand click progress. public float GetRightHandClickProgress() { return rightHandClickProgress; } /// /// Gets the current cursor normalized viewport position. /// /// The cursor viewport position. public Vector3 GetCursorPosition() { return cursorScreenPos; } /// /// Gets the cursor click progress, in range [0, 1]. /// /// The right hand click progress. public float GetCursorClickProgress() { return cursorClickProgress; } //----------------------------------- end of public functions --------------------------------------// void Awake() { //instance = this; } void Start() { // get the progress bar reference if any GameObject objProgressBar = guiHandCursor && guiHandCursor.gameObject.transform.childCount > 0 ? guiHandCursor.transform.GetChild(0).gameObject : null; cursorProgressBar = objProgressBar ? objProgressBar.GetComponent() : null; interactionInited = true; // try to automatically detect the available interaction listeners in the scene if (interactionListeners.Count == 0) { MonoBehaviour[] monoScripts = FindObjectsOfType(typeof(MonoBehaviour)) as MonoBehaviour[]; foreach (MonoBehaviour monoScript in monoScripts) { //if (typeof(InteractionListenerInterface).IsAssignableFrom(monoScript.GetType()) && // monoScript.enabled) if ((monoScript is InteractionListenerInterface) && monoScript.enabled) { interactionListeners.Add(monoScript); } } } } void OnDestroy() { interactionInited = false; //instance = null; } void Update() { KinectManager kinectManager = KinectManager.Instance; // update Kinect interaction if (kinectManager && kinectManager.IsInitialized()) { playerUserID = kinectManager.GetUserIdByIndex(playerIndex); if (playerUserID != 0) { lastUserID = playerUserID; HandEventType handEvent = HandEventType.None; float fTimeSmooth = 10f * Time.deltaTime; // get the left hand state int handState = (int)kinectManager.GetLeftHandState(playerUserID); lHandState = Mathf.Lerp(lHandState, handState, fTimeSmooth); leftHandState = (KinectInterop.HandState)Mathf.RoundToInt(lHandState); // (KinectInterop.HandState)handState; // // check if the left hand is interacting isleftIboxValid = kinectManager.GetLeftHandInteractionBox(playerUserID, ref leftIboxLeftBotBack, ref leftIboxRightTopFront, isleftIboxValid); //bool bLeftHandPrimaryNow = false; // was the left hand interacting till now bool wasLeftHandInteracting = isLeftHandInteracting; if (isleftIboxValid && leftHandInteraction && //bLeftHandPrimaryNow && kinectManager.GetJointTrackingState(playerUserID, (int)KinectInterop.JointType.HandLeft) != KinectInterop.TrackingState.NotTracked) { leftHandPos = kinectManager.GetJointPosition(playerUserID, (int)KinectInterop.JointType.HandLeft); leftHandScreenPos.z = Mathf.Clamp01((leftIboxLeftBotBack.z - leftHandPos.z) / (leftIboxLeftBotBack.z - leftIboxRightTopFront.z)); if (!handOverlayCursor) { leftHandScreenPos.x = Mathf.Clamp01((leftHandPos.x - leftIboxLeftBotBack.x) / (leftIboxRightTopFront.x - leftIboxLeftBotBack.x)); leftHandScreenPos.y = Mathf.Clamp01((leftHandPos.y - leftIboxLeftBotBack.y) / (leftIboxRightTopFront.y - leftIboxLeftBotBack.y)); isLeftHandInteracting = (leftHandPos.x >= (leftIboxLeftBotBack.x - 1.0f)) && (leftHandPos.x <= (leftIboxRightTopFront.x + 0.5f)) && (leftHandPos.y >= (leftIboxLeftBotBack.y - 0.1f)) && (leftHandPos.y <= (leftIboxRightTopFront.y + 0.7f)) && (leftIboxLeftBotBack.z >= leftHandPos.z) && (leftIboxRightTopFront.z * 0.8f <= leftHandPos.z); } else { isLeftHandInteracting = GetHandOverlayScreenPos(kinectManager, (int)KinectInterop.JointType.HandLeft, ref leftHandScreenPos) && (leftHandPos.y >= (leftIboxLeftBotBack.y - 0.15f)) && (leftHandPos.y <= (leftIboxRightTopFront.y + 0.7f)) && (leftIboxLeftBotBack.z >= leftHandPos.z) && (leftIboxRightTopFront.z * 0.8f <= leftHandPos.z); } //bLeftHandPrimaryNow = isLeftHandInteracting; // start interacting? if (!wasLeftHandInteracting && isLeftHandInteracting) { leftHandInteractingSince = Time.realtimeSinceStartup; } // check for left press isLeftHandPress = leftHandScreenPos.z > 0.99f; // ((leftIboxRightTopFront.z - 0.1f) >= leftHandPos.z); leftHandPressProgress = (Time.realtimeSinceStartup - lastLeftHandPressTime) >= KinectInterop.Constants.ClickStayDuration && leftHandScreenPos.z >= 0.7f ? (leftHandScreenPos.z - 0.7f) / 0.3f : 0f; // check for left hand click if (!dragInProgress && isLeftHandInteracting && ((allowHandClicks && ((leftHandPos - lastLeftHandPos).magnitude < KinectInterop.Constants.ClickMaxDistance)) || (allowPushToClick && leftHandPressProgress > 0f))) { if ((allowHandClicks && (Time.realtimeSinceStartup - lastLeftHandClickTime) >= KinectInterop.Constants.ClickStayDuration) || (allowPushToClick && leftHandPressProgress > 0.99f && isLeftHandPress)) { if (!isLeftHandClick) { isLeftHandClick = true; cursorClickProgress = leftHandClickProgress = 1f; foreach (InteractionListenerInterface listener in interactionListeners) { if (listener.HandClickDetected(playerUserID, playerIndex, false, leftHandScreenPos)) { isLeftHandClick = false; cursorClickProgress = leftHandClickProgress = 0f; lastLeftHandPos = Vector3.zero; lastLeftHandClickTime = Time.realtimeSinceStartup; lastLeftHandPressTime = Time.realtimeSinceStartup; } } if (controlMouseCursor) { MouseControl.MouseClick(); isLeftHandClick = false; cursorClickProgress = leftHandClickProgress = 0f; lastLeftHandPos = Vector3.zero; lastLeftHandClickTime = Time.realtimeSinceStartup; lastLeftHandPressTime = Time.realtimeSinceStartup; } } } else { // show progress after the 1st half of the needed duration float leftHandTimeProgress = allowHandClicks && (Time.realtimeSinceStartup - lastLeftHandClickTime) >= (KinectInterop.Constants.ClickStayDuration / 2f) ? ((Time.realtimeSinceStartup - lastLeftHandClickTime - (KinectInterop.Constants.ClickStayDuration / 2f)) * 2f / KinectInterop.Constants.ClickStayDuration) : 0f; cursorClickProgress = leftHandClickProgress = allowPushToClick && leftHandScreenPos.z >= 0.7f ? leftHandPressProgress : leftHandTimeProgress; } } else { isLeftHandClick = false; leftHandClickProgress = 0f; lastLeftHandPos = leftHandPos; lastLeftHandClickTime = Time.realtimeSinceStartup; } } else { isLeftHandInteracting = false; isLeftHandPress = false; leftHandPressProgress = 0f; } // get the right hand state handState = (int)kinectManager.GetRightHandState(playerUserID); rHandState = Mathf.Lerp(rHandState, handState, fTimeSmooth); rightHandState = (KinectInterop.HandState)Mathf.RoundToInt(rHandState); // check if the right hand is interacting isRightIboxValid = kinectManager.GetRightHandInteractionBox(playerUserID, ref rightIboxLeftBotBack, ref rightIboxRightTopFront, isRightIboxValid); //bool bRightHandPrimaryNow = false; // was the right hand interacting till now bool wasRightHandInteracting = isRightHandInteracting; if (isRightIboxValid && rightHandInteraction && //bRightHandPrimaryNow && kinectManager.GetJointTrackingState(playerUserID, (int)KinectInterop.JointType.HandRight) != KinectInterop.TrackingState.NotTracked) { rightHandPos = kinectManager.GetJointPosition(playerUserID, (int)KinectInterop.JointType.HandRight); rightHandScreenPos.z = Mathf.Clamp01((rightIboxLeftBotBack.z - rightHandPos.z) / (rightIboxLeftBotBack.z - rightIboxRightTopFront.z)); if (!handOverlayCursor) { rightHandScreenPos.x = Mathf.Clamp01((rightHandPos.x - rightIboxLeftBotBack.x) / (rightIboxRightTopFront.x - rightIboxLeftBotBack.x)); rightHandScreenPos.y = Mathf.Clamp01((rightHandPos.y - rightIboxLeftBotBack.y) / (rightIboxRightTopFront.y - rightIboxLeftBotBack.y)); isRightHandInteracting = (rightHandPos.x >= (rightIboxLeftBotBack.x - 0.5f)) && (rightHandPos.x <= (rightIboxRightTopFront.x + 1.0f)) && (rightHandPos.y >= (rightIboxLeftBotBack.y - 0.1f)) && (rightHandPos.y <= (rightIboxRightTopFront.y + 0.7f)) && (rightIboxLeftBotBack.z >= rightHandPos.z) && (rightIboxRightTopFront.z * 0.8f <= rightHandPos.z); } else { isRightHandInteracting = GetHandOverlayScreenPos(kinectManager, (int)KinectInterop.JointType.HandRight, ref rightHandScreenPos) && (rightHandPos.y >= (rightIboxLeftBotBack.y - 0.15f)) && (rightHandPos.y <= (rightIboxRightTopFront.y + 0.7f)) && (rightIboxLeftBotBack.z >= rightHandPos.z) && (rightIboxRightTopFront.z * 0.8f <= rightHandPos.z); } //bRightHandPrimaryNow = isRightHandInteracting; if (!wasRightHandInteracting && isRightHandInteracting) { rightHandInteractingSince = Time.realtimeSinceStartup; } // check for right press isRightHandPress = rightHandScreenPos.z > 0.99f; // ((rightIboxRightTopFront.z - 0.1f) >= rightHandPos.z); rightHandPressProgress = (Time.realtimeSinceStartup - lastRightHandPressTime) >= KinectInterop.Constants.ClickStayDuration && rightHandScreenPos.z >= 0.7f ? (rightHandScreenPos.z - 0.7f) / 0.3f : 0f; // check for right hand click if (!dragInProgress && isRightHandInteracting && ((allowHandClicks && ((rightHandPos - lastRightHandPos).magnitude < KinectInterop.Constants.ClickMaxDistance)) || (allowPushToClick && rightHandPressProgress > 0f))) { if ((allowHandClicks && (Time.realtimeSinceStartup - lastRightHandClickTime) >= KinectInterop.Constants.ClickStayDuration) || (allowPushToClick && rightHandPressProgress > 0.99f && isRightHandPress)) { if (!isRightHandClick) { isRightHandClick = true; cursorClickProgress = rightHandClickProgress = 1f; foreach (InteractionListenerInterface listener in interactionListeners) { if (listener.HandClickDetected(playerUserID, playerIndex, true, rightHandScreenPos)) { isRightHandClick = false; cursorClickProgress = rightHandClickProgress = 0f; lastRightHandPos = Vector3.zero; lastRightHandClickTime = Time.realtimeSinceStartup; lastRightHandPressTime = Time.realtimeSinceStartup; } } if (controlMouseCursor) { MouseControl.MouseClick(); isRightHandClick = false; cursorClickProgress = rightHandClickProgress = 0f; lastRightHandPos = Vector3.zero; lastRightHandClickTime = Time.realtimeSinceStartup; lastRightHandPressTime = Time.realtimeSinceStartup; } } } else { // show progress after the 1st half of the needed duration float rightHandTimeProgress = allowHandClicks && (Time.realtimeSinceStartup - lastRightHandClickTime) >= (KinectInterop.Constants.ClickStayDuration / 2f) ? ((Time.realtimeSinceStartup - lastRightHandClickTime - (KinectInterop.Constants.ClickStayDuration / 2f)) * 2f / KinectInterop.Constants.ClickStayDuration) : 0f; cursorClickProgress = rightHandClickProgress = allowPushToClick && rightHandScreenPos.z >= 0.7f ? rightHandPressProgress : rightHandTimeProgress; } } else { isRightHandClick = false; rightHandClickProgress = 0f; lastRightHandPos = rightHandPos; lastRightHandClickTime = Time.realtimeSinceStartup; } } else { isRightHandInteracting = false; isRightHandPress = false; rightHandPressProgress = 0f; } // stop the cursor click progress, if both left and right hand are not clicking if (leftHandClickProgress == 0f && rightHandClickProgress == 0f && cursorClickProgress > 0f) { cursorClickProgress = 0f; } // if both hands are interacting, check which one interacts longer than the other if (isLeftHandInteracting && isRightHandInteracting) { if (rightHandInteractingSince <= leftHandInteractingSince) isLeftHandInteracting = false; else isRightHandInteracting = false; } // if left hand just stopped interacting, send extra non-interaction event if (wasLeftHandInteracting && !isLeftHandInteracting) { foreach (InteractionListenerInterface listener in interactionListeners) { if (lastLeftHandEvent == HandEventType.Grip) listener.HandReleaseDetected(playerUserID, playerIndex, false, true, leftHandScreenPos); } lastLeftHandEvent = HandEventType.Release; } // if right hand just stopped interacting, send extra non-interaction event if (wasRightHandInteracting && !isRightHandInteracting) { foreach (InteractionListenerInterface listener in interactionListeners) { if (lastRightHandEvent == HandEventType.Grip) listener.HandReleaseDetected(playerUserID, playerIndex, true, true, rightHandScreenPos); } lastRightHandEvent = HandEventType.Release; } // process left hand handEvent = HandStateToEvent(leftHandState, lastLeftHandEvent); if ((isLeftHandInteracting != isLeftHandPrimary) || (isRightHandInteracting != isRightHandPrimary)) { if (controlMouseCursor && dragInProgress) { MouseControl.MouseRelease(); dragInProgress = false; } lastLeftHandEvent = HandEventType.Release; lastRightHandEvent = HandEventType.Release; } if (controlMouseCursor && (handEvent != lastLeftHandEvent)) { if (controlMouseDrag && !dragInProgress && (handEvent == HandEventType.Grip)) { dragInProgress = true; MouseControl.MouseDrag(); } else if (dragInProgress && (handEvent == HandEventType.Release)) { MouseControl.MouseRelease(); dragInProgress = false; } } leftHandEvent = handEvent; if (handEvent != HandEventType.None) { // no clicks, while hand grip is detected if (leftHandEvent == HandEventType.Grip && leftHandClickProgress > 0f) { cursorClickProgress = leftHandClickProgress = 0f; lastLeftHandClickTime = Time.realtimeSinceStartup; } if (leftHandEvent != lastLeftHandEvent) { // invoke interaction listeners foreach (InteractionListenerInterface listener in interactionListeners) { if (leftHandEvent == HandEventType.Grip) listener.HandGripDetected(playerUserID, playerIndex, false, isLeftHandInteracting, leftHandScreenPos); else if (leftHandEvent == HandEventType.Release) listener.HandReleaseDetected(playerUserID, playerIndex, false, isLeftHandInteracting, leftHandScreenPos); } } lastLeftHandEvent = handEvent; } // if the hand is primary, set the cursor position if (isLeftHandInteracting) { isLeftHandPrimary = true; if (leftHandClickProgress < 0.8f) // stop the cursor after 80% click progress { float smooth = smoothFactor * Time.deltaTime; if (smooth == 0f) smooth = 1f; cursorScreenPos = Vector3.Lerp(cursorScreenPos, leftHandScreenPos, smooth); } // move mouse-only if there is no cursor texture if (controlMouseCursor && (!guiHandCursor || (!gripHandTexture && !releaseHandTexture && !normalHandTexture))) { MouseControl.MouseMove(cursorScreenPos, debugText); } } else { isLeftHandPrimary = false; } // process right hand handEvent = HandStateToEvent(rightHandState, lastRightHandEvent); if (controlMouseCursor && (handEvent != lastRightHandEvent)) { if (controlMouseDrag && !dragInProgress && (handEvent == HandEventType.Grip)) { dragInProgress = true; MouseControl.MouseDrag(); } else if (dragInProgress && (handEvent == HandEventType.Release)) { MouseControl.MouseRelease(); dragInProgress = false; } } rightHandEvent = handEvent; if (handEvent != HandEventType.None) { // no clicks, while hand grip is detected if (rightHandEvent == HandEventType.Grip && rightHandClickProgress > 0f) { cursorClickProgress = rightHandClickProgress = 0f; lastRightHandClickTime = Time.realtimeSinceStartup; } if (rightHandEvent != lastRightHandEvent) { // invoke interaction listeners foreach (InteractionListenerInterface listener in interactionListeners) { if (rightHandEvent == HandEventType.Grip) listener.HandGripDetected(playerUserID, playerIndex, true, isRightHandInteracting, rightHandScreenPos); else if (rightHandEvent == HandEventType.Release) listener.HandReleaseDetected(playerUserID, playerIndex, true, isRightHandInteracting, rightHandScreenPos); } } lastRightHandEvent = handEvent; } // if the hand is primary, set the cursor position if (isRightHandInteracting) { isRightHandPrimary = true; if (rightHandClickProgress < 0.8f) // stop the cursor after 80% click progress { float smooth = smoothFactor * Time.deltaTime; if (smooth == 0f) smooth = 1f; cursorScreenPos = Vector3.Lerp(cursorScreenPos, rightHandScreenPos, smooth); } // move mouse-only if there is no cursor texture if (controlMouseCursor && (!guiHandCursor || (!gripHandTexture && !releaseHandTexture && !normalHandTexture))) { MouseControl.MouseMove(cursorScreenPos, debugText); } } else { isRightHandPrimary = false; } } else { // send release events if (lastLeftHandEvent == HandEventType.Grip || lastRightHandEvent == HandEventType.Grip) { foreach (InteractionListenerInterface listener in interactionListeners) { if (lastLeftHandEvent == HandEventType.Grip) listener.HandReleaseDetected(lastUserID, playerIndex, false, true, leftHandScreenPos); if (lastRightHandEvent == HandEventType.Grip) listener.HandReleaseDetected(lastUserID, playerIndex, true, true, leftHandScreenPos); } } leftHandState = KinectInterop.HandState.NotTracked; rightHandState = KinectInterop.HandState.NotTracked; isLeftHandPrimary = isRightHandPrimary = false; isLeftHandInteracting = isRightHandInteracting = false; leftHandInteractingSince = rightHandInteractingSince = 0f; isLeftHandClick = isRightHandClick = false; cursorClickProgress = leftHandClickProgress = rightHandClickProgress = 0f; lastLeftHandClickTime = lastRightHandClickTime = Time.realtimeSinceStartup; lastLeftHandPressTime = lastRightHandPressTime = Time.realtimeSinceStartup; isLeftHandPress = false; isRightHandPress = false; leftHandPressProgress = 0f; rightHandPressProgress = 0f; leftHandEvent = HandEventType.None; rightHandEvent = HandEventType.None; lastLeftHandEvent = HandEventType.Release; lastRightHandEvent = HandEventType.Release; if (controlMouseCursor && dragInProgress) { MouseControl.MouseRelease(); dragInProgress = false; } } // update cursor texture and position UpdateGUI(); } } // updates cursor texture and position private void UpdateGUI() { if (!interactionInited) return; // display debug information if (debugText) { string sGuiText = string.Empty; //if(isLeftHandPrimary) { sGuiText += "L.Hand" + (isLeftHandInteracting ? "*: " : " : ") + leftHandScreenPos.ToString(); if (lastLeftHandEvent == HandEventType.Grip) { sGuiText += " LeftGrip"; } else if (lastLeftHandEvent == HandEventType.Release) { sGuiText += " LeftRelease"; } if (isLeftHandClick) { sGuiText += " LeftClick"; } //else if (leftHandClickProgress > 0.5f) //{ // sGuiText += String.Format(" {0:F0}%", leftHandClickProgress * 100); //} if (isLeftHandPress) { sGuiText += " LeftPress"; } //sGuiText += " " + leftHandClickProgress; } //if(isRightHandPrimary) { sGuiText += "\nR.Hand" + (isRightHandInteracting ? "*: " : " : ") + rightHandScreenPos.ToString(); if (lastRightHandEvent == HandEventType.Grip) { sGuiText += " RightGrip"; } else if (lastRightHandEvent == HandEventType.Release) { sGuiText += " RightRelease"; } if (isRightHandClick) { sGuiText += " RightClick"; } //else if (rightHandClickProgress > 0.5f) //{ // sGuiText += String.Format(" {0:F0}%", rightHandClickProgress * 100); //} if (isRightHandPress) { sGuiText += " RightPress"; } //sGuiText += " " + rightHandClickProgress; } debugText.text = sGuiText; } // display the cursor status and position if (guiHandCursor) { Sprite cursorTexture = null; if (isLeftHandPrimary) { if (lastLeftHandEvent == HandEventType.Grip) cursorTexture = gripHandTexture; else if (lastLeftHandEvent == HandEventType.Release) cursorTexture = releaseHandTexture; } else if (isRightHandPrimary) { if (lastRightHandEvent == HandEventType.Grip) cursorTexture = gripHandTexture; else if (lastRightHandEvent == HandEventType.Release) cursorTexture = releaseHandTexture; } if (cursorTexture == null) { cursorTexture = normalHandTexture; } if ((cursorTexture != null) /**&& (isLeftHandPrimary || isRightHandPrimary)*/) { Vector2 posSprite; if (controlMouseCursor) { MouseControl.MouseMove(cursorScreenPos, debugText); posSprite = new Vector2(Input.mousePosition.x, Input.mousePosition.y); } else { Rect rectCanvas = guiHandCursor.canvas.pixelRect; float canvasScale = guiHandCursor.canvas.scaleFactor; posSprite = new Vector2(cursorScreenPos.x * rectCanvas.width / canvasScale, cursorScreenPos.y * rectCanvas.height / canvasScale); //Debug.Log("PosCursor: " + posSprite + ", Rect: " + rectCanvas + ", Scale: " + canvasScale); } guiHandCursor.sprite = cursorTexture; guiHandCursor.rectTransform.anchoredPosition = posSprite; if (cursorProgressBar) { cursorProgressBar.fillAmount = cursorClickProgress; } } } } // estimates screen cursor overlay position for the given hand private bool GetHandOverlayScreenPos(KinectManager kinectManager, int iHandJointIndex, ref Vector3 handScreenPos) { Vector3 posJointRaw = kinectManager.GetJointKinectPosition(playerUserID, iHandJointIndex, false); if (posJointRaw != Vector3.zero) { Vector2 posDepth = kinectManager.MapSpacePointToDepthCoords(sensorIndex, posJointRaw); ushort depthValue = kinectManager.GetDepthForPixel(sensorIndex, posDepth); if (posDepth != Vector2.zero && depthValue > 0) { // depth pos to color pos Vector2 posColor = kinectManager.MapDepthPointToColorCoords(sensorIndex, posDepth, depthValue); if (posColor.x != 0f && !float.IsInfinity(posColor.x)) { float clrImageW = kinectManager.GetColorImageWidth(sensorIndex); float clrImageH = kinectManager.GetColorImageHeight(sensorIndex); // get the color image x-offset and width (use the portrait background, if available) float colorWidth = clrImageW; float colorOfsX = 0f; PortraitBackground portraitBack = PortraitBackground.Instance; if (portraitBack && portraitBack.enabled) { colorWidth = clrImageH * clrImageH / clrImageW; colorOfsX = (clrImageW - colorWidth) / 2f; } float xScaled = (posColor.x - colorOfsX) / colorWidth; float yScaled = posColor.y / clrImageH; handScreenPos.x = xScaled; handScreenPos.y = 1f - yScaled; return true; } } } return false; } // converts hand state to hand event type public static HandEventType HandStateToEvent(KinectInterop.HandState handState, HandEventType lastEventType) { switch (handState) { case KinectInterop.HandState.Open: return HandEventType.Release; case KinectInterop.HandState.Closed: case KinectInterop.HandState.Lasso: return HandEventType.Grip; case KinectInterop.HandState.Unknown: return lastEventType; } return HandEventType.None; } } }