private unsafe void OnEvent(InputEventPtr eventPtr) { // Ignore if not a state event. if (!eventPtr.IsA <StateEvent>() && !eventPtr.IsA <DeltaStateEvent>()) { return; } // Fetch device. var device = InputSystem.GetDeviceById(eventPtr.deviceId); if (device == null) { return; } // Go through controls and see if there's anything interesting in the event. var controls = device.allControls; var controlCount = controls.Count; var haveChangedCandidates = false; for (var i = 0; i < controlCount; ++i) { var control = controls[i]; // Skip controls that have no state in the event. var statePtr = control.GetStatePtrFromStateEvent(eventPtr); if (statePtr == null) { continue; } // If the control that cancels has been actuated, abort the operation now. if (!string.IsNullOrEmpty(m_CancelBinding) && InputControlPath.Matches(m_CancelBinding, control) && !control.CheckStateIsAtDefault(statePtr) && control.HasValueChangeInState(statePtr)) { OnCancel(); break; } // Skip noisy controls. if (control.noisy && (m_Flags & Flags.DontIgnoreNoisyControls) == 0) { continue; } // If controls have to match a certain path, check if this one does. if (m_IncludePathCount > 0 && !HavePathMatch(control, m_IncludePaths, m_IncludePathCount)) { continue; } // If controls must not match certain path, make sure the control doesn't. if (m_ExcludePathCount > 0 && HavePathMatch(control, m_ExcludePaths, m_ExcludePathCount)) { continue; } // If we're expecting controls of a certain type, skip if control isn't of // the right type. if (m_ControlType != null && !m_ControlType.IsInstanceOfType(control)) { continue; } // If we're expecting controls to be based on a specific layout, skip if control // isn't based on that layout. if (!m_ExpectedLayout.IsEmpty() && m_ExpectedLayout != control.m_Layout && !InputControlLayout.s_Layouts.IsBasedOn(m_ExpectedLayout, control.m_Layout)) { continue; } // Skip controls that are in their default state. // NOTE: This is the cheapest check with respect to looking at actual state. So // do this first before looking further at the state. if (control.CheckStateIsAtDefault(statePtr)) { continue; } // Skip controls that have no effective value change. // NOTE: This will run the full processor stack and is move involved. if (!control.HasValueChangeInState(statePtr)) { continue; } // If we have a magnitude threshold, see if control passes it. var magnitude = -1f; if (m_MagnitudeThreshold >= 0f) { magnitude = control.EvaluateMagnitude(statePtr); if (magnitude >= 0 && magnitude < m_MagnitudeThreshold) { continue; // No, so skip. } } // Compute score. float score; if (m_OnComputeScore != null) { score = m_OnComputeScore(control, eventPtr); } else { score = magnitude; // We don't want synthetic controls to not be bindable at all but they should // generally cede priority to controls that aren't synthetic. So we bump all // scores of controls that aren't synthetic. if (!control.synthetic) { score += 1f; } } // Control is a candidate. // See if we already singled the control out as a potential candidate. var candidateIndex = m_Candidates.IndexOf(control); if (candidateIndex != -1) { // Yes, we did. So just check whether it became a better candidate than before. if (m_Scores[candidateIndex] < score) { haveChangedCandidates = true; m_Scores[candidateIndex] = score; if (m_WaitSecondsAfterMatch > 0) { m_LastMatchTime = InputRuntime.s_Instance.currentTime; } } } else { // No, so add it. var candidateCount = m_Candidates.Count; m_Candidates.Add(control); ArrayHelpers.AppendWithCapacity(ref m_Scores, ref candidateCount, score); haveChangedCandidates = true; if (m_WaitSecondsAfterMatch > 0) { m_LastMatchTime = InputRuntime.s_Instance.currentTime; } } } if (haveChangedCandidates && !cancelled) { // If we have a callback that wants to control matching, leave it to the callback to decide // whether the rebind is complete or not. Otherwise, just complete. if (m_OnPotentialMatch != null) { SortCandidatesByScore(); m_OnPotentialMatch(this); } else if (m_WaitSecondsAfterMatch <= 0) { OnComplete(); } else { SortCandidatesByScore(); } } }
private void OnEvent(InputEventPtr eventPtr) { // Ignore if not a state event. if (!eventPtr.IsA <StateEvent>() && !eventPtr.IsA <DeltaStateEvent>()) { return; } // Fetch device. var device = InputSystem.GetDeviceById(eventPtr.deviceId); if (device == null) { return; } // Go through controls and see if there's anything interesting in the event. var controls = device.allControls; var controlCount = controls.Count; for (var i = 0; i < controlCount; ++i) { var control = controls[i]; ////TODO: skip noisy controls // Skip controls that have no state in the event. var statePtr = control.GetStatePtrFromStateEvent(eventPtr); if (statePtr == IntPtr.Zero) { continue; } // If we're expecting controls of a certain type, skip if control isn't of // the right type. if (m_ControlType != null && !m_ControlType.IsInstanceOfType(control)) { continue; } // If we're expecting controls to be based on a specific layout, skip if control // isn't based on that layout. if (!m_ExpectedLayout.IsEmpty() && InputControlLayout.s_Layouts.IsBasedOn(m_ExpectedLayout, control.m_Layout)) { continue; } // Skip controls that are in their default state. // NOTE: This is the cheapest check with respect to looking at actual state. So // do this first before looking further at the state. if (control.CheckStateIsAtDefault(statePtr)) { continue; } // Skip controls that have no effective value change. // NOTE: This will run the full processor stack and is move involved. if (!control.HasValueChangeIn(statePtr)) { continue; } // If it's the control that cancels, abort the operation now. if (!string.IsNullOrEmpty(m_CancelBinding) && InputControlPath.Matches(m_CancelBinding, control)) { OnCancel(); break; } m_Candidates.Add(control); OnComplete(); break; } }