protected void Update() { model.CheckPluginsHaveChanged(); if (model.IsRecording) { model.RecordUpdate(); } // If no keys are pressed then just exit out if (!InputWrapper.AnyKeyOrAxis()) { if (model.IsRecording) { model.RecordFinish(); } foreach (var noLongerPressed in _activeBindings) { // axis commands really benefit from a final "reset to 0" command run -- so do that if (noLongerPressed.KeyChord.HasAxis) { model.EnqueueAction( new BindingEvent { EventName = BindingEvent.ON_BINDING_REPEAT, Command = noLongerPressed.Command, Binding = noLongerPressed, Args = new CommandExecuteEventArgs { KeyBinding = noLongerPressed, Data = 0, IsRepeat = true } } ); } } _activeBindings.Clear(); return; } if (model.IsRecording) { return; } // If we are typing somewhere else, don't listen for keybindings var focusedObject = EventSystem.current.currentSelectedGameObject; if (focusedObject != null && focusedObject.GetComponent <UnityEngine.UI.InputField>() != null) { return; } // get all bindings that match the keys being pressed ordered by the most specific ones first var matches = model.KeyBindings .Where((b) => b.KeyChord.IsBeingPressed()) .OrderByDescending((b) => b.KeyChord.Length) .ToList(); // nothing being pressed if (matches.Count == 0) { _activeBindings.Clear(); return; } // see if anything used to be pressed but is not anymore foreach (var noLongerPressed in _activeBindings.Where((b) => !matches.Contains(b))) { // axis commands really benefit from a final "reset to 0" command run -- so do that if (noLongerPressed.KeyChord.HasAxis) { model.EnqueueAction( new BindingEvent { EventName = BindingEvent.ON_BINDING_UP, Command = noLongerPressed.Command, Binding = noLongerPressed, Args = new CommandExecuteEventArgs { KeyBinding = noLongerPressed, Data = 0, IsRepeat = true } } ); } } // remove only the inactive bindings _activeBindings.RemoveWhere((b) => !matches.Contains(b)); foreach (var binding in matches) { var chord = binding.KeyChord; var action = binding.Action; // did another binding get triggered that is a superset of us? // (or are we a subset of an action that was just triggered) if (_activeBindings.Any((b) => chord.IsProperSubsetOf(b.KeyChord))) { // .. then consider us already tiggered continue; } if (chord.IsBeingRepeated()) { // Check repeat if still holding down last key if (_activeBindings.Any((b) => b.Equals(binding))) { // Still holding down the key... is it time for a repeat? if (Time.unscaledTime >= _chordRepeatTimestamp) { _chordRepeatTimestamp = Time.unscaledTime + binding.Command.RepeatSpeed; model.EnqueueAction( new BindingEvent { EventName = BindingEvent.ON_BINDING_REPEAT, Command = binding.Command, Binding = binding, Args = new CommandExecuteEventArgs { KeyBinding = binding, Data = binding.KeyChord.GetPressedValue(), IsRepeat = true } } ); } } else { _activeBindings.Add(binding); _chordRepeatTimestamp = Time.unscaledTime + binding.Command.RepeatDelay; } } else { // Handle the keypress and set the repeat delay timer model.EnqueueAction( new BindingEvent { EventName = BindingEvent.ON_BINDING_DOWN, Command = binding.Command, Binding = binding, Args = new CommandExecuteEventArgs { KeyBinding = binding, Data = binding.KeyChord.GetPressedValue(), IsRepeat = false } } ); _chordRepeatTimestamp = Time.unscaledTime + binding.Command.RepeatDelay; _activeBindings.Add(binding); } } // run any queue commands for this phase foreach (var e in model.DequeueActionForUpdate()) { var result = e.Execute(); } }