/// <summary> /// This is fired anytime new data is received whether it is a newline or not. This will allow us to /// start putting that data into the window so the user can see it (even if the trigger can't fire until /// the full line is available). Data provided here may or may not be a complete line. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void HandleDataReceived(object sender, string e) { try { // Get a StringBuilder from the shared pool. var sb = Argus.Memory.StringBuilderPool.Take(); sb.Append(e); // Remove unwanted characters sb.RemoveUnsupportedCharacters(); // Nothing is there, perhaps because it was all replaced. Get out early. if (sb.Length == 0) { return; } // Append the data to the terminal as it comes in. GameTerminal.Append(sb); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled) { GameBackBufferTerminal.Append(sb, false); } // Return the StringBuilder to the pool. Argus.Memory.StringBuilderPool.Return(sb); } catch (Exception ex) { this.Interp.Conveyor.EchoError($"ERROR (HandleDataReceived): {ex.Message}"); } }
/// <summary> /// This is fired anytime new data is received whether it is a newline or not. This will allow us to /// start putting that data into the window so the user can see it (even if the trigger can't fire until /// the full line is available). /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void HandleDataReceived(object sender, string e) { try { // Get a StringBuilder from the shared pool. var sb = Argus.Memory.StringBuilderPool.Take(); sb.Append(e); // Remove unwanted characters sb.RemoveUnsupportedCharacters(); // Append the data to the terminal as it comes in. GameTerminal.Append(sb); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled) { GameBackBufferTerminal.Append(sb, false); } // Return the StringBuilder to the pool. Argus.Memory.StringBuilderPool.Return(sb); } catch (Exception ex) { GameTerminal.Append($"ERROR: {ex.Message}", AnsiColors.Red); } }
/// <summary> /// Handles text from the interpreter that needs to be echoed out to the terminal. This text /// does not get checked for triggers, it's an echo that's coming from the interpreter or /// the possibly the Conveyor. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void InterpreterEcho(object sender, EchoEventArgs e) { AvalonTerminal term; if (e == null) { this.Interp.Conveyor.EchoError(" Null EchoEventArgs in InterpreterEcho"); return; } switch (e.Terminal) { case TerminalTarget.None: case TerminalTarget.Main: term = GameTerminal; break; case TerminalTarget.Terminal1: term = Terminal1; CustomTab1Badge.IncrementOrReset(!CustomTab1.IsSelected); break; case TerminalTarget.Terminal2: term = Terminal2; CustomTab2Badge.IncrementOrReset(!CustomTab2.IsSelected); break; case TerminalTarget.Terminal3: term = Terminal3; CustomTab3Badge.IncrementOrReset(!CustomTab3.IsSelected); break; default: term = GameTerminal; break; } if (e.UseDefaultColors) { term.Append(e.Text); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled && e.Terminal == TerminalTarget.Main) { GameBackBufferTerminal.Append(e.Text, false); } } else { term.Append(e.Text, e.ForegroundColor, e.ReverseColors); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled && e.Terminal == TerminalTarget.Main) { GameBackBufferTerminal.Append(e.Text, e.ForegroundColor, e.ReverseColors, false); } } }
/// <summary> /// Shared preview key down logic between the game terminal and it's back buffer. If they have focus this /// will implement page up and page down so that the back buffer will show all of the paging, once it gets /// to the bottom it will disappear. The escape key will send the focus back to the input box hiding the /// back buffer. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GameTerminal_PreviewKeyDown(object sender, KeyEventArgs e) { switch (e.Key) { case Key.PageUp: e.Handled = true; // Back buffer is collapsed, show it, scroll to the bottom of it. if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Collapsed) { GameBackBufferTerminal.ScrollToLastLine(); GameBackBufferTerminal.Visibility = System.Windows.Visibility.Visible; // Since the height of this changed scroll it to the bottom. GameTerminal.ScrollToLastLine(); break; } // If it was already visible, then we PageUp() GameBackBufferTerminal.PageUp(); break; case Key.PageDown: e.Handled = true; // Back buffer is visible then execute a PageDown() if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Visible) { GameBackBufferTerminal.PageDown(); } // Now, if the last line in the back buffer is visible then we can just collapse the // back buffer because the main terminal shows everything at the end. Set the focus // back to the input box if it's not already there. if (GameBackBufferTerminal.IsLastLineVisible()) { GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; TextInput.Editor.Focus(); } break; case Key.Escape: // Collapse the back buffer so it hides it and reclaims the space for the main terminal. GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; // Reset the input history to the default position and clear the text in the input box. Interp.InputHistoryPosition = -1; TextInput.Editor.Text = ""; TextInput.Editor.Focus(); break; } }
/// <summary> /// Handles text from the interpreter that needs to be echo'd out to the terminal. This text /// does not get checked for triggers, it's an echo that's coming from the interpreter or /// the possibly the Conveyor. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void InterpreterEcho(object sender, EventArgs e) { var ea = e as EchoEventArgs; AvalonTerminal term; if (ea == null) { GameTerminal.Append("--> Error: Null EchoEventArgs in InterpreterEcho", AnsiColors.Red); return; } switch (ea.Terminal) { case TerminalTarget.None: case TerminalTarget.Main: term = GameTerminal; break; case TerminalTarget.Communication: term = CommunicationTerminal; break; case TerminalTarget.OutOfCharacterCommunication: term = OocCommunicationTerminal; break; default: term = GameTerminal; break; } if (ea.UseDefaultColors) { term.Append(ea.Text); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled && ea.Terminal == TerminalTarget.Main) { GameBackBufferTerminal.Append(ea.Text, false); } } else { term.Append(ea.Text, ea.ForegroundColor, ea.ReverseColors); // If the back buffer setting is enabled put the data also in there. if (App.Settings.AvalonSettings.BackBufferEnabled && ea.Terminal == TerminalTarget.Main) { GameBackBufferTerminal.Append(ea.Text, ea.ForegroundColor, ea.ReverseColors, false); } } }
/// <summary> /// Pass mouse scrolling off to the back buffer. Probably. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GameTerminal_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { // If no back buffer, don't bother. if (!App.Settings.AvalonSettings.BackBufferEnabled || !App.Settings.AvalonSettings.MouseWheelScrollReroutesToBackBuffer) { return; } // Allowing scrolling down in the main terminal when the back buffer is collapsed. if (e.Delta < 0 && GameBackBufferTerminal.Visibility == Visibility.Collapsed) { e.Handled = false; return; } // Back buffer is collapsed, show it, scroll to the bottom of it. if (GameBackBufferTerminal.Visibility == Visibility.Collapsed) { GameBackBufferTerminal.Visibility = Visibility.Visible; // Scroll via the vertical offset, if not done for some reason the first time the window is shown // it will be at the top. GameBackBufferTerminal.ScrollToLastLine(true); // Since the height of this changed scroll it to the bottom. GameTerminal.ScrollToLastLine(); } else if (GameBackBufferTerminal.Visibility == Visibility.Visible) { if (e.Delta > 0) { this.GameBackBufferTerminal.PageUp(); // This mitigates scrolling up. e.Handled = true; } else { this.GameBackBufferTerminal.PageDown(); // Now, if the last line in the back buffer is visible then we can just collapse the // back buffer because the main terminal shows everything at the end. if (GameBackBufferTerminal.IsLastLineVisible()) { GameBackBufferTerminal.Visibility = Visibility.Collapsed; TextInput.Editor.Focus(); } } } }
/// <summary> /// Mouse wheel scroll handling for the BackBuffer. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GameBackBufferTerminal_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (GameBackBufferTerminal.Visibility == Visibility.Visible) { if (e.Delta < 0) { // Now, if the last line in the back buffer is visible then we can just collapse the // back buffer because the main terminal shows everything at the end. if (GameBackBufferTerminal.IsLastLineVisible()) { GameBackBufferTerminal.Visibility = Visibility.Collapsed; TextInput.Editor.Focus(); } } } }
/// <summary> /// The PreviewKeyDown event for the input text box used to setup special behavior from that box. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Editor_PreviewKeyDown(object sender, KeyEventArgs e) { // So they key's for macros aren't entered into the text box. foreach (var item in App.Settings.ProfileSettings.MacroList) { if ((int)e.Key == item.Key) { e.Handled = true; return; } } switch (e.Key) { case Key.Enter: e.Handled = true; // When a command is entered into the input box. // Make sure the newline didn't make it into the text input, then select all in the box so it can be cleared quickly. TextInput.Editor.Text = TextInput.Editor.Text.Replace("\r", "").Replace("\n", ""); TextInput.Editor.SelectAll(); Interp.Send(TextInput.Editor.Text); // If the user wants the input box to clear after a command, make it so. if (App.Settings.AvalonSettings.InputBoxClearAfterCommand) { TextInput.Editor.Text = ""; } // Set the history count to the end Interp.InputHistoryPosition = -1; break; case Key.Up: e.Handled = false; // If the drop down is open allow the up and down keys to work for it, not history. if (TextInput.IsDropDownOpen) { return; } // Go to the previous item in the history. TextInput.Editor.Text = Interp.InputHistoryNext(); TextInput.Editor.SelectionStart = (TextInput.Editor.Text.Length); TextInput.Editor.SelectionLength = 0; break; case Key.Down: e.Handled = false; // If the drop down is open allow the up and down keys to work for it, not history. if (TextInput.IsDropDownOpen) { return; } // Go to the next item in the history. TextInput.Editor.Text = Interp.InputHistoryPrevious(); TextInput.Editor.SelectionStart = (TextInput.Editor.Text.Length); TextInput.Editor.SelectionLength = 0; break; case Key.PageUp: e.Handled = true; // Back buffer is collapsed, show it, scroll to the bottom of it. if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Collapsed) { GameBackBufferTerminal.ScrollToLastLine(); GameBackBufferTerminal.Visibility = System.Windows.Visibility.Visible; // Since the height of this changed scroll it to the bottom. GameTerminal.ScrollToLastLine(); break; } // If it was already visible, then we PageUp() GameBackBufferTerminal.PageUp(); break; case Key.PageDown: e.Handled = true; // Back buffer is visible then execute a PageDown() if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Visible) { GameBackBufferTerminal.PageDown(); } // Now, if the last line in the back buffer is visible then we can just collapse the // back buffer because the main terminal shows everything at the end. if (GameBackBufferTerminal.IsLastLineVisible()) { GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; TextInput.Editor.Focus(); } break; case Key.Oem5: case Key.OemBackslash: TextInput.Editor.SelectAll(); e.Handled = true; break; case Key.Escape: // Collapse the back buffer so it hides it and reclaims the space for the main terminal. GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; // Reset the input history to the default position and clear the text in the input box. Interp.InputHistoryPosition = -1; TextInput.Editor.Text = ""; break; } }
/// <summary> /// The PreviewKeyDown event for the input text box used to setup special behavior from that box. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Editor_PreviewKeyDown(object sender, KeyEventArgs e) { // So they key's for macros aren't entered into the text box. foreach (var item in App.Settings.ProfileSettings.MacroList) { if ((int)e.Key == item.Key) { e.Handled = true; return; } } switch (e.Key) { case Key.Enter: e.Handled = true; // When a command is entered into the input box. // Make sure the newline didn't make it into the text input, then select all in the box so it can be cleared quickly. TextInput.Editor.Text = TextInput.Editor.Text.RemoveLineEndings(); TextInput.Editor.SelectAll(); Interp.Send(TextInput.Editor.Text); // If the user wants the input box to clear after a command, make it so. if (App.Settings.AvalonSettings.InputBoxClearAfterCommand) { TextInput.Editor.Text = ""; } // Set the history count to the end Interp.InputHistoryPosition = -1; break; case Key.Up: e.Handled = false; // If the drop down is open allow the up and down keys to work for it, not history. if (TextInput.IsDropDownOpen) { return; } // Go to the previous item in the history. TextInput.Editor.Text = Interp.InputHistoryNext(); TextInput.Editor.SelectionStart = (TextInput.Editor.Text.Length); TextInput.Editor.SelectionLength = 0; break; case Key.Down: e.Handled = false; // If the drop down is open allow the up and down keys to work for it, not history. if (TextInput.IsDropDownOpen) { return; } // Go to the next item in the history. TextInput.Editor.Text = Interp.InputHistoryPrevious(); TextInput.Editor.SelectionStart = (TextInput.Editor.Text.Length); TextInput.Editor.SelectionLength = 0; break; case Key.PageUp: e.Handled = true; // Back buffer is collapsed, show it, scroll to the bottom of it. if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Collapsed) { GameBackBufferTerminal.Visibility = System.Windows.Visibility.Visible; // Scroll via the vertical offset, if not done for some reason the first time the window is shown // it will be at the top. GameBackBufferTerminal.ScrollToLastLine(true); // Since the height of this changed scroll it to the bottom. GameTerminal.ScrollToLastLine(); break; } // If it was already visible, then we PageUp() GameBackBufferTerminal.PageUp(); break; case Key.PageDown: e.Handled = true; // Back buffer is visible then execute a PageDown() if (GameBackBufferTerminal.Visibility == System.Windows.Visibility.Visible) { GameBackBufferTerminal.PageDown(); } // Now, if the last line in the back buffer is visible then we can just collapse the // back buffer because the main terminal shows everything at the end. if (GameBackBufferTerminal.IsLastLineVisible()) { GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; TextInput.Editor.Focus(); } break; case Key.Oem5: case Key.OemBackslash: TextInput.Editor.SelectAll(); e.Handled = true; break; case Key.Escape: // Collapse the back buffer so it hides it and reclaims the space for the main terminal. GameBackBufferTerminal.Visibility = System.Windows.Visibility.Collapsed; // Setting to see if the comm windows should scroll to the bottom on escape. if (App.Settings.AvalonSettings.EscapeScrollsAllTerminalsToBottom) { Terminal1.ScrollToLastLine(); Terminal2.ScrollToLastLine(); Terminal3.ScrollToLastLine(); GameTerminal.ScrollToLastLine(); } // Hide the auto completion box if it's open. if (PopupAutoComplete.IsOpen) { PopupAutoComplete.IsOpen = false; } // Reset the input history to the default position and clear the text in the input box. Interp.InputHistoryPosition = -1; TextInput.Editor.Text = ""; break; case Key.Tab: // Auto Complete from command history and/or aliases. e.Handled = true; string command = null; bool ctrl = ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control); bool shift = ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift); // If control is down search aliases, if it's not search the history if (ctrl && !string.IsNullOrWhiteSpace(TextInput.Editor.Text)) { // Aliases var alias = App.Settings.ProfileSettings.AliasList.FirstOrDefault(x => x.AliasExpression.StartsWith(TextInput.Editor.Text, System.StringComparison.OrdinalIgnoreCase)); if (alias != null) { command = alias.AliasExpression; } // If the alias isn't null, put it in the text editor and leave, we're done. If it is, we'll go ahead and // continue on to the history as a fall back. if (!string.IsNullOrWhiteSpace(command)) { TextInput.Editor.Text = command; TextInput.Editor.SelectionStart = TextInput.Editor.Text.Length; return; } } // If shift is down search past input data, if it's not search the history if (shift && App.Settings.AvalonSettings.AutoCompleteWord && !string.IsNullOrWhiteSpace(TextInput.Editor.Text)) { try { TextInput.Editor.SelectCurrentWord(); string word = TextInput.Editor.SelectedText; App.MainWindow.PopupAutoComplete.IsOpen = false; App.MainWindow.PopupAutoComplete.PlacementTarget = TextInput.Editor; App.MainWindow.PopupAutoComplete.Height = 200; App.MainWindow.PopupAutoComplete.Width = 200; App.MainWindow.PopupAutoComplete.HorizontalOffset = App.MainWindow.PopupAutoComplete.Width; App.MainWindow.PopupAutoComplete.VerticalOffset = -200; App.MainWindow.PopupAutoComplete.IsOpen = true; // Get a list of words that match, then reverse it so the newest entries come first. var list = Interp.InputAutoCompleteKeywords.Where(x => x.StartsWith(word, StringComparison.OrdinalIgnoreCase)).Reverse(); PopupAutoCompleteListBox.ItemsSource = list; // Select the first item in the list, then focus the list. PopupAutoCompleteListBox.Focus(); if (PopupAutoCompleteListBox.Items.Count > 0) { PopupAutoCompleteListBox.SelectedIndex = 0; } } catch (Exception ex) { App.Conveyor.EchoLog(ex.Message, LogType.Error); } return; } // If there is no input in the text editor, get the last entered command otherwise search the input // history for the command (searching the latest entries backwards). if (string.IsNullOrWhiteSpace(TextInput.Editor.Text)) { command = Interp.InputHistory.Last(); } else { command = Interp.InputHistory.FindLast(x => x.StartsWith(TextInput.Editor.Text, System.StringComparison.OrdinalIgnoreCase)); } if (!string.IsNullOrWhiteSpace(command)) { TextInput.Editor.Text = command; TextInput.Editor.SelectionStart = TextInput.Editor.Text.Length; } break; } }