From 5528826ee605c910bd2b6b6eca8c27239215f48a Mon Sep 17 00:00:00 2001 From: SeanPesce Date: Mon, 4 Sep 2017 22:09:55 -0400 Subject: [PATCH] -Implement console input autocomplete preview -Add new config preference: ShowAutoCompletePreview -Add new console command: console_autocomplete_preview -Modify functionality of up/down arrow keys when in-game console is open: If autocomplete suggestions exist for current input, up/down arrows cycle through the suggestions --- include/SpD3D9OConsole.h | 5 +++ rsrc/d3d9_Mod.ini | 1 + src/SpD3D9OConsole.cpp | 75 ++++++++++++++++++++++++---------- src/SpD3D9OConsoleCommands.cpp | 37 ++++++++++++++++- 4 files changed, 96 insertions(+), 22 deletions(-) diff --git a/include/SpD3D9OConsole.h b/include/SpD3D9OConsole.h index 564efb1..1a267ff 100644 --- a/include/SpD3D9OConsole.h +++ b/include/SpD3D9OConsole.h @@ -31,6 +31,7 @@ #define _SP_D3D9O_C_PREF_KEY_CARET_BLINK_ "CaretBlinkDelay" #define _SP_D3D9O_C_PREF_KEY_BORDER_WIDTH_ "BorderWidth" #define _SP_D3D9O_C_PREF_KEY_OUTPUT_LINES_ "OutputLines" +#define _SP_D3D9O_C_PREF_KEY_AUTOCOMPLETE_PREVIEW_ "ShowAutoCompletePreview" #define _SP_D3D9O_C_PREF_KEY_AUTOCOMPLETE_LIMIT_ "AutoCompleteLimit" #define _SP_D3D9O_C_PREF_KEY_CURSOR_SHOW_ "ShowMouseCursor" #define _SP_D3D9O_C_PREF_KEY_CURSOR_SIZE_ "MouseCursorSize" @@ -57,12 +58,14 @@ #define _SP_D3D9O_C_DEFAULT_BACKGROUND_COLOR_ D3DXCOLOR(0.0f, 0.0f, 0.0f, 0.5f) // Black #define _SP_D3D9O_C_DEFAULT_BORDER_COLOR_ D3DXCOLOR(0.5f, 0.5f, 0.5f, 0.5f) // Gray #define _SP_D3D9O_C_DEFAULT_BORDER_WIDTH_ 3 +#define _SP_D3D9O_C_DEFAULT_AUTOCOMP_PREVIEW_COLOR_ D3DXCOLOR(0.65f, 0.65f, 0.65f, 0.5f) // Slightly lighter gray #define _SP_D3D9O_C_DEFAULT_AUTOCOMP_BACKGROUND_COLOR_ _SP_D3D9O_C_DEFAULT_BACKGROUND_COLOR_ #define _SP_D3D9O_C_DEFAULT_AUTOCOMP_BACKGROUND_HOVER_COLOR_ D3DXCOLOR(0xFF1C1C1C) // Very dark gray #define _SP_D3D9O_C_DEFAULT_AUTOCOMP_BACKGROUND_SELECT_COLOR_ D3DXCOLOR(0xFF333333) // Dark gray #define _SP_D3D9O_C_DEFAULT_AUTOCOMP_BORDER_COLOR_ _SP_D3D9O_C_DEFAULT_BORDER_COLOR_ #define _SP_D3D9O_C_DEFAULT_AUTOCOMP_BORDER_WIDTH_ 1 #define _SP_D3D9O_C_DEFAULT_OUTPUT_LINES_ 15 +#define _SP_D3D9O_C_DEFAULT_SHOW_AUTOCOMP_PREVIEW_ true #define _SP_D3D9O_C_DEFAULT_AUTOCOMPLETE_LIMIT_ 5 #define _SP_D3D9O_C_DEFAULT_PROMPT_ELEMENTS_ (SP_D3D9O_PROMPT_ELEMENTS_DISABLED) #define _SP_D3D9O_C_DEFAULT_CURSOR_SHOW_ true @@ -90,6 +93,7 @@ typedef struct SP_D3D9O_CONSOLE_COLORS { D3DXCOLOR text_cursor = _SP_D3D9O_C_DEFAULT_CURSOR_COLOR_; // Color of the text-selection cursor D3DXCOLOR background = _SP_D3D9O_C_DEFAULT_BACKGROUND_COLOR_; // Main console window background color D3DXCOLOR border = _SP_D3D9O_C_DEFAULT_BORDER_COLOR_; // Main console window border color + D3DXCOLOR autocomplete_preview = _SP_D3D9O_C_DEFAULT_AUTOCOMP_PREVIEW_COLOR_; // Autocomplete preview text (appears after current input string, showing the remaining substring of the selected autocomplete suggestion) D3DXCOLOR autocomplete_bg = _SP_D3D9O_C_DEFAULT_AUTOCOMP_BACKGROUND_COLOR_; // Normal background color for autocomplete box D3DXCOLOR autocomplete_border = _SP_D3D9O_C_DEFAULT_AUTOCOMP_BORDER_COLOR_; // Autocomplete box border color D3DXCOLOR autocomplete_bg_hover = _SP_D3D9O_C_DEFAULT_AUTOCOMP_BACKGROUND_HOVER_COLOR_; // Background color for autocomplete entry when mouse cursor is hovering, but right mouse button is not pressed @@ -185,6 +189,7 @@ class SpD3D9OConsole CONSOLE_TEXT_SELECTION selection; // Struct that holds cursor selection data unsigned int command_log_position = 0; // Used to obtain previous commands with the up/down keys + bool autocomplete_preview = _SP_D3D9O_C_DEFAULT_SHOW_AUTOCOMP_PREVIEW_; // Enable/disable currently-selected autocomplete suggestion preview in input field unsigned int autocomplete_limit = _SP_D3D9O_C_DEFAULT_AUTOCOMPLETE_LIMIT_; // Maximum number of autocomplete suggestions to show // Constructor/destructor diff --git a/rsrc/d3d9_Mod.ini b/rsrc/d3d9_Mod.ini index c39ef60..ceafb62 100644 --- a/rsrc/d3d9_Mod.ini +++ b/rsrc/d3d9_Mod.ini @@ -44,6 +44,7 @@ Caret=_ CaretBlinkDelay=500 BorderWidth=3 OutputLines=15 +ShowAutoCompletePreview=1 AutoCompleteLimit=5 ShowMouseCursor=1 MouseCursorSize=16 diff --git a/src/SpD3D9OConsole.cpp b/src/SpD3D9OConsole.cpp index caec20f..ed97c96 100644 --- a/src/SpD3D9OConsole.cpp +++ b/src/SpD3D9OConsole.cpp @@ -208,7 +208,7 @@ void SpD3D9OConsole::draw() output_string.append(cur_cmd); std::string input_line = cur_cmd; - // Get autocomplete options + // Build autocomplete options std::string prompt_alignment_spaces; for (int i = 0; i < (int)full_prompt.length(); i++) { @@ -224,6 +224,8 @@ void SpD3D9OConsole::draw() overlay->device->Clear(1, &border, D3DCLEAR_TARGET, color.border, 0, 0); overlay->device->Clear(1, &background, D3DCLEAR_TARGET, color.background, 0, 0); + std::string input_autocomplete_preview = full_prompt; // Autocomplete preview text (appears after current input string, showing the remaining substring of the selected autocomplete suggestion) + // Draw background for autocomplete dropdown if (autocomplete_matches.size() > 0) { @@ -243,12 +245,18 @@ void SpD3D9OConsole::draw() { overlay->device->Clear(1, &background, D3DCLEAR_TARGET, color.autocomplete_bg_hover, 0, 0); } + + // Build autocomplete preview line + input_autocomplete_preview.append(autocomplete_matches.at(selection.autocomplete_selection).substr(input_display_start)); + input_autocomplete_preview = input_autocomplete_preview.substr(0, max_chars); } // Render the console text font->BeginDrawing(); - font->DrawText((float)border_width, (float)border_width, color.text, output_string.c_str(), D3DFONT_COLORTABLE, 0); + if(autocomplete_preview) + font->DrawText((float)border_width, (float)border_width + (char_size.cy * output_log_displayed_lines), color.autocomplete_preview, input_autocomplete_preview.c_str(), 0, 0); // Autocomplete preview + font->DrawText((float)border_width, (float)border_width, color.text, output_string.c_str(), 0, 0); // Output, prompt, and visible input text if (selection.focus == SP_D3D9O_SELECT_TEXT) { draw_highlighted_text(selection, &input_line); @@ -633,8 +641,8 @@ void SpD3D9OConsole::handle_key_press(WPARAM wParam) { DWORD last_err; std::string str; // Used when a temp string is needed - std::vector matches; // Only used if tab key is pressed - int input_sel_start, input_sel_end; // Only used when obtaining selected input + std::vector matches; // Used in cases that access autocomplete suggestions + int input_sel_start, input_sel_end; // Used in cases that need to obtain selected input if (is_open() && !SpD3D9OInputHandler::get()->handled) // If the console is visible, take input { @@ -666,34 +674,52 @@ void SpD3D9OConsole::handle_key_press(WPARAM wParam) SpD3D9OInputHandler::get()->handled = true; break; case VK_UP: - clear_selection(); - if (command_log_position <= 1) + get_autocomplete_options(command.c_str(), autocomplete_limit, &matches); + if (command.length() > 0 && (int)matches.size() > 0) { - command_log_position = 0; + if (selection.autocomplete_selection > 0) + selection.autocomplete_selection--; + else + selection.autocomplete_selection = ((int)matches.size() - 1); } else { - command_log_position--; + clear_selection(); + if (command_log_position <= 1) + command_log_position = 0; + else + command_log_position--; + caret_position = 0; + command = command_log.at(command_log_position); + caret_position = command.length(); } - caret_position = 0; - command = command_log.at(command_log_position); - caret_position = command.length(); SpD3D9OInputHandler::get()->handled = true; break; case VK_DOWN: - clear_selection(); - if (command_log_position < (unsigned int)command_log.size() - 1) + get_autocomplete_options(command.c_str(), autocomplete_limit, &matches); + if (command.length() > 0 && (int)matches.size() > 0) { - caret_position = 0; - command_log_position++; - command = command_log.at(command_log_position); - caret_position = command.length(); + if (selection.autocomplete_selection < ((int)matches.size() - 1)) + selection.autocomplete_selection++; + else + selection.autocomplete_selection = 0; } - else if (command_log_position != (unsigned int)command_log.size()) + else { - caret_position = 0; - command_log_position = (int)command_log.size(); - command.clear(); + clear_selection(); + if (command_log_position < (unsigned int)command_log.size() - 1) + { + caret_position = 0; + command_log_position++; + command = command_log.at(command_log_position); + caret_position = command.length(); + } + else if (command_log_position != (unsigned int)command_log.size()) + { + caret_position = 0; + command_log_position = (int)command_log.size(); + command.clear(); + } } SpD3D9OInputHandler::get()->handled = true; break; @@ -1497,6 +1523,12 @@ void SpD3D9OConsole::get_user_prefs() output_log_displayed_lines = (int)GetPrivateProfileInt(_SP_D3D9O_C_PREF_SECTION_, _SP_D3D9O_C_PREF_KEY_OUTPUT_LINES_, _SP_D3D9O_C_DEFAULT_OUTPUT_LINES_, _SP_D3D9O_C_PREF_FILE_); if (output_log_displayed_lines < 1) output_log_displayed_lines = 1; + + // Show current autocomplete suggestion preview in input field + if ((int)GetPrivateProfileInt(_SP_D3D9O_C_PREF_SECTION_, _SP_D3D9O_C_PREF_KEY_AUTOCOMPLETE_PREVIEW_, _SP_D3D9O_C_DEFAULT_SHOW_AUTOCOMP_PREVIEW_, _SP_D3D9O_C_PREF_FILE_) != 0) + autocomplete_preview = true; + else + autocomplete_preview = false; // Max allowed autocomplete suggestions autocomplete_limit = (int)GetPrivateProfileInt(_SP_D3D9O_C_PREF_SECTION_, _SP_D3D9O_C_PREF_KEY_AUTOCOMPLETE_LIMIT_, _SP_D3D9O_C_DEFAULT_AUTOCOMPLETE_LIMIT_, _SP_D3D9O_C_PREF_FILE_); @@ -1576,6 +1608,7 @@ void SpD3D9OConsole::restore_default_settings() output_log_displayed_lines = _SP_D3D9O_C_DEFAULT_OUTPUT_LINES_; // Number of lines of previous output to display output_log_capacity = _SP_D3D9O_C_DEFAULT_OUTPUT_LOG_CAPACITY_; // Number of lines of output to keep in memory (oldest are deleted when max is hit) command_log_capacity = _SP_D3D9O_C_DEFAULT_COMMAND_LOG_CAPACITY_; // Number of console commands to keep logged (oldest are deleted when max is hit) + autocomplete_preview = _SP_D3D9O_C_DEFAULT_SHOW_AUTOCOMP_PREVIEW_; autocomplete_limit = _SP_D3D9O_C_DEFAULT_AUTOCOMPLETE_LIMIT_; // Maximum number of autocomplete suggestions to show if (output_log_capacity < output_log_displayed_lines) diff --git a/src/SpD3D9OConsoleCommands.cpp b/src/SpD3D9OConsoleCommands.cpp index e071663..ac1f461 100644 --- a/src/SpD3D9OConsoleCommands.cpp +++ b/src/SpD3D9OConsoleCommands.cpp @@ -145,6 +145,10 @@ void console_settings_to_string(std::string *output, const char* line_prefix = _ output->append(line_prefix).append("Console mouse cursor = disabled\n"); } output->append(line_prefix).append("Console mouse cursor size = ").append(std::to_string(gl_pSpD3D9Device->overlay->console->cursor_size)).append("\n"); + if (gl_pSpD3D9Device->overlay->console->autocomplete_preview) + output->append(line_prefix).append("Preview current autocomplete suggestion = enabled\n"); + else + output->append(line_prefix).append("Preview current autocomplete suggestion = disabled\n"); output->append(line_prefix).append("Autocomplete suggestion limit = ").append(std::to_string(gl_pSpD3D9Device->overlay->console->autocomplete_limit)).append("\n"); output->append(line_prefix).append("Border width = ").append(std::to_string(gl_pSpD3D9Device->overlay->console->border_width)).append(" pixels\n"); if (gl_pSpD3D9Device->overlay->console->prompt_elements & SP_D3D9O_PROMPT_USER) @@ -754,6 +758,36 @@ int cc_search_command(std::vector args, std::string *output) } +// Shows/hides remaining characters for the currently-highlighted autocomplete suggestion in the console input field +int cc_autocomplete_preview(std::vector args, std::string *output) +{ + int ret_val = CONSOLE_COMMAND_SUCCESS; + if (args.size() > 0) + { + switch (parse_toggle_arg(args.at(0).c_str())) + { + case 0: + gl_pSpD3D9Device->overlay->console->autocomplete_preview = false; + break; + case 1: + gl_pSpD3D9Device->overlay->console->autocomplete_preview = true; + break; + default: + output->append(ERROR_INVALID_TOGGLE_ARGUMENT); + ret_val = ERROR_INVALID_PARAMETER; + break; + } + } + + if (gl_pSpD3D9Device->overlay->console->autocomplete_preview) + output->append("Preview current autocomplete suggestion = enabled"); + else + output->append("Preview current autocomplete suggestion = disabled"); + + return ret_val; +} + + // Sets the maximum number of autocomplete suggestions (0 = off) int cc_autocomplete_limit(std::vector args, std::string *output) { @@ -2303,7 +2337,8 @@ void register_default_console_commands() SpD3D9OConsole::register_command("console_script", cc_console_script, "console_script \n Opens a plain-text script file and executes each line as a separate console command."); SpD3D9OConsole::register_alias("script", "console_script"); SpD3D9OConsole::register_command("console_font_size", cc_console_font_size, std::string("console_font_size [size]\n Sets the console overlay font size. Font size ranges from ").append(std::to_string(_SP_D3D9O_C_MIN_FONT_SIZE_)).append(" to ").append(std::to_string(_SP_D3D9O_C_MAX_FONT_SIZE_)).append(".").c_str()); - SpD3D9OConsole::register_command("console_autocomplete_limit", cc_autocomplete_limit, "autocomplete_limit [limit]\n Sets the maximum number of autocomplete suggestions to be shown (0 = off)."); + SpD3D9OConsole::register_command("console_autocomplete_preview", cc_autocomplete_preview, "console_autocomplete_preview [is_enabled]\n Shows/hides preview of remaining characters for the currently-highlighted autocomplete suggestion in the console input field (1 = enabled, 0 = disabled)."); + SpD3D9OConsole::register_command("console_autocomplete_limit", cc_autocomplete_limit, "console_autocomplete_limit [limit]\n Sets the maximum number of autocomplete suggestions to be shown (0 = off)."); SpD3D9OConsole::register_command("console_prompt", cc_console_prompt, "console_prompt [prompt]\n Sets the console input prompt string."); SpD3D9OConsole::register_command("console_prompt_user", cc_console_prompt_user, "console_prompt_user [is_enabled]\n Enables/disables the username element of the console input prompt."); SpD3D9OConsole::register_command("console_prompt_hostname", cc_console_prompt_host, "console_prompt_hostname [is_enabled]\n Enables/disables the hostname element of the console input prompt.");