#include "../hooks/gui.h" #ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS #define CIMGUI_DEFINE_ENUMS_AND_STRUCTS #endif #include "../devices/smb_at24c64an.h" #include "../key_config.h" #include "cimgui.h" #include "imgui/backends/GL/freeglut.h" #include "imgui_memory_editor.h" static HWND window; /* UI Constants */ const ImVec4 DISABLED_COL = { .7f, .7f, .7f, 1.0f }; const ImVec4 WARN_COL = { 1.0f, 1.0f, .1f, 1.0f }; const ImVec4 DANGER_COL = { 1.0f, .1f, .1f, 1.0f }; struct { const char* name; int index; int pinNum; } JVS_BUTTON_NAMES[JVS_BUTTON_PAIR_COUNT] = { { "Coin", 45 }, { "Start", 17 }, { "Service", 41 }, { "UP", 23 }, { "DOWN", 25 }, { "LEFT", 21 }, { "RIGHT", 19 }, { "Push 1", 27 }, { "Push 2", 29 }, { "Push 3", 31 }, { "Push 4", 33 }, { "Push 5", 35 }, { "Push 6", 37 }, { "Push 7", 39 }, { "Push 8", 47 }, }; const char* RESOLUTION_NAMES[] = { "Unspecified", "640x480", "1024x600", "1024x768", "1280x720", "1280x1024", "1360x768", "1920x1080", }; const char* ORIENTATION_NAMES[] = { "Landscape", "Portrait", }; /* ImGui useful globals */ static ImVec2 vec0 = { 0 }; static ImVec2 vec10 = { 1, 0 }; /* ImGui externs */ extern bool ImGui_ImplWin32_Init(void* hwnd); extern void ImGui_ImplWin32_Shutdown(); extern void ImGui_ImplWin32_NewFrame(); extern bool ImGui_ImplDX9_Init(IDirect3DDevice9* device); extern void ImGui_ImplDX9_Shutdown(); extern void ImGui_ImplDX9_NewFrame(); extern void ImGui_ImplDX9_RenderDrawData(ImDrawData* draw_data); extern bool ImGui_ImplDX9_GetCP(IDirect3DDevice9* pDevice, D3DDEVICE_CREATION_PARAMETERS* CP); extern bool ImGui_ImplGLUT_Init(); extern void ImGui_ImplGLUT_InstallFuncs(); extern void ImGui_ImplGLUT_Shutdown(); extern void ImGui_ImplGLUT_NewFrame(); extern void ImGui_ImplGLUT_ReshapeFunc(int w, int h); extern void ImGui_ImplGLUT_MotionFunc(int x, int y); extern void ImGui_ImplGLUT_MouseFunc(int button, int state, int x, int y); extern void ImGui_ImplGLUT_MouseWheelFunc(int button, int dir, int x, int y); extern void ImGui_ImplGLUT_KeyboardFunc(unsigned char c, int x, int y); extern void ImGui_ImplGLUT_KeyboardUpFunc(unsigned char c, int x, int y); extern void ImGui_ImplGLUT_SpecialFunc(int key, int x, int y); extern void ImGui_ImplGLUT_SpecialUpFunc(int key, int x, int y); extern bool ImGui_ImplOpenGL3_Init(const char* glsl_version); extern void ImGui_ImplOpenGL3_Shutdown(); extern void ImGui_ImplOpenGL3_NewFrame(); extern void ImGui_ImplOpenGL3_RenderDrawData(ImDrawData* draw_data); // TODO: Implement log viewing extern CRITICAL_SECTION logger_lock; void InitImGui(unsigned int hookType, IDirect3DDevice9* pDevice) { if (hookType == UI_HOOK_DX9) { D3DDEVICE_CREATION_PARAMETERS CP; ImGui_ImplDX9_GetCP(pDevice, &CP); window = CP.hFocusWindow; } else if (hookType == UI_HOOK_GLUT) { window = GetActiveWindow(); } igCreateContext(NULL); ImGuiIO* io = igGetIO(); io->IniFilename = NULL; io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; ImFontAtlas_AddFontDefault(io->Fonts, NULL); // ImFontAtlas_Build(io->Fonts); if (hookType == UI_HOOK_DX9) { ImGui_ImplWin32_Init(window); ImGui_ImplDX9_Init(pDevice); } else if (hookType == UI_HOOK_GLUT) { ImGui_ImplGLUT_Init(); ImGui_ImplOpenGL3_Init(NULL); // TODO: This /** * ! Important we can't use InstallFuncs, because it replaces the * ! reshape func, which games use. We handle this manuall ourself. * * // ImGui_ImplGLUT_InstallFuncs(); * // glutReshapeFunc(ImGui_ImplGLUT_ReshapeFunc); */ glutMotionFunc(ImGui_ImplGLUT_MotionFunc); glutPassiveMotionFunc(ImGui_ImplGLUT_MotionFunc); glutMouseFunc(ImGui_ImplGLUT_MouseFunc); glutKeyboardFunc(ImGui_ImplGLUT_KeyboardFunc); glutKeyboardUpFunc(ImGui_ImplGLUT_KeyboardUpFunc); glutSpecialFunc(ImGui_ImplGLUT_SpecialFunc); glutSpecialUpFunc(ImGui_ImplGLUT_SpecialUpFunc); } } void hud_fps() { if (igBegin("FPS", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoNavInputs)) { ImGuiIO* io = igGetIO(); ImVec2 win_pos; win_pos.x = io->DisplaySize.x - 120; win_pos.y = 10; igSetWindowPos_Vec2(win_pos, ImGuiCond_Once); igText("FPS: %.1f", io->Framerate); igText(" dT: %.2fms", 1000 / io->Framerate); } igEnd(); } void hud_eeprom(ImGuiKey open_key) { static MemoryEditor editor; static bool has_init = false; if (!has_init) { MemoryEditor_Init(&editor); editor.Open = false; has_init = true; } if (igIsKeyPressed_Bool(open_key, false)) editor.Open = !editor.Open; // TODO: Less hacky :) extern BYTE EEPROM_DATA[0x2000]; if (editor.Open) MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, sizeof EEPROM_DATA, 0x000); } void hud_sram(ImGuiKey open_key) { static MemoryEditor editor; static bool has_init = false; if (!has_init) { MemoryEditor_Init(&editor); editor.Open = false; has_init = true; } if (igIsKeyPressed_Bool(open_key, false)) editor.Open = !editor.Open; // TODO: Less hacky :) extern LPBYTE SRAM; if (editor.Open) MemoryEditor_DrawWindow(&editor, "SRAM Editor", SRAM, 1024 * 1024, 0x0000); } void igHelpMarker(const char* text) { igTextDisabled("(?)"); if (igIsItemHovered(0)) { igBeginTooltip(); igPushTextWrapPos(igGetFontSize() * 35.0f); igTextUnformatted(text, NULL); igPopTextWrapPos(); igEndTooltip(); } } void AddSetting(const char* name, const char* help) { if (help) { igHelpMarker(help); igSameLine(0.0, -1.0); } igTextUnformatted(name, NULL); igNextColumn(); } bool AddSettingInt(const char* name, const char* help, int* value) { igPushID_Int((int)value); AddSetting(name, help); bool changed = igInputInt("", value, 1, 1, ImGuiInputTextFlags_None); igNextColumn(); igPopID(); return changed; } bool AddSettingBool(const char* name, const char* help, bool* value) { igPushID_Int((int)value); AddSetting(name, help); bool changed = igCheckbox("", value); igNextColumn(); igPopID(); if (changed) save_current_config(); return changed; } bool AddSettingString(const char* name, const char* help, char** value) { igPushID_Int((int)value); AddSetting(name, help); char buffer[512]; snprintf(buffer, _countof(buffer), "%s", *value); buffer[_countof(buffer) - 1] = '\0'; bool changed = igInputText("", buffer, _countof(buffer) - 1, ImGuiInputFlags_None, NULL, NULL); if (changed) { int newLen = strlen(buffer) + 1; *value = realloc(*value, newLen); memcpy(*value, buffer, newLen); save_current_config(); } igNextColumn(); igPopID(); return changed; } bool AddSettingIPv4(const char* name, const char* help, unsigned int* value) { igPushID_Int((int)value); AddSetting(name, help); char buffer[17]; snprintf(buffer, _countof(buffer), "%hhu.%hhu.%hhu.%hhu", (*value >> 24) & 0xff, (*value >> 16) & 0xff, (*value >> 8) & 0xff, (*value) & 0xff); buffer[_countof(buffer) - 1] = '\0'; bool changed = igInputText("", buffer, _countof(buffer) - 1, ImGuiInputFlags_None, NULL, NULL); if (changed) { unsigned char a, b, c, d; size_t n = 0; if (sscanf(buffer, "%hhu.%hhu.%hhu.%hhu%n", &a, &b, &c, &d, &n) == 4 && n == strlen(buffer)) { *value = (a << 24) | (b << 16) | (c << 8) | d; save_current_config(); } else { changed = false; } } igNextColumn(); igPopID(); return changed; } bool igDipsw(const char* label, bool* value) { if (igGetCurrentWindow()->SkipItems) return false; const ImGuiID id = igGetID_Str(label); const float square_sz = igGetFrameHeight(); ImVec2 tl; igGetCursorScreenPos(&tl); ImVec2 br; br.x = tl.x + square_sz / 1.5f; br.y = tl.y + square_sz; bool hovered, held; ImRect rect; rect.Min = tl; rect.Max = br; igItemSize_Rect(rect, igGetCurrentContext()->Style.FramePadding.y); if (!igItemAdd(rect, id, NULL, ImGuiItemFlags_None)) return false; bool pressed = igButtonBehavior(rect, id, &hovered, &held, ImGuiButtonFlags_None); if (pressed) { *value = !(*value); igMarkItemEdited(id); } ImDrawList* draw_list = igGetWindowDrawList(); ImDrawList_AddRectFilled(draw_list, tl, br, igGetColorU32_Col((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg, 1), 0, ImDrawFlags_None); int pad = (int)(square_sz / 8.0f); tl.x += pad; tl.y += pad; br.x -= pad; br.y -= pad; if (*value) { ImDrawList_AddRectFilled(draw_list, tl, br, igGetColorU32_Col(ImGuiCol_CheckMark, 0.3f), 0, ImDrawFlags_None); tl.y += square_sz / 2.0f; ImDrawList_AddRectFilled(draw_list, tl, br, igGetColorU32_Col(ImGuiCol_CheckMark, 1), 0, ImDrawFlags_None); } else { br.y -= square_sz / 2.0f; ImDrawList_AddRectFilled(draw_list, tl, br, igGetColorU32_Col(ImGuiCol_CheckMark, 1), 0, ImDrawFlags_None); } return pressed; } void tab_settings_system() { igColumns(2, "SettingsSystem", true); igTextUnformatted("Name", NULL); igNextColumn(); igTextUnformatted("Setting", NULL); igNextColumn(); igSeparator(); bool staticChanged = false; { igPushID_Int((int)&MiceConfig.sysconf.region); AddSetting("Region", NULL); bool jpn = !!(MiceConfig.sysconf.region & 1); bool usa = !!(MiceConfig.sysconf.region & 2); bool exp = !!(MiceConfig.sysconf.region & 4); bool chn = !!(MiceConfig.sysconf.region & 8); igTextUnformatted("JPN", NULL); igSameLine(0.0, -1.0); if (igRadioButton_Bool("##JPN", MiceConfig.sysconf.region == 1)) { MiceConfig.sysconf.region = 1; staticChanged = true; save_current_config(); } igSameLine(0.0, -1.0); igSeparatorEx(ImGuiSeparatorFlags_Vertical); igSameLine(0.0, -1.0); igTextUnformatted("USA", NULL); igSameLine(0.0, -1.0); if (igRadioButton_Bool("##USA", MiceConfig.sysconf.region == 2)) { MiceConfig.sysconf.region = 2; staticChanged = true; save_current_config(); } igSameLine(0.0, -1.0); igSeparatorEx(ImGuiSeparatorFlags_Vertical); igSameLine(0.0, -1.0); igTextUnformatted("EXP", NULL); igSameLine(0.0, -1.0); if (igRadioButton_Bool("##EXP", MiceConfig.sysconf.region == 4)) { MiceConfig.sysconf.region = 4; staticChanged = true; save_current_config(); } igSameLine(0.0, -1.0); igSeparatorEx(ImGuiSeparatorFlags_Vertical); igSameLine(0.0, -1.0); igTextUnformatted("CHN", NULL); igSameLine(0.0, -1.0); if (igRadioButton_Bool("##", MiceConfig.sysconf.region == 8)) { MiceConfig.sysconf.region = 8; staticChanged = true; save_current_config(); } igNextColumn(); igPopID(); } staticChanged |= AddSettingBool("Rental", NULL, &MiceConfig.sysconf.rental); staticChanged |= AddSettingString("Serial", "Main board serial number", &MiceConfig.sysconf.serial); if (staticChanged) build_eeprom(); igSeparator(); AddSetting("Resolution", NULL); const char* current_item; current_item = RESOLUTION_NAMES[(MiceConfig.sysconf.dipsw >> 4) & 0b111]; if (igBeginCombo("##Resolution", current_item, ImGuiComboFlags_None)) { for (int i = 0; i < _countof(RESOLUTION_NAMES); i++) { bool is_selected = (current_item == RESOLUTION_NAMES[i]); if (igSelectable_Bool(RESOLUTION_NAMES[i], is_selected, ImGuiSelectableFlags_None, vec0)) { MiceConfig.sysconf.dipsw = ((MiceConfig.sysconf.dipsw & 0b1'000'1111) | (i << 4)) & 0xff; save_current_config(); } if (is_selected) igSetItemDefaultFocus(); } igEndCombo(); } igNextColumn(); AddSetting("Orientation", NULL); current_item = ORIENTATION_NAMES[(MiceConfig.sysconf.dipsw >> 3) & 0b1]; if (igBeginCombo("##Orientation", current_item, ImGuiComboFlags_None)) { for (int i = 0; i < _countof(ORIENTATION_NAMES); i++) { bool is_selected = (current_item == ORIENTATION_NAMES[i]); if (igSelectable_Bool(ORIENTATION_NAMES[i], is_selected, ImGuiSelectableFlags_None, vec0)) { MiceConfig.sysconf.dipsw = ((MiceConfig.sysconf.dipsw & 0b1111'0'111) | (i << 3)) & 0xff; save_current_config(); } if (is_selected) igSetItemDefaultFocus(); } igEndCombo(); } igNextColumn(); AddSetting("DIP Switches", "Linked with the above two settings"); for (int i = 0; i < 8; i++) { bool val = MiceConfig.sysconf.dipsw & (1 << i); igPushID_Int(i); if (i != 0) igSameLine(0.0, 2); if (igDipsw("", &val)) { MiceConfig.sysconf.dipsw = (MiceConfig.sysconf.dipsw & ~(1 << i)) | (val << i); save_current_config(); } igPopID(); } igNextColumn(); igEndColumns(); } void tab_settings_window() { igColumns(2, "SettingsWindow", true); igTextUnformatted("Name", NULL); igNextColumn(); igTextUnformatted("Setting", NULL); igNextColumn(); igSeparator(); bool changed = false; changed |= AddSettingBool("Windowed", "Forces games into windowed mode", &MiceConfig.window.windowed); changed |= AddSettingBool("Borderless", "Should windowed games run borderless", &MiceConfig.window.borderless); changed |= AddSettingInt("Adaptor", "Display adaptor to use", &MiceConfig.window.adaptor); changed |= AddSettingBool("Centre", "Centre the window. X and Y are used otherwise", &MiceConfig.window.centre); igBeginDisabled(MiceConfig.window.centre); changed |= AddSettingInt("X", "Window position X", &MiceConfig.window.x); changed |= AddSettingInt("Y", "Window position Y", &MiceConfig.window.y); igEndDisabled(); changed |= AddSettingBool("No sizing", "Don't change window resolution", &MiceConfig.window.nosize); igBeginDisabled(MiceConfig.window.nosize); changed |= AddSettingBool("Use DIPSW", "Use the DIP switches for resolution", &MiceConfig.window.dipsw); igBeginDisabled(MiceConfig.window.dipsw); changed |= AddSettingInt("W", "Window width (0 to unset)", &MiceConfig.window.w); changed |= AddSettingInt("H", "Window height (0 to unset)", &MiceConfig.window.h); igEndDisabled(); igEndDisabled(); if (changed) save_current_config(); igEndColumns(); } void tab_settings_network() { igColumns(2, "SettingsNetwork", true); igTextUnformatted("Name", NULL); igNextColumn(); igTextUnformatted("Setting", NULL); igNextColumn(); igSeparator(); bool networkChanged = false; networkChanged |= AddSettingIPv4("IP Address", NULL, &MiceConfig.network.ip_address); networkChanged |= AddSettingIPv4("Subnet Mask", NULL, &MiceConfig.network.subnet_mask); networkChanged |= AddSettingIPv4("Gateway", NULL, &MiceConfig.network.gateway); networkChanged |= AddSettingIPv4("Primary DNS", NULL, &MiceConfig.network.primary_dns); networkChanged |= AddSettingIPv4("Secondary DNS", NULL, &MiceConfig.network.secondary_dns); if (networkChanged) build_eeprom(); igSeparator(); igPushColumnsBackground(); igTextUnformatted("Emulated DNS records. Routers must be pingable", NULL); igPopColumnsBackground(); igSeparator(); bool changed = false; changed |= AddSettingIPv4("naominet.jp", NULL, &MiceConfig.network.naominet_jp); changed |= AddSettingIPv4("ib.naominet.jp", NULL, &MiceConfig.network.ib_naominet_jp); changed |= AddSettingIPv4("aime.naominet.jp", NULL, &MiceConfig.network.aime_naominet_jp); changed |= AddSettingIPv4("tenporouter.loc", NULL, &MiceConfig.network.tenporouter_loc); changed |= AddSettingIPv4("bbrouter.loc", NULL, &MiceConfig.network.bbrouter_loc); changed |= AddSettingIPv4("mobirouter.loc", NULL, &MiceConfig.network.mobirouter_loc); changed |= AddSettingIPv4("dslrouter.loc", NULL, &MiceConfig.network.dslrouter_loc); if (changed) save_current_config(); igSeparator(); { AddSetting("MAC Address", "The first half of the MAC address is locked to SEGA's prefix"); igTextUnformatted("D8:BB:C1:", NULL); unsigned int scan; char buffer[3] = { 0 }; igPushStyleVar_Vec2(ImGuiStyleVar_FramePadding, vec10); snprintf(buffer, _countof(buffer), "%02X", (MiceConfig.network.mac >> 16) & 0xff); igSameLine(0.0, 0); igPushItemWidth(16); if (igInputText("##mac0", buffer, _countof(buffer), ImGuiInputTextFlags_CharsHexadecimal, NULL, NULL)) { _snscanf_s(buffer, _countof(buffer), "%02x", &scan); MiceConfig.network.mac = (MiceConfig.network.mac & 0x00FFFF) | ((scan & 0xff) << 16); save_current_config(); } igSameLine(0.0, 0); igTextUnformatted(":", NULL); snprintf(buffer, _countof(buffer), "%02X", (MiceConfig.network.mac >> 8) & 0xff); igSameLine(0.0, 0); igPushItemWidth(16); if (igInputText("##mac1", buffer, _countof(buffer), ImGuiInputTextFlags_CharsHexadecimal, NULL, NULL)) { _snscanf_s(buffer, _countof(buffer), "%02x", &scan); MiceConfig.network.mac = (MiceConfig.network.mac & 0xFF00FF) | ((scan & 0xff) << 8); save_current_config(); } igSameLine(0.0, 0); igTextUnformatted(":", NULL); snprintf(buffer, _countof(buffer), "%02X", MiceConfig.network.mac & 0xff); igSameLine(0.0, 0); igPushItemWidth(16); if (igInputText("##mac2", buffer, _countof(buffer), ImGuiInputTextFlags_CharsHexadecimal, NULL, NULL)) { _snscanf_s(buffer, _countof(buffer), "%02x", &scan); MiceConfig.network.mac = (MiceConfig.network.mac & 0xFFFF00) | (scan & 0xff); save_current_config(); } igPopStyleVar(1); igNextColumn(); } igEndColumns(); } void tab_settings_adavanced() { igColumns(2, "SettingsNetwork", true); igTextUnformatted("Name", NULL); igNextColumn(); igTextUnformatted("Setting", NULL); igNextColumn(); igSeparator(); igPushColumnsBackground(); igTextColored(DANGER_COL, "Enable or disable drivers. Disabling any is not recommended."); igPopColumnsBackground(); igSeparator(); bool changed; changed |= AddSettingBool("\\\\.\\columba", NULL, &MiceConfig.drivers.columba); changed |= AddSettingBool("\\\\.\\mxsram", NULL, &MiceConfig.drivers.mxsram); changed |= AddSettingBool("\\\\.\\mxsuperio", NULL, &MiceConfig.drivers.mxsuperio); changed |= AddSettingBool("\\\\.\\mxjvs", NULL, &MiceConfig.drivers.mxjvs); changed |= AddSettingBool("\\\\.\\mxhwreset", NULL, &MiceConfig.drivers.mxhwreset); changed |= AddSettingBool("\\\\.\\mxsmbus", NULL, &MiceConfig.drivers.mxsmbus); changed |= AddSettingBool("\\\\.\\mxparallel", NULL, &MiceConfig.drivers.mxparallel); changed |= AddSettingBool("\\\\.\\platform", NULL, &MiceConfig.drivers.platform); igSeparator(); igPushColumnsBackground(); igTextColored(DANGER_COL, "Enable or disable hooks. Disabling any is not recommended."); igPopColumnsBackground(); igSeparator(); changed |= AddSettingBool("logging", "Hooks logging functions and the eventlog to capture game logs", &MiceConfig.hooks.logging); changed |= AddSettingBool("gui", "Required for overlays to work", &MiceConfig.hooks.gui); changed |= AddSettingBool("setupapi", "Required for SRAM", &MiceConfig.hooks.setupapi); changed |= AddSettingBool("commio", "Emulates COM devices", &MiceConfig.hooks.commio); changed |= AddSettingBool("io", "Hooks all file IO operations, including driver communication", &MiceConfig.hooks.io); changed |= AddSettingBool("processes", "Controls process spawning to re-hook children", &MiceConfig.hooks.processes); changed |= AddSettingBool("network", "Provides a virtual network environment for the game", &MiceConfig.hooks.network); changed |= AddSettingBool("time", "Some binaries try to change the system time; this handles that", &MiceConfig.hooks.time); changed |= AddSettingBool("registry", NULL, &MiceConfig.hooks.registry); changed |= AddSettingBool("drives", "Provides an emulation layer for the physical game SSD", &MiceConfig.hooks.drives); igEndColumns(); if (changed) save_current_config(); } void tab_main_settings() { if (igBeginTabBar("SettingsTabs", 0)) { if (igBeginTabItem("System", NULL, 0)) { tab_settings_system(); igEndTabItem(); } if (igBeginTabItem("Window", NULL, 0)) { tab_settings_window(); igEndTabItem(); } if (igBeginTabItem("Network", NULL, 0)) { tab_settings_network(); igEndTabItem(); } if (igBeginTabItem("Advanced", NULL, 0)) { tab_settings_adavanced(); igEndTabItem(); } igEndTabBar(); } } bool igKeyBindPopup(const char* name, int* boundKey) { if (igBeginPopupModal(name, NULL, ImGuiWindowFlags_AlwaysAutoResize)) { igText("Press any button"); if (igButton("Cancel", vec0)) { igCloseCurrentPopup(); *boundKey = -1; igEndPopup(); return true; } // Skip the mouse buttons for (int i = 8; i < 0xff; i++) { if (GetAsyncKeyState(i) < 0) { *boundKey = i; igCloseCurrentPopup(); igEndPopup(); return true; } } igEndPopup(); } return false; } void AddSettingButton(int board, int id) { char keyName[32]; static int currentlyBinding; char pinInfo[32]; snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[id].pinNum, JVS_BUTTON_NAMES[id].pinNum + 1); AddSetting(JVS_BUTTON_NAMES[id].name, pinInfo); if (jvsKeybindings[board].buttons[id * 2] == 0) { igTextColored(DISABLED_COL, "None"); } else { GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2], MAPVK_VK_TO_VSC) << 16, keyName, _countof(keyName)); igTextUnformatted(keyName, NULL); } igNextColumn(); char name[16]; char name2[16]; char clear[16]; char clear2[16]; char invertName[16]; char invertName2[16]; snprintf(name, _countof(name), "Bind##Bind%d", id); snprintf(name2, _countof(name2), "Bind##Bind2p%d", id); snprintf(clear, _countof(clear), "Clear##Bind%d", id); snprintf(clear2, _countof(clear2), "Clear##Bind2p%d", id); snprintf(invertName, _countof(invertName), "##Invert%d", id); snprintf(invertName2, _countof(invertName2), "##Invert2p%d", id); if (igButton(name, vec0)) { currentlyBinding = 1; igOpenPopup_Str(name, ImGuiPopupFlags_None); } if (jvsKeybindings[board].buttons[id * 2]) { igSameLine(0, -1); if (igButton(clear, vec0)) jvsKeybindings[board].buttons[id * 2] = 0; } igNextColumn(); igBeginDisabled(!jvsKeybindings[board].buttons[id * 2]); igCheckbox(invertName, &jvsKeybindings[board].invert[id * 2]); igEndDisabled(); igNextColumn(); if (jvsKeybindings[board].buttons[id * 2 + 1] == 0) { igTextColored(DISABLED_COL, "None"); } else { GetKeyNameTextA(MapVirtualKey(jvsKeybindings[board].buttons[id * 2 + 1], MAPVK_VK_TO_VSC) << 16, keyName, _countof(keyName)); igTextUnformatted(keyName, NULL); } igNextColumn(); if (igButton(name2, vec0)) { currentlyBinding = 2; igOpenPopup_Str(name, ImGuiPopupFlags_None); } if (jvsKeybindings[board].buttons[id * 2 + 1]) { igSameLine(0, -1); if (igButton(clear2, vec0)) { jvsKeybindings[board].buttons[id * 2 + 1] = 0; } } igNextColumn(); igBeginDisabled(!jvsKeybindings[board].buttons[id * 2 + 1]); igCheckbox(invertName2, &jvsKeybindings[board].invert[id * 2 + 1]); igEndDisabled(); igNextColumn(); int boundKey; if (igKeyBindPopup(name, &boundKey)) { if (boundKey != -1) { jvsKeybindings[board].buttons[id * 2 + (currentlyBinding - 1)] = boundKey; } currentlyBinding = 0; } } void tab_jvs_board(int num) { igPushID_Int(num); igColumns(7, "LogicalButtons", true); igSetColumnWidth(0, 100); igSetColumnWidth(1, 70); igSetColumnWidth(2, 100); igSetColumnWidth(3, 60); igSetColumnWidth(4, 70); igSetColumnWidth(5, 100); igSetColumnWidth(6, 60); igTextUnformatted("Button", NULL); igNextColumn(); igTextUnformatted("Player 1", NULL); igNextColumn(); igNextColumn(); igTextUnformatted("Invert", NULL); igNextColumn(); igTextUnformatted("Player 2", NULL); igNextColumn(); igNextColumn(); igTextUnformatted("Invert", NULL); igNextColumn(); igSeparator(); for (int i = 0; i < _countof(JVS_BUTTON_NAMES); i++) AddSettingButton(num, i); igSeparator(); AddSetting("Test", NULL); char keyName[16]; if (jvsKeybindings[num].test == 0) { igTextColored(DISABLED_COL, "None"); } else { GetKeyNameTextA(MapVirtualKey(jvsKeybindings[num].test, MAPVK_VK_TO_VSC) << 16, keyName, _countof(keyName)); igTextUnformatted(keyName, NULL); } igNextColumn(); if (igButton("Bind##JvsTest", vec0)) igOpenPopup_Str("BindJvsTest", ImGuiPopupFlags_None); if (jvsKeybindings[num].test) { igSameLine(0, -1); if (igButton("Clear##ClearJvsTest", vec0)) jvsKeybindings[num].test = 0; } int boundKey; if (igKeyBindPopup("BindJvsTest", &boundKey)) if (boundKey != -1) jvsKeybindings[num].test = boundKey; igEndColumns(); igPopID(); } void tab_system_buttons() { char keyName[32]; int boundKey; igColumns(3, "SystemButtons", true); igTextUnformatted("Button", NULL); igNextColumn(); igTextUnformatted("Key", NULL); igNextColumn(); igNextColumn(); igSeparator(); igTextUnformatted("System Test", NULL); igNextColumn(); if (keySystemTest == 0) { igTextColored(DISABLED_COL, "None"); } else { GetKeyNameTextA(MapVirtualKey(keySystemTest, MAPVK_VK_TO_VSC) << 16, keyName, _countof(keyName)); igTextUnformatted(keyName, NULL); } igNextColumn(); if (igButton("Bind##BindTest", vec0)) igOpenPopup_Str("BindSysTest", ImGuiPopupFlags_None); if (keySystemTest) { igSameLine(0, -1); if (igButton("Clear##ClearTest", vec0)) keySystemTest = 0; } igNextColumn(); if (igKeyBindPopup("BindSysTest", &boundKey)) if (boundKey != -1) keySystemTest = boundKey; igTextUnformatted("System Service", NULL); igNextColumn(); if (keySystemService == 0) { igTextColored(DISABLED_COL, "None"); } else { GetKeyNameTextA(MapVirtualKey(keySystemService, MAPVK_VK_TO_VSC) << 16, keyName, _countof(keyName)); igTextUnformatted(keyName, NULL); } igNextColumn(); if (igButton("Bind##BindService", vec0)) igOpenPopup_Str("BindSysService", ImGuiPopupFlags_None); if (keySystemService) { igSameLine(0, -1); if (igButton("Clear##ClearService", vec0)) keySystemService = 0; } igNextColumn(); if (igKeyBindPopup("BindSysService", &boundKey)) if (boundKey != -1) keySystemService = boundKey; } void tab_main_keybinds() { igInputInt("Number of JVS boards", &numJvsBoards, 1, 1, ImGuiInputTextFlags_None); if (numJvsBoards < 0) numJvsBoards = 0; if (numJvsBoards > JVS_IO_MAX) numJvsBoards = JVS_IO_MAX; if (igBeginTabBar("JVSBoards", 0)) { for (int i = 0; i < numJvsBoards; i++) { char name[32]; snprintf(name, _countof(name), "Board %d", i + 1); if (igBeginTabItem(name, NULL, 0)) { tab_jvs_board(i); igEndTabItem(); } } if (igBeginTabItem("System", NULL, 0)) { tab_system_buttons(); igEndTabItem(); } igEndTabBar(); } } void hud_control(ImGuiKey open_key) { static bool isOpen = true; static bool oldCursor; if (igIsKeyPressed_Bool(open_key, false)) { isOpen = !isOpen; if (isOpen) { CURSORINFO ci; GetCursorInfo(&ci); oldCursor = !!(ci.flags & CURSOR_SHOWING); ShowCursor(TRUE); } else { ShowCursor(oldCursor); } } if (!isOpen) return; igBegin("Micetools", NULL, 0); static bool haveFirstFrame = false; if (!haveFirstFrame) { ImVec2 size = { 600, 450 }; igSetWindowSize_Vec2(size, 0); haveFirstFrame = true; } EnterCriticalSection(&logger_lock); if (igBeginTabBar("MainTabs", 0)) { if (igBeginTabItem("Keybinds", NULL, 0)) { igBeginChild_Str("Keybinds", vec0, FALSE, 0); tab_main_keybinds(); igEndChild(); igEndTabItem(); } if (igBeginTabItem("Settings", NULL, 0)) { igBeginChild_Str("Settings", vec0, FALSE, 0); tab_main_settings(); igEndChild(); igEndTabItem(); } igEndTabBar(); } LeaveCriticalSection(&logger_lock); igEnd(); } void __stdcall hud_gui(unsigned int hookType, IDirect3DDevice9* dev) { static bool showMenu = false; ShowCursor(1); static bool initialized = false; if (!initialized) { InitImGui(hookType, dev); initialized = true; } if (hookType == UI_HOOK_DX9) { ImGui_ImplDX9_NewFrame(); ImGui_ImplWin32_NewFrame(); igNewFrame(); } else if (hookType == UI_HOOK_GLUT) { ImGui_ImplGLUT_ReshapeFunc(glutGet(GLUT_WINDOW_WIDTH), glutGet(GLUT_WINDOW_HEIGHT)); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGLUT_NewFrame(); } static bool showFps = false; if (igIsKeyPressed_Bool(ImGuiKey_F12, false)) showFps = !showFps; if (showFps) hud_fps(); hud_eeprom(ImGuiKey_F11); hud_sram(ImGuiKey_F10); hud_control(ImGuiKey_F4); if (hookType == UI_HOOK_DX9) { igEndFrame(); igRender(); ImGui_ImplDX9_RenderDrawData(igGetDrawData()); } else if (hookType == UI_HOOK_GLUT) { igRender(); ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); } } void setup_hud_gui() { register_gui_hook(&hud_gui); }