ControllerTracker HandleButtonDown(EControllerButton btn, EEventSet event_set) { if ((bitmask_buttons_down & (1U << (int)btn)) == 0) { return(null); /* not actually pressing this button */ } ControllerTracker tracker = FindHandler(event_set); if (tracker != null) { if (tracker == tracker_hover && btn != EControllerButton.Menu) { tracker_hover_lock |= 1U << (int)btn; } ControllerEvent ev = null; switch (btn) { case EControllerButton.Trigger: ev = tracker._i_onTriggerDown; break; case EControllerButton.Grip: ev = tracker._i_onGripDown; break; case EControllerButton.Menu: ev = tracker._i_onMenuClick; break; } tracker._Call(ev, this); } return(tracker); }
public void PickIfBetter(float priority, ref ControllerTracker current_best, ref float current_best_priority) { if (priority > current_best_priority || (priority == current_best_priority && creation_order > current_best.creation_order)) { current_best_priority = priority; current_best = this; } }
void LeaveNow() { ControllerTracker prev = tracker_hover; tracker_hover = null; tracker_hover_lock = 0; prev._Call(prev._i_onLeave, this); SetPointer(""); }
void CallEnterEvents() { if (tracker_hover_next == null) { return; } if (tracker_hover == null) { tracker_hover = tracker_hover_next; tracker_hover._Call(tracker_hover._i_onEnter, this); } Debug.Assert(tracker_hover == tracker_hover_next); }
public void ForceLeave(ControllerTracker single_tracker = null) { if (active_trigger != null && (single_tracker == null || single_tracker == active_trigger)) { DeactivateTrigger(); } if (active_grip != null && (single_tracker == null || single_tracker == active_grip)) { DeactivateGrip(); } if (active_touchpad != null && (single_tracker == null || single_tracker == active_touchpad)) { DeactivateTouchpad(); } if (tracker_hover != null && (single_tracker == null || single_tracker == tracker_hover)) { LeaveNow(); } }
static ControllerTracker GetOrBuildTracker(MonoBehaviour tracker, bool is_hover) { Baroque._EnsureStarted(); ControllerTracker ct; var these_trackers = is_hover ? hover_trackers : global_trackers; if (!these_trackers.TryGetValue(tracker, out ct)) { ct = new ControllerTracker(tracker, is_hover); these_trackers[tracker] = ct; } if (--auto_free_trackers <= 0) { hover_trackers = RemoveDeadTrackers(hover_trackers); global_trackers = RemoveDeadTrackers(global_trackers); auto_free_trackers = (hover_trackers.Count + global_trackers.Count) / 2 + 16; } return(ct); }
ControllerTracker FindHandler(EEventSet event_set) { /* returns either tracker_hover or a global tracker, but one * that can handle the event_set. */ if (tracker_hover != null && (tracker_hover._event_sets & event_set) != 0) { return(tracker_hover); } else { /* look for global trackers */ ControllerTracker best = null; float best_priority = float.NegativeInfinity; foreach (var ct in global_trackers.Values) { if ((ct._event_sets & event_set) != 0 && ct.isActiveAndEnabled) { float priority = ct.computePriority(this); if (priority != float.NegativeInfinity) { ct.PickIfBetter(priority, ref best, ref best_priority); } } } /* If it's a non-concurrent tracker and it is used by the other controller, cancel */ if (best != null && !best.isConcurrent) { foreach (var ctrl in Baroque.GetControllers()) { if (ctrl != this && ctrl.ActiveWith(best)) { return(null); } } } return(best); } }
bool ActiveWith(ControllerTracker ct) { return(ct == tracker_hover || ct == active_trigger || ct == active_grip || ct == active_touchpad); }
static void ResolveControllerConflicts(Controller[] controllers) { Debug.Assert(controllers.Length == 2); /* for now, always exactly two */ Controller left_ctrl = controllers[0]; Controller right_ctrl = controllers[1]; ControllerTracker tracker = left_ctrl.tracker_hover_next; if (tracker != null && tracker == right_ctrl.tracker_hover_next && !tracker.isConcurrent) { /* conflict: both controllers are inside the zone corresponding to * the same, non-Concurrent, ControllerTracker */ Controller forced_out; /* Heuristics, but will never pick whoever has got 'tracker_hover_lock & MANUAL_LOCK' */ if ((right_ctrl.tracker_hover_lock & MANUAL_LOCK) != 0) { forced_out = left_ctrl; } else if (left_ctrl.tracker_hover_lock != 0) { forced_out = right_ctrl; } else if (right_ctrl.tracker_hover_lock != 0) { forced_out = left_ctrl; } else if (right_ctrl.IsClickingNow()) { forced_out = left_ctrl; } else if (left_ctrl.IsClickingNow()) { forced_out = right_ctrl; } else if (right_ctrl.tracker_hover_next_priority > left_ctrl.tracker_hover_next_priority) { forced_out = left_ctrl; } else if (right_ctrl.tracker_hover_next_priority < left_ctrl.tracker_hover_next_priority) { forced_out = right_ctrl; } else if (left_ctrl.touchpadTouched) { forced_out = right_ctrl; } else { forced_out = left_ctrl; } /* Force one of the controllers "out" of the zone, and force a button deactivation if needed. * In principle, afterwards, it is not possible that the tracker remains locked for both * controllers, because tracker_hover_lock == MANUAL_LOCK can only be set if the tracker is * the current hover in the first place and this tracker cannot be current for both. */ if (forced_out.active_trigger == tracker) { forced_out.DeactivateTrigger(); } if (forced_out.active_grip == tracker) { forced_out.DeactivateGrip(); } if (forced_out.active_touchpad == tracker) { forced_out.DeactivateTouchpad(); } forced_out.tracker_hover_next = null; } }
void ReadControllerState() { /* Updates the state fields; updates 'is_tracking' and 'bitmask_buttons'; * /* may cause un-grabbing (deactivating) of buttons and so 'active_*' may be reset to null; * sets 'tracker_hover_next'. */ if (!GetControllerState(ref controllerState)) { bitmask_buttons = 0; bitmask_buttons_down = 0; is_tracking_active = false; tracker_hover_next = null; tracker_hover_lock = 0; ResetVelocityEstimates(); } else { /* read the button state */ uint prev_bitmask_buttons = bitmask_buttons; bool trigclick = (controllerState.rAxis1.x > 0.999f); /* == 1.0: the controller fully 'clicked' */ ulong trigger = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_SteamVR_Trigger)); ulong pad = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_SteamVR_Touchpad)); ulong padtouch = controllerState.ulButtonTouched & (1UL << ((int)EVRButtonId.k_EButton_SteamVR_Touchpad)); ulong grip = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_Grip)); ulong menu = controllerState.ulButtonPressed & (1UL << ((int)EVRButtonId.k_EButton_ApplicationMenu)); /* the bit at 0x400000U means that the trigger was fully clicked during the * previous frame. If the bit is set but we are not fully clicking any more, * then we consider the trigger to be already released even if trigger != 0 * right now (i.e. the trigger is still pressed a lot, just not fully any more). */ if ((bitmask_buttons & 0x400000U) != 0 && !trigclick && trigger != 0) { trigclick = true; /* keep the 0x400000U bit as long as we get trigger != 0 */ trigger = 0; } uint b = 0; if (menu != 0) { b |= (1U << (int)EControllerButton.Menu); } if (grip != 0) { b |= (1U << (int)EControllerButton.Grip); } if (pad != 0) { b |= (1U << (int)EControllerButton.Touchpad); } if (trigger != 0) { b |= (1U << (int)EControllerButton.Trigger); } if (padtouch != 0) { b |= (1U << (int)EControllerButton.TouchpadTouched); } if (trigclick) { b |= 0x400000U; } bitmask_buttons = b; bitmask_buttons_down = bitmask_buttons & ~prev_bitmask_buttons; /* ignore trigger click when grip is down and vice-versa */ if (grip != 0) { bitmask_buttons_down &= ~(1U << (int)EControllerButton.Trigger); } if (trigger != 0) { bitmask_buttons_down &= ~(1U << (int)EControllerButton.Grip); } if (!is_tracking_active) { bitmask_buttons_down = 0; is_tracking_active = true; } } /* un-grab */ if (active_trigger != null && !triggerPressed) { DeactivateTrigger(); } if (active_grip != null && !gripPressed) { DeactivateGrip(); } if (active_touchpad != null && (!touchpadTouched || (active_touchpad_state == ActiveTouchpadState.Action1 && !touchpadPressed))) { DeactivateTouchpad(); } if (is_tracking_active) { /* read the position and rotation, and update the velocity estimates */ current_position = ComputePosition(); current_rotation = transform.rotation; UpdateVelocityEstimates(); /* find the next BaseControllerTracker at that position, taking the highest * priority one. */ var potential = new HashSet <Transform>(); foreach (var coll in GetOverlappingColliders(current_position)) { Transform tr = coll.transform; while (tr != null) { if (!potential.Add(tr)) { break; /* already in the set */ } tr = tr.parent; } } float best_priority = float.NegativeInfinity; ControllerTracker best = null; overlapping_trackers.Clear(); /* should already be cleared, but better safe than sorry */ foreach (Transform tr in potential) { foreach (var tracker in tr.GetComponents <MonoBehaviour>()) { ControllerTracker ct; if (tracker == null || !hover_trackers.TryGetValue(tracker, out ct)) { continue; } float priority = ct.computePriority(this); if (priority == float.NegativeInfinity) { continue; } overlapping_trackers[ct] = priority; ct.PickIfBetter(priority, ref best, ref best_priority); } } /* If tracker_hover_lock is set, we keep tracker_hover. * We still do the loop above in order to get 'overlapping_trackers'. */ if (tracker_hover_lock != 0) { Debug.Assert(tracker_hover != null); tracker_hover_next = tracker_hover; tracker_hover_next_priority = float.PositiveInfinity; } else { tracker_hover_next = best; tracker_hover_next_priority = best_priority; } } }
void CallButtonDown() { const float TOUCHPAD_CLICK_TIME = 0.25f; const EEventSet TouchpadAll = (EEventSet.TouchpadAction1 | EEventSet.TouchpadAction2 | EEventSet.TouchpadAction3); if (bitmask_buttons_down != 0) { if (active_trigger == null) { active_trigger = HandleButtonDown(EControllerButton.Trigger, EEventSet.Trigger); } if (active_grip == null) { active_grip = HandleButtonDown(EControllerButton.Grip, EEventSet.Grip); } HandleButtonDown(EControllerButton.Menu, EEventSet.Menu); /* == Handle the touchpad == */ if ((bitmask_buttons_down & (1U << (int)EControllerButton.TouchpadTouched)) != 0) { /* starting to touch: the only case is "released" => "small delay" */ touch_original_pos2 = touchpadPosition; if (active_touchpad_state == ActiveTouchpadState.None) { Debug.Assert(active_touchpad == null); active_touchpad = FindHandler(TouchpadAll); if (active_touchpad != null) { if (active_touchpad == tracker_hover) { tracker_hover_lock |= 1U << (int)EControllerButton.Touchpad; } EEventSet es = active_touchpad._event_sets; int count = ((es & EEventSet.TouchpadAction1) != 0 ? 1 : 0) + ((es & EEventSet.TouchpadAction2) != 0 ? 1 : 0) + ((es & EEventSet.TouchpadAction3) != 0 ? 1 : 0); float delay = count >= 2 ? TOUCHPAD_CLICK_TIME : 1e-20f; active_touchpad_state = ActiveTouchpadState.SmallDelay; active_touchpad_timeout = GetTime() + delay; touch_original_pos3 = position; } } } if ((bitmask_buttons_down & (1U << (int)EControllerButton.Touchpad)) != 0) { /* pressing: goes to "action 1" if the tracker handles it */ ControllerTracker cs = active_touchpad; if (cs == null) { cs = HandleButtonDown(EControllerButton.Touchpad, EEventSet.TouchpadAction1); } if (cs != null && (cs._event_sets & EEventSet.TouchpadAction1) != 0) { StopTouchpadAction(); active_touchpad_state = ActiveTouchpadState.Action1; active_touchpad = cs; active_touchpad._Call(active_touchpad._i_onTouchPressDown, this); } } } /* == More touchpad handling == */ if (touchpadTouched) { if (active_touchpad_state == ActiveTouchpadState.None || active_touchpad_state == ActiveTouchpadState.SmallDelay) { const float TOUCHPAD_SCROLL_DISTANCE = 0.22f; const float TOUCHPAD_DRAG_SPACE_DISTANCE = 0.08f; ControllerTracker cs = active_touchpad; if (cs == null) { cs = FindHandler(EEventSet.TouchpadAction2 | EEventSet.TouchpadAction3); } if (cs != null) { if ((cs._event_sets & EEventSet.TouchpadAction2) != 0) { /* detect finger movement */ if (Vector2.Distance(touch_original_pos2, touchpadPosition) > TOUCHPAD_SCROLL_DISTANCE) { active_touchpad_timeout = 0; active_touchpad_state = ActiveTouchpadState.Action2; active_touchpad = cs; if (active_touchpad == tracker_hover) { tracker_hover_lock |= 1U << (int)EControllerButton.Touchpad; } scrollWheelVisible |= SWV_SCROLLING; UpdateScrollWheel(); } } if (active_touchpad_state == ActiveTouchpadState.SmallDelay && (cs._event_sets & EEventSet.TouchpadAction3) != 0) { /* detect timeout or controller movement from the "small delay" state */ if (active_touchpad_timeout <= GetTime() || Vector3.Distance(touch_original_pos3, position) > TOUCHPAD_DRAG_SPACE_DISTANCE) { Vector3 saved = current_position; active_touchpad_state = ActiveTouchpadState.Action3; active_touchpad = cs; current_position = touch_original_pos3; active_touchpad._Call(active_touchpad._i_onTouchDown, this); current_position = saved; } } } } } }