private void ReadOneOrMoreKeys() { _readkeyStopwatch.Restart(); while (_console.KeyAvailable) { // _charMap is only guaranteed to accumulate input while KeyAvailable // returns false. Make sure to check KeyAvailable after every ProcessKey call, // and clear it in a loop in case the input was something like ^[[1 which can // be 3, 2, or part of 1 key depending on timing. _charMap.ProcessKey(_console.ReadKey()); while (_charMap.KeyAvailable) { var key = PSKeyInfo.FromConsoleKeyInfo(_charMap.ReadKey()); _lastNKeys.Enqueue(key); _queuedKeys.Enqueue(key); } if (_readkeyStopwatch.ElapsedMilliseconds > 2) { // Don't spend too long in this loop if there are lots of queued keys break; } } if (_queuedKeys.Count == 0) { while (!_charMap.KeyAvailable) { // Don't want to block when there is an escape sequence being read. if (_charMap.InEscapeSequence) { if (_console.KeyAvailable) { _charMap.ProcessKey(_console.ReadKey()); } else { // We don't want to sleep for the whole escape timeout // or the user will have a laggy console, but there's // nothing to block on at this point either, so do a // small sleep to yield the CPU while we're waiting // to decide what the input was. This will only run // if there are no keys waiting to be read. Thread.Sleep(5); } } else { _charMap.ProcessKey(_console.ReadKey()); } } while (_charMap.KeyAvailable) { var key = PSKeyInfo.FromConsoleKeyInfo(_charMap.ReadKey()); _lastNKeys.Enqueue(key); _queuedKeys.Enqueue(key); } } }
private static void Chord(ConsoleKeyInfo?key = null, object arg = null) { if (!key.HasValue) { throw new ArgumentNullException(nameof(key)); } if (_singleton._chordDispatchTable.TryGetValue(PSKeyInfo.FromConsoleKeyInfo(key.Value), out var secondKeyDispatchTable)) { var secondKey = ReadKey(); _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); } }
/// <summary> /// Chords in vi needs special handling because a numeric argument can be input between the 1st and 2nd key. /// </summary> private static void ViChord(ConsoleKeyInfo?key = null, object arg = null) { if (!key.HasValue) { throw new ArgumentNullException(nameof(key)); } if (arg != null) { Chord(key, arg); return; } if (_singleton._chordDispatchTable.TryGetValue(PSKeyInfo.FromConsoleKeyInfo(key.Value), out var secondKeyDispatchTable)) { var secondKey = ReadKey(); if (secondKeyDispatchTable.TryGetValue(secondKey, out var handler)) { _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); } else if (!IsNumeric(secondKey)) { _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: arg); } else { var argBuffer = _singleton._statusBuffer; argBuffer.Clear(); _singleton._statusLinePrompt = "digit-argument: "; while (IsNumeric(secondKey)) { argBuffer.Append(secondKey.KeyChar); _singleton.Render(); secondKey = ReadKey(); } int numericArg = int.Parse(argBuffer.ToString()); if (secondKeyDispatchTable.TryGetValue(secondKey, out handler)) { _singleton.ProcessOneKey(secondKey, secondKeyDispatchTable, ignoreIfNoAction: true, arg: numericArg); } else { Ding(); } argBuffer.Clear(); _singleton.ClearStatusMessage(render: true); } } }
/// <summary> /// Chords in vi needs special handling because a numeric argument can be input between the 1st and 2nd key. /// </summary> private static void ViChord(ConsoleKeyInfo?key = null, object arg = null) { if (!key.HasValue) { throw new ArgumentNullException(nameof(key)); } if (arg != null) { Chord(key, arg); return; } if (_singleton._chordDispatchTable.TryGetValue(PSKeyInfo.FromConsoleKeyInfo(key.Value), out var secondKeyDispatchTable)) { ViChordHandler(secondKeyDispatchTable, arg); } }
private void SetKeyHandlerInternal(string[] keys, Action <ConsoleKeyInfo?, object> handler, string briefDescription, string longDescription, ScriptBlock scriptBlock) { foreach (var key in keys) { var chord = ConsoleKeyChordConverter.Convert(key); var firstKey = PSKeyInfo.FromConsoleKeyInfo(chord[0]); if (chord.Length == 1) { _dispatchTable[firstKey] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock); } else { _dispatchTable[firstKey] = MakeKeyHandler(Chord, "ChordFirstKey"); if (!_chordDispatchTable.TryGetValue(firstKey, out var secondDispatchTable)) { secondDispatchTable = new Dictionary <PSKeyInfo, KeyHandler>(); _chordDispatchTable[firstKey] = secondDispatchTable; } secondDispatchTable[PSKeyInfo.FromConsoleKeyInfo(chord[1])] = MakeKeyHandler(handler, briefDescription, longDescription, scriptBlock); } } }
private void RemoveKeyHandlerInternal(string[] keys) { foreach (var key in keys) { var chord = ConsoleKeyChordConverter.Convert(key); var firstKey = PSKeyInfo.FromConsoleKeyInfo(chord[0]); if (chord.Length == 1) { _dispatchTable.Remove(firstKey); } else { if (_chordDispatchTable.TryGetValue(firstKey, out var secondDispatchTable)) { secondDispatchTable.Remove(PSKeyInfo.FromConsoleKeyInfo(chord[1])); if (secondDispatchTable.Count == 0) { _dispatchTable.Remove(firstKey); } } } } }
/// <summary> /// Return key handlers bound to specified chords. /// </summary> /// <returns></returns> public static IEnumerable <PowerShell.KeyHandler> GetKeyHandlers(string[] Chord) { var boundFunctions = new HashSet <string>(StringComparer.OrdinalIgnoreCase); if (Chord == null || Chord.Length == 0) { yield break; } foreach (string Key in Chord) { ConsoleKeyInfo[] consoleKeyChord = ConsoleKeyChordConverter.Convert(Key); PSKeyInfo firstKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[0]); if (_singleton._dispatchTable.TryGetValue(firstKey, out KeyHandler entry)) { if (consoleKeyChord.Length == 1) { yield return(new PowerShell.KeyHandler { Key = firstKey.KeyStr, Function = entry.BriefDescription, Description = entry.LongDescription, Group = GetDisplayGrouping(entry.BriefDescription), }); } else { PSKeyInfo secondKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[1]); if (_singleton._chordDispatchTable.TryGetValue(firstKey, out var secondDispatchTable) && secondDispatchTable.TryGetValue(secondKey, out entry)) { yield return(new PowerShell.KeyHandler { Key = firstKey.KeyStr + "," + secondKey.KeyStr, Function = entry.BriefDescription, Description = entry.LongDescription, Group = GetDisplayGrouping(entry.BriefDescription), }); } } } // If in Vi mode, also check Vi's command mode list. if (_singleton._options.EditMode == EditMode.Vi) { if (_viCmdKeyMap.TryGetValue(firstKey, out entry)) { if (consoleKeyChord.Length == 1) { if (entry.BriefDescription == "Ignore") { continue; } yield return(new PowerShell.KeyHandler { Key = "<" + firstKey.KeyStr + ">", Function = entry.BriefDescription, Description = entry.LongDescription, Group = GetDisplayGrouping(entry.BriefDescription), }); } else { PSKeyInfo secondKey = PSKeyInfo.FromConsoleKeyInfo(consoleKeyChord[1]); if (_viCmdChordTable.TryGetValue(firstKey, out var secondDispatchTable) && secondDispatchTable.TryGetValue(secondKey, out entry)) { if (entry.BriefDescription == "Ignore") { continue; } yield return(new PowerShell.KeyHandler { Key = "<" + firstKey.KeyStr + "," + secondKey.KeyStr + ">", Function = entry.BriefDescription, Description = entry.LongDescription, Group = GetDisplayGrouping(entry.BriefDescription), }); } } } } } }