micetools/src/micetools/dll/gui/gui.c

1073 lines
36 KiB
C

#include "../hooks/gui.h"
#ifndef CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
#endif
#include "../devices/smb_at24c64an.h"
#include "../drivers/jvs_boards/jvs.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 };
typedef struct JVS_BUTTON_NAME {
const char* name;
int index;
int pinNum;
} JVS_BUTTON_NAME, *PJVS_BUTTON_NAME;
JVS_BUTTON_NAME 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 },
};
JVS_BUTTON_NAME JVS_BUTTON_NAMES_MAIMAI[14] = {
{ "Coin" }, { "Button 1" }, { "Button 2" }, { "Button 3" }, { "Button 4" },
{ "Button 5" }, { "Button 6" }, { "Button 7" }, { "Button 8" },
};
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;
// Open flags
static bool showFps = false;
static bool showEeprom = false;
static bool showSram = false;
static bool showControl = false;
static bool showCardP1 = false;
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);
}
}
extern BYTE cardLED_RGB_P1[3];
extern BYTE cardLED_RGB_P2[3];
void hud_card(ImGuiKey open_key) {
if (igIsKeyPressed_Bool(open_key, false)) showCardP1 = !showCardP1;
if (!showCardP1) return;
igBegin("Card Reader", NULL, 0);
ImVec4 col;
col.w = 1.0f;
col.x = cardLED_RGB_P1[0] / 511.0f;
col.y = cardLED_RGB_P1[1] / 511.0f;
col.z = cardLED_RGB_P1[2] / 511.0f;
igPushStyleColor_Vec4(ImGuiCol_Button, col);
igButton("Insert card P1", vec0);
igPopStyleColor(1);
col.x = cardLED_RGB_P2[0] / 511.0f;
col.y = cardLED_RGB_P2[1] / 511.0f;
col.z = cardLED_RGB_P2[2] / 511.0f;
igPushStyleColor_Vec4(ImGuiCol_Button, col);
igButton("Insert card P2", vec0);
igPopStyleColor(1);
igEnd();
}
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);
showEeprom = false;
has_init = true;
}
if (igIsKeyPressed_Bool(open_key, false)) showEeprom = !showEeprom;
// TODO: Less hacky :)
extern LPBYTE EEPROM_DATA;
editor.Open = showEeprom;
if (showEeprom) MemoryEditor_DrawWindow(&editor, "EEPROM Editor", EEPROM_DATA, 0x2000, 0x000);
}
void hud_sram(ImGuiKey open_key) {
static MemoryEditor editor;
static bool has_init = false;
if (!has_init) {
MemoryEditor_Init(&editor);
showSram = false;
has_init = true;
}
if (igIsKeyPressed_Bool(open_key, false)) showSram = !showSram;
// TODO: Less hacky :)
extern LPBYTE SRAM_DATA;
editor.Open = showSram;
if (showSram) MemoryEditor_DrawWindow(&editor, "SRAM Editor", SRAM_DATA, 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(false);
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(false);
}
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(false);
} 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;
}
#define SERIAL_HELP \
"This value was automatically generated for you and uniquely identifies your computer"
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(false);
}
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(false);
}
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(false);
}
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(false);
}
igNextColumn();
igPopID();
}
staticChanged |= AddSettingBool("Rental", NULL, &MiceConfig.sysconf.rental);
// The 'M' prefix isn't technically foolproof, but it's good enough for a simple help message
staticChanged |= AddSettingString(
"PCB serial number",
(MiceConfig.sysconf.serial && MiceConfig.sysconf.serial[0] == 'M' ? SERIAL_HELP : NULL),
&MiceConfig.sysconf.serial);
if (staticChanged) {
build_eeprom();
save_current_config(false);
}
if (AddSettingString(
"Keychip serial number",
(MiceConfig.sysconf.keyid && MiceConfig.sysconf.keyid[0] == 'M' ? SERIAL_HELP : NULL),
&MiceConfig.sysconf.keyid)) {
save_current_config(false);
}
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(false);
}
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(false);
}
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(false);
}
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(false);
igEndColumns();
}
void tab_settings_network() {
igColumns(2, "SettingsNetwork", true);
igTextUnformatted("Name", NULL);
igNextColumn();
igTextUnformatted("Setting", NULL);
igNextColumn();
igSeparator();
bool networkChanged = false;
networkChanged |=
AddSettingIPv4("Real Upstream DNS",
"When not set to 0.0.0.0, used in place of any system configured servers.",
&MiceConfig.network.upstream_dns_server);
igSeparator();
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(false);
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(false);
}
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(false);
}
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(false);
}
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(false);
}
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;
}
bool igKeyBindPopup_New(const char* name, PMICE_BUTTON_BINDING binding) {
if (igBeginPopupModal(name, NULL, ImGuiWindowFlags_AlwaysAutoResize)) {
igText("Press any button");
if (igButton("Cancel", vec0)) {
igCloseCurrentPopup();
igEndPopup();
return true;
}
if (MiceInputGetNewBinding(binding)) {
igCloseCurrentPopup();
igEndPopup();
return true;
}
igEndPopup();
}
return false;
}
void AddSettingButton(PMICE_JVS board, int player, int button) {
char keyName[32];
static int currentlyBinding;
int index = player * board->m_ButtonsPerPlayer + button + board->m_Coins + 1;
PMICE_BUTTON_BINDING bind = &(board->m_Bindings[index]);
switch (bind->m_Type) {
case MICE_BB_TYPE_UNBOUND:
igTextColored(DISABLED_COL, "None");
break;
case MICE_BB_TYPE_DI_JOY:
switch (bind->m_DIJoy.m_ButtonMajor) {
case MICE_BUTTON_MAJOR_AXIS:
igTextColored(DISABLED_COL, "Axis");
break;
case MICE_BUTTON_MAJOR_DPAD:
igText("D-Pad %s", bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_UP ? "Up"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_DOWN ? "Down"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_LEFT ? "Left"
: bind->m_DIJoy.m_ButtonMinor == MICE_DPAD_RIGHT ? "Right"
: "??");
break;
case MICE_BUTTON_MAJOR_BUTTON:
igText("Button %d", bind->m_DIJoy.m_ButtonMinor + 1);
break;
}
break;
case MICE_BB_TYPE_GET_ASYNC_KEY:
GetKeyNameTextA(MapVirtualKey(bind->m_AsyncKey.m_Key, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName));
igTextUnformatted(keyName, NULL);
break;
}
igNextColumn();
char name[16];
char clear[16];
char invertName[16];
snprintf(name, _countof(name), "Bind##Bind%d", index);
snprintf(clear, _countof(clear), "Clear##Bind%d", index);
snprintf(invertName, _countof(invertName), "##Invert%d", index);
if (igButton(name, vec0)) {
MiceInputGetNewBinding(NULL);
igOpenPopup_Str(name, ImGuiPopupFlags_None);
}
if (bind->m_Type != MICE_BB_TYPE_UNBOUND) {
igSameLine(0, -1);
if (igButton(clear, vec0)) {
bind->m_Type = MICE_BB_TYPE_UNBOUND;
save_current_config(false);
}
}
igNextColumn();
igBeginDisabled(bind->m_Type == MICE_BB_TYPE_UNBOUND);
if (igCheckbox(invertName, (bool*)&bind->m_Invert)) save_current_config(false);
igEndDisabled();
igNextColumn();
if (igKeyBindPopup_New(name, bind)) save_current_config(false);
}
void AddButtonsForBoard(PMICE_JVS board) {
for (DWORD button = 0; button < board->m_ButtonsPerPlayer; button++) {
char pinInfo[32];
snprintf(pinInfo, _countof(pinInfo), "CN3, Pins %d/%d", JVS_BUTTON_NAMES[button].pinNum,
JVS_BUTTON_NAMES[button].pinNum + 1);
AddSetting(JVS_BUTTON_NAMES[button].name, pinInfo);
for (DWORD player = 0; player < board->m_Players; player++) {
AddSettingButton(board, player, button);
}
}
}
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();
AddButtonsForBoard(&_MiceJvsBoards[0]);
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;
save_current_config(false);
}
}
int boundKey;
if (igKeyBindPopup("BindJvsTest", &boundKey))
if (boundKey != -1) {
jvsKeybindings[num].test = boundKey;
save_current_config(false);
}
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 (MiceConfig.keys.test == 0) {
igTextColored(DISABLED_COL, "None");
} else {
GetKeyNameTextA(MapVirtualKey(MiceConfig.keys.test, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName));
igTextUnformatted(keyName, NULL);
}
igNextColumn();
if (igButton("Bind##BindTest", vec0)) igOpenPopup_Str("BindSysTest", ImGuiPopupFlags_None);
if (MiceConfig.keys.test) {
igSameLine(0, -1);
if (igButton("Clear##ClearTest", vec0)) {
MiceConfig.keys.test = 0;
save_current_config(false);
}
}
igNextColumn();
if (igKeyBindPopup("BindSysTest", &boundKey))
if (boundKey != -1) {
MiceConfig.keys.test = boundKey;
save_current_config(false);
}
igTextUnformatted("System Service", NULL);
igNextColumn();
if (MiceConfig.keys.service == 0) {
igTextColored(DISABLED_COL, "None");
} else {
GetKeyNameTextA(MapVirtualKey(MiceConfig.keys.service, MAPVK_VK_TO_VSC) << 16, keyName,
_countof(keyName));
igTextUnformatted(keyName, NULL);
}
igNextColumn();
if (igButton("Bind##BindService", vec0))
igOpenPopup_Str("BindSysService", ImGuiPopupFlags_None);
if (MiceConfig.keys.service) {
igSameLine(0, -1);
if (igButton("Clear##ClearService", vec0)) {
MiceConfig.keys.service = 0;
save_current_config(false);
}
}
igNextColumn();
if (igKeyBindPopup("BindSysService", &boundKey))
if (boundKey != -1) {
MiceConfig.keys.service = boundKey;
save_current_config(false);
}
}
void tab_main_keybinds() {
if (igInputInt("Number of JVS boards", &MiceConfig.keys.board_count, 1, 1,
ImGuiInputTextFlags_None)) {
if (MiceConfig.keys.board_count < 0) MiceConfig.keys.board_count = 0;
if (MiceConfig.keys.board_count > JVS_IO_MAX) MiceConfig.keys.board_count = JVS_IO_MAX;
save_current_config(false);
}
if (igBeginTabBar("JVSBoards", 0)) {
for (int i = 0; i < MiceConfig.keys.board_count; 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 tab_main_aime_cards() {
igText(
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can "
"be "
"specified as either an NFC ID or an access code.\nIf a card file is present, it will be "
"used preferentially.");
igColumns(2, "AimeWindow", true);
igSeparator();
bool changed = false;
changed |= AddSettingString("Player 1 Card ID", NULL, &MiceConfig.aime.player1_card);
changed |= AddSettingString("Player 2 Card ID", NULL, &MiceConfig.aime.player2_card);
changed |= AddSettingString("Player 1 Card File", NULL, &MiceConfig.aime.player1_cardfile);
changed |= AddSettingString("Player 2 Card File", NULL, &MiceConfig.aime.player2_cardfile);
igEndColumns();
if (changed) save_current_config(false);
}
void hud_control(ImGuiKey open_key) {
if (igIsKeyPressed_Bool(open_key, false)) showControl = !showControl;
if (!showControl) 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("AiMe Cards", NULL, 0)) {
igBeginChild_Str("AiMe Cards", vec0, FALSE, 0);
tab_main_aime_cards();
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 lastAnyOpen = false;
bool anyOpen = showControl || showEeprom || showSram || showCardP1;
if (anyOpen != lastAnyOpen) {
changeCursorState = anyOpen ? 1 : 0;
lastAnyOpen = anyOpen;
}
static bool initialized = false;
if (!initialized) {
InitImGui(hookType, dev);
initialized = true;
changeCursorState = 0; // Hide cursor by default
}
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();
}
if (igIsKeyPressed_Bool(ImGuiKey_F12, false)) showFps = !showFps;
if (showFps) hud_fps();
hud_eeprom(ImGuiKey_F11);
hud_sram(ImGuiKey_F10);
hud_control(ImGuiKey_F4);
hud_card(ImGuiKey_F5);
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); }