#include "loveplus.h" #include #include "avs/game.h" #include "hooks/graphics/graphics.h" #include "hooks/devicehook.h" #include "touch/touch.h" #include "util/detour.h" #include "util/libutils.h" #include "util/logging.h" #include "util/utils.h" namespace games::loveplus { // touch stuff static bool TOUCH_ENABLE = false; static bool TOUCH_ATTACHED = false; void touch_update() { // check if touch enabled if (!TOUCH_ENABLE) { return; } // attach touch module if (!TOUCH_ATTACHED) { // Find the game window. // We check the foreground window first, then fall back to searching for the window title // All game versions seem to have their model first in the window title HWND wnd = GetForegroundWindow(); if (!string_begins_with(GetActiveWindowTitle(), "LovePlus")) { wnd = FindWindowBeginsWith(avs::game::MODEL); } // attach touch hook if (wnd) { log_info("loveplus", "using window handle for touch: {}", fmt::ptr(wnd)); touch_create_wnd(wnd); } else { log_info("loveplus", "falling back to the DirectX window handle for touch"); touch_attach_dx_hook(); } // show cursor if (GRAPHICS_SHOW_CURSOR) { ShowCursor(1); } // set attached TOUCH_ATTACHED = true; } } static int __cdecl lib_touchpanel_init() { touch_update(); return 0; } static int __cdecl lib_touchpanel_calibrate(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { return 0; } // FIXME: test this calling convention change! static int __cdecl lib_touchpanel_diagnostics(void *a1) { return 0; } static int __cdecl lib_touchpanel_get_touch(DWORD *a1) { touch_update(); // get touch points std::vector touch_points; touch_get_points(touch_points); // check first touch point if (!touch_points.empty()) { auto &tp = touch_points[0]; a1[0] = tp.y; a1[1] = tp.x; a1[2] = 0; a1[3] = 1; a1[4] = 0; } else { a1[0] = 0; a1[1] = 0; a1[2] = 0; a1[3] = 0; a1[4] = 0; } return 0; } static int __cdecl lib_touchpanel_get_touch_direct(DWORD *a1) { return lib_touchpanel_get_touch(a1); } static int __cdecl lib_touchpanel_update() { return 1; } static bool __cdecl lib_touchpanel_term() { return 0; } static bool __cdecl lib_touchpanel_instance_term() { return 0; } static BOOL __cdecl SetEqualizer(char *a1) { return FALSE; } static LPSTR __stdcall GetCommandLineA_hook() { static std::string lp_args = "-win -noCamera -noWatchDog -noIOError -noIrda -notarget"; return lp_args.data(); } LovePlusGame::LovePlusGame() : Game("LovePlus") { } void LovePlusGame::attach() { Game::attach(); // init stuff devicehook_init(); // enable touch TOUCH_ENABLE = true; // touchpanel emulation HMODULE lib_touchpanel = libutils::try_library("lib_touchpanel.dll"); detour::inline_hook((void *) lib_touchpanel_init, libutils::try_proc( lib_touchpanel, "lib_touchpanel_init")); detour::inline_hook((void *) lib_touchpanel_calibrate, libutils::try_proc( lib_touchpanel, "lib_touchpanel_calibrate")); detour::inline_hook((void *) lib_touchpanel_diagnostics, libutils::try_proc( lib_touchpanel, "lib_touchpanel_diagnostics")); detour::inline_hook((void *) lib_touchpanel_get_touch, libutils::try_proc( lib_touchpanel, "lib_touchpanel_get_touch_direct")); detour::inline_hook((void *) lib_touchpanel_get_touch_direct, libutils::try_proc( lib_touchpanel, "lib_touchpanel_get_touch")); detour::inline_hook((void *) lib_touchpanel_update, libutils::try_proc( lib_touchpanel, "lib_touchpanel_update")); detour::inline_hook((void *) lib_touchpanel_term, libutils::try_proc( lib_touchpanel, "lib_touchpanel_term")); detour::inline_hook((void *) lib_touchpanel_instance_term, libutils::try_proc( lib_touchpanel, "lib_touchpanel_instance_term")); // equalizer crash fix HMODULE seteq = libutils::try_library("ad_hd_seteq_dll.dll"); detour::inline_hook((void *) SetEqualizer, libutils::try_proc(seteq, "SetEqualizer")); // get command line hook HMODULE lpac = libutils::try_library("lpac.dll"); detour::iat("GetCommandLineA", GetCommandLineA_hook, lpac); } void LovePlusGame::detach() { Game::detach(); // disable touch TOUCH_ENABLE = false; } }