internal void MarkDoneIfYield() { if (ProcessState == KeyProcessState.Yield) { ProcessState = KeyProcessState.Done; Console.WriteLine($"${Name}@Yield->@Done"); } }
internal KeyProcessState Climb(KeyEvent eventType, IKeyEventArgs iargs, TrieNode <ICombination, KeyEventCommand> candidateNode, bool downInChord) { var args = iargs as KeyEventArgsExt; Debug.Assert(args != null, nameof(args) + " != null"); if (args.NoFurtherProcess) { return(ProcessState = KeyProcessState.NoFurtherProcess); } // no match // Chord_downOrUp? or if (candidateNode == null) { if (eventType == KeyEvent.Down) { if (_treeWalker.IsOnRoot) { // AnyKeyNotInRoot_down_or_up: *A_down *A_up is not registered in root _lastKeyDownNodeForAllUp = null; return(ProcessState = KeyProcessState.Yield); } // KeyInChord_down:C+D, A+B A_down if (downInChord) { return(ProcessState = KeyProcessState.Continue); // waiting for trigger key } Reset(); return(ProcessState = KeyProcessState.Reprocess); // to process combination chord up } // allUp design goal: // 1. could register allUp event // 2. navigate when A+B+C_up event not triggered because of chord_up before trigger_up if (_lastKeyDownNodeForAllUp != null && _lastKeyDownNodeForAllUp.Key.IsAnyKey(args.KeyCode)) { if (args.KeyboardState.AreAllUp(_lastKeyDownNodeForAllUp.Key.AllKeys)) { candidateNode = _lastKeyDownNodeForAllUp; eventType = KeyEvent.AllUp; } else { return(ProcessState = KeyProcessState.Continue); } } else { if (_treeWalker.IsOnRoot) { // AnyKeyNotInRoot_down_or_up: *A_down *A_up is not registered in root _lastKeyDownNodeForAllUp = null; return(ProcessState = KeyProcessState.Yield); } // on path, up if (_treeWalker.ChildrenCount == 0) { // NoChild & NotOnRoot: // KeyInChord_up : A+B when A_up. // other keyup: A+B and B mapto C?? Reset(); return(ProcessState = KeyProcessState.Reprocess); // Chord_up would be processed on root } // HaveChild & KeyInChord_up: A+B, C when A_up continue wait C if (_treeWalker.CurrentNode.Key.Chord.Contains(args.KeyCode)) { Console.WriteLine( " would never been here:treeWalker.CurrentNode.Key.Chord.Contains(args.KeyCode)"); Debugger.Break(); return(ProcessState = KeyProcessState.Continue); } //HaveChild & KeyNotInChord_up: B+D, F when C_up. Reset(); return(ProcessState = KeyProcessState.Reprocess); } } args.KeyEvent = eventType; var lastDownHit = ""; if (_lastKeyDownNodeForAllUp != null) { lastDownHit = $"\t↓@{_lastKeyDownNodeForAllUp}"; } Console.WriteLine($"${Name}{lastDownHit}"); // matched var actionList = candidateNode.Values() as KeyActionList <KeyEventCommand>; Debug.Assert(actionList != null, nameof(actionList) + " != null"); // execute #if !DEBUG try { #endif var oneExecuted = false; foreach (var keyCommand in actionList[eventType]) { if (keyCommand.CanExecute != null && !keyCommand.CanExecute(args)) { Console.WriteLine($"\t/!{eventType}\t{keyCommand.Id}\t{keyCommand.Description}"); continue; } oneExecuted = true; var exe = keyCommand.Execute; var isAsync = exe?.Method.GetCustomAttribute(typeof(AsyncStateMachineAttribute)) != null; Console.WriteLine( $"\t!{eventType}{(isAsync ? "_async" : "")}\t{keyCommand.Id}\t{keyCommand.Description}"); exe?.Invoke(args); } if (!oneExecuted && actionList[eventType].Any()) { Console.WriteLine($"All event of type:{eventType} not executable!"); if (eventType == KeyEvent.Up && _lastKeyDownNodeForAllUp != null && _lastKeyDownNodeForAllUp.Key.Chord.Contains(args.KeyCode)) { return(ProcessState = KeyProcessState.Continue); } Reset(); return(ProcessState = KeyProcessState.Yield); // all not executable, state of the eventType disabled } #if !DEBUG } catch (Exception e) { MessageBox.Show(e.ToString()); } #endif if (args.PathToGo != null && !args.PathToGo.SequenceEqual(candidateNode.KeyPath)) // goto state by requiring { if (!_treeWalker.TryGoToState(args.PathToGo, out var state)) { Console.WriteLine($"Couldn't go to state {state}"); } _lastKeyDownNodeForAllUp = null; return(ProcessState = KeyProcessState.Continue); } switch (eventType) { case KeyEvent.Up: { // only navigate on up/AllUp event _treeWalker.GoToChild(candidateNode); if (candidateNode.ChildrenCount == 0) { if (actionList[KeyEvent.AllUp].Any()) { // wait for chord up return(ProcessState = KeyProcessState.Continue); } Notify?.CloseKeysTip(Name); Reset(); return(ProcessState = KeyProcessState.Done); } Notify?.ShowKeysTip(Name, _treeWalker.CurrentNode.Tip); return(ProcessState = KeyProcessState.Continue); } case KeyEvent.AllUp: _lastKeyDownNodeForAllUp = null; // navigate on AllUp event only when not navigated by up // A+B then B_up then A_up would not execute if clause if (_treeWalker.CurrentNode.Equals(candidateNode)) { return(ProcessState); } _treeWalker.GoToChild(candidateNode); if (candidateNode.ChildrenCount == 0) { Reset(); Notify?.CloseKeysTip(Name); return(ProcessState = KeyProcessState.Done); } else { Notify?.ShowKeysTip(Name, _treeWalker.CurrentNode.Tip); return(ProcessState = KeyProcessState.Continue); } case KeyEvent.Down: _lastKeyDownNodeForAllUp = candidateNode; return(ProcessState = KeyProcessState.Continue); default: throw new Exception($"KeyEvent: {eventType} not supported"); } }