コード例 #1
0
ファイル: KeyStateTree.cs プロジェクト: metaseed/Metakey
 internal void MarkDoneIfYield()
 {
     if (ProcessState == KeyProcessState.Yield)
     {
         ProcessState = KeyProcessState.Done;
         Console.WriteLine($"${Name}@Yield->@Done");
     }
 }
コード例 #2
0
ファイル: KeyStateTree.cs プロジェクト: metaseed/Metakey
        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");
            }
        }