/// <summary>
 /// Scrolls all the visible terminal windows to the bottom.
 /// </summary>
 public void ScrollAllToBottom()
 {
     GameTerminal.ScrollToLastLine();
     Terminal1.ScrollToLastLine();
     Terminal2.ScrollToLastLine();
     Terminal3.ScrollToLastLine();
 }
        /// <summary>
        /// Handles the event when the custom tab selection changes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TabCustom_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // When the game tab gets the focus always put the focus into the input box.
            if (CustomTab1.IsSelected && TextInput.Editor != null)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    // Reset the value to 0, it's now been shown.
                    CustomTab1Badge.Value = 0;

                    // In order to get the focus in this instance an UpdateLayout() call has to be called first.
                    UpdateLayout();

                    Terminal1.ScrollToEnd();

                    // When the app is first loaded the Editor was coming up null so we'll just check the nulls
                    // and then default the caret position to 0 if that's the case.
                    TextInput.Editor.CaretIndex = TextInput?.Editor?.Text?.Length ?? 0;
                    TextInput.Editor.Focus();
                }));
            }
            else if (CustomTab2.IsSelected && TextInput.Editor != null)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    // Reset the value to 0, it's now been shown.
                    CustomTab2Badge.Value = 0;

                    // In order to get the focus in this instance an UpdateLayout() call has to be called first.
                    UpdateLayout();

                    Terminal2.ScrollToEnd();

                    // When the app is first loaded the Editor was coming up null so we'll just check the nulls
                    // and then default the caret position to 0 if that's the case.
                    TextInput.Editor.CaretIndex = TextInput?.Editor?.Text?.Length ?? 0;
                    TextInput.Editor.Focus();
                }));
            }
            else if (CustomTab3.IsSelected && TextInput.Editor != null)
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    // Reset the value to 0, it's now been shown.
                    CustomTab3Badge.Value = 0;

                    // In order to get the focus in this instance an UpdateLayout() call has to be called first.
                    UpdateLayout();

                    Terminal3.ScrollToEnd();

                    // When the app is first loaded the Editor was coming up null so we'll just check the nulls
                    // and then default the caret position to 0 if that's the case.
                    TextInput.Editor.CaretIndex = TextInput?.Editor?.Text?.Length ?? 0;
                    TextInput.Editor.Focus();
                }));
            }
        }
        /// <summary>
        /// Updates any properties that need to be updated after the settings are updated.  This deals primarily
        /// with properties that aren't bound through dependency properties.
        /// </summary>
        public void UpdateUISettings()
        {
            // Terminal font
            FontFamily font;

            switch (App.Settings.AvalonSettings.TerminalFont)
            {
            case AvalonSettings.TerminalFonts.Consolas:
                this.ViewModel.TerminalFontFamily = new FontFamily("Consolas");
                break;

            case AvalonSettings.TerminalFonts.CourierNew:
                this.ViewModel.TerminalFontFamily = new FontFamily("Courier New");
                break;

            default:
                this.ViewModel.TerminalFontFamily = new FontFamily("Consolas");
                break;
            }

            this.ViewModel.SpellCheckEnabled = App.Settings.ProfileSettings.SpellChecking;

            // Scroll everything to the last line in case heights/widths/wrapping has changed.
            GameTerminal.ScrollToLastLine();
            Terminal1.ScrollToLastLine();
            Terminal2.ScrollToLastLine();
            Terminal3.ScrollToLastLine();

            // This will allow the main window to go maximize and not cover the task bar on the main window
            // but will maximize over the task bar on 2nd monitors.
            // TODO - Make this work on all monitors
            this.MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
            this.MaxWidth  = SystemParameters.MaximizedPrimaryScreenWidth;

            // The number of seconds in between batch writes for the the database wrapper.
            SqlTasks.SetInterval(App.Settings.AvalonSettings.DatabaseWriteInterval);

            // Apply the border settings by trigger the SizeChanged event.
            this.MainPage_SizeChanged(null, null);

            // Grid Layout
            LoadGridState();
        }
示例#4
0
        /// <summary>
        /// Checks a line to see if any Triggers should fire and if so executes those triggers.
        /// </summary>
        /// <param name="line"></param>
        public async void CheckTriggers(Line line)
        {
            // Don't process if the user has disabled triggers.
            if (!App.Settings.ProfileSettings.TriggersEnabled)
            {
                return;
            }

            // Don't process if the line is blank.
            if (string.IsNullOrWhiteSpace(line.Text))
            {
                return;
            }

            // Replacement triggers come, they actually alter the line in the terminal.
            this.ProcessReplacementTriggers(line);

            // Go through the immutable system triggers, system triggers are silent in that
            // they won't echo to the terminal window, they also don't adhere to attributes like
            // character or enabled.  These can and will have CLR implementations and can be loaded
            // from other DLL's as plugins.  System triggers are also unique in that they are designed
            // to be loaded from a plugin and they don't save their state in the profile.
            foreach (var item in App.InstanceGlobals.SystemTriggers)
            {
                // Skip it if it's not enabled.
                if (!item.Enabled)
                {
                    continue;
                }

                if (item.IsMatch(line.Text))
                {
                    // Run any CLR that might exist.
                    item.Execute();

                    if (item.ExecuteAs == ExecuteType.Command && !string.IsNullOrEmpty(item.Command))
                    {
                        // If it has text but it's not lua, send it to the interpreter.
                        await Interp.Send(item.Command, item.IsSilent, false);
                    }
                    else if ((item.IsLua || item.ExecuteAs == ExecuteType.LuaMoonsharp) && !string.IsNullOrEmpty(item.Command))
                    {
                        var paramList = new string[item.Match.Groups.Count];
                        paramList[0] = line.Text;

                        for (int i = 1; i < item.Match.Groups.Count; i++)
                        {
                            paramList[i] = item.Match.Groups[i].Value;
                        }

                        string luaResult = Interp.ScriptHost.MoonSharp.ExecuteFunction <string>(item.FunctionName, paramList);
                    }

                    // Check if we're supposed to move this line somewhere else.
                    if (item.MoveTo != TerminalTarget.None)
                    {
                        // Create a brand new line (not a shared reference) where this can be shown in the communication window.
                        var commLine = new Line
                        {
                            FormattedText = $"[{Utilities.Utilities.Timestamp()}]: {line.FormattedText}\r\n"
                        };

                        if (item.MoveTo == TerminalTarget.Terminal1)
                        {
                            Terminal1.Append(commLine);

                            if (!App.MainWindow.CustomTab1.IsSelected)
                            {
                                App.MainWindow.CustomTab1Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab1.IsSelected && App.MainWindow.CustomTab1Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab1Badge.Value = 0;
                            }
                        }
                        else if (item.MoveTo == TerminalTarget.Terminal2)
                        {
                            Terminal2.Append(commLine);

                            if (!App.MainWindow.CustomTab2.IsSelected)
                            {
                                App.MainWindow.CustomTab2Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab2.IsSelected && App.MainWindow.CustomTab2Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab2Badge.Value = 0;
                            }
                        }
                        else if (item.MoveTo == TerminalTarget.Terminal3)
                        {
                            Terminal3.Append(commLine);

                            if (!App.MainWindow.CustomTab3.IsSelected)
                            {
                                App.MainWindow.CustomTab3Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab3.IsSelected && App.MainWindow.CustomTab3Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab3Badge.Value = 0;
                            }
                        }
                    }

                    // This breaks instead of returning, no more system triggers would be processed but user
                    // ones might.
                    if (item.StopProcessing)
                    {
                        // To help with debugging.
                        if (App.Settings.AvalonSettings.Debug)
                        {
                            App.Conveyor.EchoLog("System trigger matched that stops the processing of the rest of the trigger list.", LogType.Debug);
                        }

                        break;
                    }
                }
            }

            // Go through the TriggerList which are user defined triggers.
            foreach (var item in App.Settings.ProfileSettings.TriggerList.EnabledEnumerable())
            {
                // Skip it if it's not global or for this character.
                if (!string.IsNullOrWhiteSpace(item.Character) && item.Character != App.Conveyor.GetVariable("Character"))
                {
                    continue;
                }

                if (item.IsMatch(line.Text))
                {
                    // Run any CLR that might exist.
                    item.Execute();

                    // Increment the counter.
                    item.Count++;

                    // Line Highlighting if the trigger is supposed to.  Insert the ANSI color at the start of the line.
                    if (item.HighlightLine)
                    {
                        // TODO - Allow the highlighted color to be set for each trigger.
                        int start = GameTerminal.Document.Text.LastIndexOf(line.FormattedText, StringComparison.Ordinal);
                        GameTerminal.Document.Insert(start, AnsiColors.DarkCyan);
                    }

                    // Only send if it has something in it.  Use the processed command.
                    if (item.ExecuteAs == ExecuteType.Command && !string.IsNullOrEmpty(item.ProcessedCommand))
                    {
                        // If it has text but it's not lua, send it to the interpreter.
                        await Interp.Send(item.ProcessedCommand, false, false);
                    }
                    else if ((item.IsLua || item.ExecuteAs == ExecuteType.LuaMoonsharp) && !string.IsNullOrWhiteSpace(item.Command))
                    {
                        var paramList = new string[item.Match.Groups.Count];
                        paramList[0] = line.Text;

                        for (int i = 1; i < item.Match.Groups.Count; i++)
                        {
                            paramList[i] = item.Match.Groups[i].Value;
                        }

                        // Not sure why the try/catch calling CheckTriggers wasn't catching Lua errors.  Eat
                        // the error here and allow the script host to process it's exception handler which will
                        // echo it to the terminal.
                        try
                        {
                            // We'll send the function we want to call but also the code, if the code has changed
                            // it nothing will be reloaded thus saving memory and calls.  This is why replacing %1
                            // variables is problematic here and why we are forcing the use of Lua varargs (...)
                            _ = await Interp.ScriptHost.MoonSharp.ExecuteFunctionAsync <object>(item.FunctionName, paramList);
                        }
                        catch { }
                    }

                    // Check if we're supposed to move this line somewhere else.
                    if (item.MoveTo != TerminalTarget.None)
                    {
                        // Create a brand new line (not a shared reference) where this can be shown in the communication window.
                        var commLine = new Line
                        {
                            FormattedText = $"[{Utilities.Utilities.Timestamp()}]: {line.FormattedText}\r\n"
                        };

                        if (item.MoveTo == TerminalTarget.Terminal1)
                        {
                            Terminal1.Append(commLine);

                            if (!App.MainWindow.CustomTab1.IsSelected)
                            {
                                App.MainWindow.CustomTab1Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab1.IsSelected && App.MainWindow.CustomTab1Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab1Badge.Value = 0;
                            }
                        }
                        else if (item.MoveTo == TerminalTarget.Terminal2)
                        {
                            Terminal2.Append(commLine);

                            if (!App.MainWindow.CustomTab2.IsSelected)
                            {
                                App.MainWindow.CustomTab2Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab2.IsSelected && App.MainWindow.CustomTab2Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab2Badge.Value = 0;
                            }
                        }
                        else if (item.MoveTo == TerminalTarget.Terminal3)
                        {
                            Terminal3.Append(commLine);

                            if (!App.MainWindow.CustomTab3.IsSelected)
                            {
                                App.MainWindow.CustomTab3Badge.Value++;
                            }
                            else if (App.MainWindow.CustomTab3.IsSelected && App.MainWindow.CustomTab3Badge.Value != 0)
                            {
                                // Only setting this if the value isn't 0 so it doesn't trigger UI processing.
                                App.MainWindow.CustomTab3Badge.Value = 0;
                            }
                        }
                    }

                    // So, if this trigger matches and i has StopProcessing set it will not process any trigger
                    // thereafter.  This lets a savvy user setup a very efficient trigger processing pipeline but
                    // can potentially cause issues if they have something that stops processing but didn't intend
                    // for it (since it would not fire any triggers after).  All triggers are set to process by
                    // default.
                    if (item.StopProcessing)
                    {
                        // To help with debugging.
                        if (App.Settings.AvalonSettings.Debug)
                        {
                            App.Conveyor.EchoLog("Regular trigger matched that stops the processing of the rest of the trigger list.", LogType.Debug);
                        }

                        return;
                    }
                }
            }
        }
示例#5
0
        /// <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;
            }
        }
示例#6
0
        /// <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.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.  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;

                // Setting to see if the comm windows should scroll to the bottom on escape.
                if (App.Settings.AvalonSettings.EscapeScrollsAllTerminalsToBottom)
                {
                    GameTerminal.ScrollToLastLine();
                    Terminal1.ScrollToLastLine();
                    Terminal2.ScrollToLastLine();
                    Terminal3.ScrollToLastLine();
                }

                // 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;
            }
        }