Esempio n. 1
0
        private static void Chord(ConsoleKeyInfo?key = null, object arg = null)
        {
            if (!key.HasValue)
            {
                throw new ArgumentNullException("key");
            }

            Dictionary <ConsoleKeyInfo, KeyHandler> secondKeyDispatchTable;

            if (_singleton._chordDispatchTable.TryGetValue(key.Value, out secondKeyDispatchTable))
            {
                if (_singleton._demoMode)
                {
                    // Render so the first key of the chord appears in the demo window
                    _singleton.Render();
                }
                var secondKey = ReadKey();
                _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg);
            }
        }
Esempio n. 2
0
        private static ConsoleKeyInfo ReadKey()
        {
            // Reading a key is handled on a different thread.  During process shutdown,
            // PowerShell will wait in it's ConsoleCtrlHandler until the pipeline has completed.
            // If we're running, we're most likely blocked waiting for user input.
            // This is a problem for two reasons.  First, exiting takes a long time (5 seconds
            // on Win8) because PowerShell is waiting forever, but the OS will forcibly terminate
            // the console.  Also - if there are any event handlers for the engine event
            // PowerShell.Exiting, those handlers won't get a chance to run.
            //
            // By waiting for a key on a different thread, our pipeline execution thread
            // (the thread Readline is called from) avoid being blocked in code that can't
            // be unblocked and instead blocks on events we control.

            // First, set an event so the thread to read a key actually attempts to read a key.
            _singleton._readKeyWaitHandle.Set();

            int        handleId;
            PowerShell ps = null;

            try
            {
                while (true)
                {
                    // Next, wait for one of three things:
                    //   - a key is pressed
                    //   - the console is exiting
                    //   - 300ms - to process events if we're idle

                    handleId = WaitHandle.WaitAny(_singleton._requestKeyWaitHandles, 300);
                    if (handleId != WaitHandle.WaitTimeout)
                    {
                        break;
                    }

                    // If we timed out, check for event subscribers (which is just
                    // a hint that there might be an event waiting to be processed.)
                    var eventSubscribers = _singleton._engineIntrinsics.Events.Subscribers;
                    if (eventSubscribers.Count > 0)
                    {
                        bool runPipelineForEventProcessing = false;
                        foreach (var sub in eventSubscribers)
                        {
                            if (sub.SourceIdentifier.Equals("PowerShell.OnIdle", StringComparison.OrdinalIgnoreCase))
                            {
                                // There is an OnIdle event.  We're idle because we timed out.  Normally
                                // PowerShell generates this event, but PowerShell assumes the engine is not
                                // idle because it called PSConsoleHostReadline which isn't returning.
                                // So we generate the event intstead.
                                _singleton._engineIntrinsics.Events.GenerateEvent("PowerShell.OnIdle", null, null, null);
                                runPipelineForEventProcessing = true;
                                break;
                            }

                            // If there are any event subscribers that have an action (which might
                            // write to the console) and have a source object (i.e. aren't engine
                            // events), run a tiny useless bit of PowerShell so that the events
                            // can be processed.
                            if (sub.Action != null && sub.SourceObject != null)
                            {
                                runPipelineForEventProcessing = true;
                                break;
                            }
                        }

                        if (runPipelineForEventProcessing)
                        {
                            if (ps == null)
                            {
                                ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
                                ps.AddScript("0");
                            }

                            // To detect output during possible event processing, see if the cursor moved
                            // and rerender if so.
                            var y = Console.CursorTop;
                            ps.Invoke();
                            if (y != Console.CursorTop)
                            {
                                _singleton._initialY = Console.CursorTop;
                                _singleton.Render();
                            }
                        }
                    }
                }
            }
            finally
            {
                if (ps != null)
                {
                    ps.Dispose();
                }
            }

            if (handleId == 1)
            {
                // The console is exiting - throw an exception to unwind the stack to the point
                // where we can return from ReadLine.
                if (_singleton.Options.HistorySaveStyle == HistorySaveStyle.SaveAtExit)
                {
                    _singleton.SaveHistoryAtExit();
                }
                _singleton._historyFileMutex.Dispose();

                throw new OperationCanceledException();
            }
            var key = _singleton._queuedKeys.Dequeue();

            if (_singleton._captureKeys)
            {
                _singleton._savedKeys.Enqueue(key);
            }
            return(key);
        }