Update to spice2x-25-04-25 (pre-apply)
> broken commit
This commit is contained in:
+198
-68
@@ -11,16 +11,19 @@
|
||||
#include "cfg/icon.h"
|
||||
#include "cfg/screen_resize.h"
|
||||
#include "games/ddr/ddr.h"
|
||||
#include "games/iidx/iidx.h"
|
||||
#include "hooks/graphics/backends/d3d9/d3d9_backend.h"
|
||||
#include "launcher/shutdown.h"
|
||||
#include "overlay/overlay.h"
|
||||
#include "touch/touch.h"
|
||||
#include "touch/touch_indicators.h"
|
||||
#include "util/detour.h"
|
||||
#include "util/logging.h"
|
||||
#include "util/fileutils.h"
|
||||
#include "util/utils.h"
|
||||
#include "misc/wintouchemu.h"
|
||||
#include "util/time.h"
|
||||
#include "rawinput/rawinput.h"
|
||||
|
||||
struct CaptureData {
|
||||
std::shared_ptr<uint8_t[]> data;
|
||||
@@ -28,11 +31,15 @@ struct CaptureData {
|
||||
uint64_t timestamp;
|
||||
};
|
||||
|
||||
HWND TDJ_SUBSCREEN_WINDOW = nullptr;
|
||||
HWND SDVX_SUBSCREEN_WINDOW = nullptr;
|
||||
|
||||
// icon
|
||||
static HICON WINDOW_ICON = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(MAINICON));
|
||||
|
||||
// state
|
||||
static WNDPROC WNDPROC_ORIG = nullptr;
|
||||
static WNDPROC WSUB_WNDPROC_ORIG = nullptr;
|
||||
static std::vector<WNDPROC> WNDPROC_CUSTOM {};
|
||||
static bool GRAPHICS_SCREENSHOT_TRIGGER = false;
|
||||
static std::set<int> GRAPHICS_SCREENS { 0 };
|
||||
@@ -53,9 +60,17 @@ graphics_orientation GRAPHICS_ADJUST_ORIENTATION = ORIENTATION_NORMAL;
|
||||
bool GRAPHICS_WINDOWED = false;
|
||||
std::vector<HWND> GRAPHICS_WINDOWS;
|
||||
UINT GRAPHICS_FORCE_REFRESH = 0;
|
||||
std::optional<int> GRAPHICS_FORCE_VSYNC_BUFFER;
|
||||
bool GRAPHICS_FORCE_SINGLE_ADAPTER = false;
|
||||
bool GRAPHICS_9_ON_12 = false;
|
||||
bool GRAPHICS_PREVENT_SECONDARY_WINDOW = false;
|
||||
graphics_dx9on12_state GRAPHICS_9_ON_12_STATE = DX9ON12_AUTO;
|
||||
bool GRAPHICS_9_ON_12_REQUESTED_BY_GAME = false;
|
||||
bool SUBSCREEN_FORCE_REDRAW = false;
|
||||
bool D3D9_DEVICE_HOOK_DISABLE = false;
|
||||
std::optional<std::pair<uint32_t, uint32_t>> GRAPHICS_FS_CUSTOM_RESOLUTION;
|
||||
bool GRAPHICS_FS_ORIENTATION_SWAP = false;
|
||||
uint32_t GRAPHICS_FS_ORIGINAL_WIDTH = 0;
|
||||
uint32_t GRAPHICS_FS_ORIGINAL_HEIGHT = 0;
|
||||
|
||||
// settings
|
||||
std::string GRAPHICS_DEVICEID = "PCI\\VEN_1002&DEV_7146";
|
||||
@@ -154,26 +169,44 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
|
||||
// capture mouse
|
||||
if (GRAPHICS_CAPTURE_CURSOR) {
|
||||
bool free_cursor = false;
|
||||
bool capture_cursor = false;
|
||||
bool early_return = false;
|
||||
switch (uMsg) {
|
||||
case WM_SETFOCUS: {
|
||||
|
||||
// capture mouse
|
||||
RECT WINDOW_RECT;
|
||||
GetWindowRect(hWnd, &WINDOW_RECT);
|
||||
ClipCursor(&WINDOW_RECT);
|
||||
|
||||
return true;
|
||||
}
|
||||
case WM_KILLFOCUS: {
|
||||
|
||||
// free mouse
|
||||
ClipCursor(0);
|
||||
|
||||
return true;
|
||||
}
|
||||
case WM_SETFOCUS:
|
||||
capture_cursor = true;
|
||||
early_return = true;
|
||||
break;
|
||||
case WM_KILLFOCUS:
|
||||
free_cursor = true;
|
||||
early_return = true;
|
||||
break;
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
// known issue: dragging with the title bar results in WM_WINDOWPOSCHANGED
|
||||
// getting called, which calls ClipCursor successfully, but doesn't actually
|
||||
// confine the cursor for some reason; seems like odd Windows behavior
|
||||
// (can be fixed if focus is shifted to another window and then back to the game
|
||||
// window)
|
||||
if (hWnd == GetActiveWindow()) {
|
||||
capture_cursor = true;
|
||||
} else {
|
||||
free_cursor = true;
|
||||
}
|
||||
// do not return early; may result in WM_SIZE / WM_MOVE no longer being called
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (free_cursor) {
|
||||
ClipCursor(nullptr);
|
||||
} else if (capture_cursor) {
|
||||
RECT WINDOW_RECT;
|
||||
GetWindowRect(hWnd, &WINDOW_RECT);
|
||||
ClipCursor(&WINDOW_RECT);
|
||||
}
|
||||
if (early_return) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// drop keydown messages
|
||||
@@ -187,47 +220,44 @@ static LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM l
|
||||
break;
|
||||
}
|
||||
|
||||
// update the size of an emulated touch window is the window changes size or moves
|
||||
if (SPICETOUCH_TOUCH_HWND) {
|
||||
switch (uMsg) {
|
||||
case WM_MOVE:
|
||||
case WM_SIZE: {
|
||||
// get window rect
|
||||
RECT windowRect {};
|
||||
GetWindowRect(hWnd, &windowRect);
|
||||
|
||||
// adjust to client area
|
||||
POINT p {};
|
||||
ClientToScreen(hWnd, &p);
|
||||
windowRect.top = p.y;
|
||||
|
||||
int new_x = windowRect.left;
|
||||
int new_y = windowRect.top;
|
||||
int new_width = windowRect.right - new_x;
|
||||
int new_height = windowRect.bottom - new_y;
|
||||
|
||||
log_misc("graphics", "detected window change ({}x{} @ {}, {} -> {}x{} @ {}, {}), updating touch window to match",
|
||||
SPICETOUCH_TOUCH_WIDTH, SPICETOUCH_TOUCH_HEIGHT, SPICETOUCH_TOUCH_X, SPICETOUCH_TOUCH_Y,
|
||||
new_width, new_height, new_x, new_y);
|
||||
|
||||
SPICETOUCH_TOUCH_X = new_x;
|
||||
SPICETOUCH_TOUCH_Y = new_y;
|
||||
SPICETOUCH_TOUCH_WIDTH = new_width;
|
||||
SPICETOUCH_TOUCH_HEIGHT = new_height;
|
||||
SetWindowPos(SPICETOUCH_TOUCH_HWND, HWND_TOP,
|
||||
new_x, new_y,
|
||||
new_width, new_height,
|
||||
SWP_NOZORDER | SWP_NOREDRAW | SWP_NOREPOSITION | SWP_NOACTIVATE);
|
||||
switch (uMsg) {
|
||||
case WM_MOVE:
|
||||
case WM_SIZE: {
|
||||
// Update SPICETOUCH space when the main window changes size or moves.
|
||||
// The update happens regardless of whether the "fake" spicetouch window is present or not.
|
||||
// This allows touches received on subscreen window to be translated correctly.
|
||||
update_spicetouch_window_dimensions(hWnd);
|
||||
// log_misc(
|
||||
// "graphics", "detected window change ({}x{} @ {}, {}), updating touch coord-space to match",
|
||||
// SPICETOUCH_TOUCH_WIDTH, SPICETOUCH_TOUCH_HEIGHT, SPICETOUCH_TOUCH_X, SPICETOUCH_TOUCH_Y);
|
||||
|
||||
// Update SPICETOUCH window if present
|
||||
if (SPICETOUCH_TOUCH_HWND) {
|
||||
SetWindowPos(
|
||||
SPICETOUCH_TOUCH_HWND, HWND_TOP,
|
||||
SPICETOUCH_TOUCH_X, SPICETOUCH_TOUCH_Y,
|
||||
SPICETOUCH_TOUCH_WIDTH, SPICETOUCH_TOUCH_HEIGHT,
|
||||
SWP_NOZORDER | SWP_NOREDRAW | SWP_NOREPOSITION | SWP_NOACTIVATE);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// call default
|
||||
return CallWindowProcA(WNDPROC_ORIG, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
// window procedure for subscreen
|
||||
// this might be replaced by spicetouch hook later
|
||||
static LRESULT CALLBACK WsubWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
if (uMsg == WM_CLOSE) {
|
||||
log_misc("graphics", "ignore WM_CLOSE for subscreen window");
|
||||
return false;
|
||||
}
|
||||
return CallWindowProcA(WSUB_WNDPROC_ORIG, hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LONG WINAPI ChangeDisplaySettingsA_hook(DEVMODEA *lpDevMode, DWORD dwflags) {
|
||||
log_misc("graphics", "ChangeDisplaySettingsA hook hit");
|
||||
|
||||
@@ -271,10 +301,12 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
||||
HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
|
||||
LPVOID lpParam)
|
||||
{
|
||||
const std::string window_name(lpWindowName != nullptr ? lpWindowName : "(null)");
|
||||
|
||||
log_misc("graphics", "CreateWindowExA hook hit (0x{:08x}, {}, {}, 0x{:08x}, {}, {}, {}, {}, {}, {}, {}, {})",
|
||||
dwExStyle,
|
||||
fmt::ptr(lpClassName),
|
||||
lpWindowName != nullptr ? lpWindowName : "(null)",
|
||||
window_name,
|
||||
dwStyle,
|
||||
x,
|
||||
y,
|
||||
@@ -285,43 +317,86 @@ static HWND WINAPI CreateWindowExA_hook(DWORD dwExStyle, LPCSTR lpClassName, LPC
|
||||
fmt::ptr(hInstance),
|
||||
fmt::ptr(lpParam));
|
||||
|
||||
// set display orientation
|
||||
// only do this when the target window is portrait
|
||||
// set display orientation and/or refresh rate
|
||||
// only set orientation when the target window is portrait
|
||||
// (avoid doing this for SDVX subscreen which is in landscape, for example)
|
||||
if ((nHeight > nWidth) &&
|
||||
const auto adjust_orientation =
|
||||
(GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ||
|
||||
GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CCW)) {
|
||||
DWORD orientation = (GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW) ? DMDO_90 : DMDO_270;
|
||||
GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CCW);
|
||||
|
||||
if ((nHeight > nWidth && adjust_orientation) || GRAPHICS_FORCE_REFRESH > 0) {
|
||||
DEVMODE mode {};
|
||||
|
||||
// get display settings
|
||||
if (EnumDisplaySettings(0, ENUM_CURRENT_SETTINGS, &mode)) {
|
||||
log_misc("graphics", "auto-rotate: rotating display to DMDO_xx mode {}", orientation);
|
||||
mode.dmPelsWidth = nWidth;
|
||||
mode.dmPelsHeight = nHeight;
|
||||
mode.dmDisplayOrientation = orientation;
|
||||
if (EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &mode)) {
|
||||
if (adjust_orientation) {
|
||||
DWORD orientation = GRAPHICS_ADJUST_ORIENTATION == ORIENTATION_CW ? DMDO_90 : DMDO_270;
|
||||
log_misc(
|
||||
"graphics",
|
||||
"auto-rotate: call ChangeDisplaySettings and rotate display to DMDO_xx mode {}",
|
||||
orientation);
|
||||
mode.dmPelsWidth = nWidth;
|
||||
mode.dmPelsHeight = nHeight;
|
||||
mode.dmDisplayOrientation = orientation;
|
||||
}
|
||||
|
||||
if (GRAPHICS_FORCE_REFRESH > 0) {
|
||||
log_info(
|
||||
"graphics",
|
||||
"auto-rotate: force refresh rate: {} => {} Hz",
|
||||
"call ChangeDisplaySettings to force refresh rate: {} => {} Hz (-graphics-force-refresh)",
|
||||
mode.dmDisplayFrequency,
|
||||
GRAPHICS_FORCE_REFRESH);
|
||||
|
||||
mode.dmDisplayFrequency = GRAPHICS_FORCE_REFRESH;
|
||||
}
|
||||
auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
|
||||
|
||||
const auto disp_res = ChangeDisplaySettings(&mode, CDS_FULLSCREEN);
|
||||
if (disp_res != DISP_CHANGE_SUCCESSFUL) {
|
||||
log_warning("graphics", "auto-rotate: failed to change display settings: {}", disp_res);
|
||||
log_warning("graphics", "failed to change display settings: {}", disp_res);
|
||||
}
|
||||
} else {
|
||||
log_warning("graphics", "auto-rotate: failed to get display settings");
|
||||
log_warning("graphics", "failed to get display settings");
|
||||
}
|
||||
}
|
||||
|
||||
// gfdm
|
||||
if (avs::game::is_model({"J32", "J33", "K32", "K33", "L32", "L33", "M32"})) {
|
||||
// set window name
|
||||
if (!lpWindowName) {
|
||||
lpWindowName = "GITADORA";
|
||||
}
|
||||
}
|
||||
|
||||
bool is_tdj_sub_window = avs::game::is_model("LDJ") && window_name.ends_with(" sub");
|
||||
bool is_sdvx_sub_window = avs::game::is_model("KFC") && window_name.ends_with(" Sub Screen");
|
||||
|
||||
// TDJ windowed mode with subscreen: hide maximize button
|
||||
if ((is_tdj_sub_window && GRAPHICS_IIDX_WSUB) || is_sdvx_sub_window) {
|
||||
dwStyle &= ~(WS_MAXIMIZEBOX);
|
||||
}
|
||||
|
||||
// call original
|
||||
HWND result = CreateWindowExA_orig(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
|
||||
hWndParent, hMenu, hInstance, lpParam);
|
||||
GRAPHICS_WINDOWS.push_back(result);
|
||||
|
||||
if (is_tdj_sub_window) {
|
||||
// TDJ windowed mode: remember the subscreen window handle for later
|
||||
TDJ_SUBSCREEN_WINDOW = result;
|
||||
|
||||
// hook for preventing the closing of subscreen window
|
||||
if (GRAPHICS_IIDX_WSUB) {
|
||||
graphics_hook_subscreen_window(TDJ_SUBSCREEN_WINDOW);
|
||||
}
|
||||
}
|
||||
|
||||
// hook for preventing the closing of subscreen window
|
||||
if (is_sdvx_sub_window) {
|
||||
SDVX_SUBSCREEN_WINDOW = result;
|
||||
graphics_hook_subscreen_window(SDVX_SUBSCREEN_WINDOW);
|
||||
}
|
||||
|
||||
disable_touch_indicators(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -387,6 +462,8 @@ static HWND WINAPI CreateWindowExW_hook(DWORD dwExStyle, LPCWSTR lpClassName, LP
|
||||
dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight,
|
||||
hWndParent, hMenu, hInstance, lpParam);
|
||||
GRAPHICS_WINDOWS.push_back(result);
|
||||
|
||||
disable_touch_indicators(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -400,10 +477,17 @@ static BOOL WINAPI EnumDisplayDevicesA_hook(LPCTSTR lpDevice, DWORD iDevNum,
|
||||
// call original
|
||||
BOOL value = EnumDisplayDevicesA_orig(lpDevice, iDevNum, lpDisplayDevice, dwFlags);
|
||||
|
||||
// device ID override
|
||||
if (value) {
|
||||
#ifndef SPICE64
|
||||
// older IIDX games check for hardcoded PCI vendor/device ID pair of GPU
|
||||
if ((avs::game::is_model("JDZ") || avs::game::is_model("KDZ")) && value) {
|
||||
log_info(
|
||||
"graphics",
|
||||
"EnumDisplayDevicesA_hook: swap DeviceID {} with {} (for IIDX 18/19)",
|
||||
lpDisplayDevice->DeviceID,
|
||||
GRAPHICS_DEVICEID.c_str());
|
||||
memcpy(&lpDisplayDevice->DeviceID, GRAPHICS_DEVICEID.c_str(), GRAPHICS_DEVICEID.size() + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
// return original result
|
||||
return value;
|
||||
@@ -434,6 +518,39 @@ static BOOL WINAPI MoveWindow_hook(HWND hWnd, int X, int Y, int nWidth, int nHei
|
||||
nHeight = rect.bottom - rect.top;
|
||||
}
|
||||
|
||||
// iidx windowed TDJ mode
|
||||
if (GRAPHICS_WINDOWED && TDJ_SUBSCREEN_WINDOW && hWnd == TDJ_SUBSCREEN_WINDOW) {
|
||||
if (GRAPHICS_IIDX_WSUB) {
|
||||
// (Experimental) Show subscreen in windowed mode
|
||||
graphics_load_windowed_subscreen_parameters();
|
||||
|
||||
RECT rect {};
|
||||
DWORD dwStyle;
|
||||
|
||||
dwStyle = GetWindowLongA(hWnd, GWL_STYLE);
|
||||
|
||||
SetRect(&rect, 0, 0, GRAPHICS_IIDX_WSUB_WIDTH, GRAPHICS_IIDX_WSUB_HEIGHT);
|
||||
AdjustWindowRect(&rect, dwStyle, 0);
|
||||
|
||||
X = GRAPHICS_IIDX_WSUB_X;
|
||||
Y = GRAPHICS_IIDX_WSUB_Y;
|
||||
|
||||
nWidth = rect.right - rect.left;
|
||||
nHeight = rect.bottom - rect.top;
|
||||
|
||||
touch_attach_wnd(TDJ_SUBSCREEN_WINDOW);
|
||||
} else {
|
||||
// Existing behaviour: suppress subscreen window and prompt user to use overlay instead
|
||||
log_info(
|
||||
"graphics",
|
||||
"MoveWindow hook - hiding TDJ subscreen window {}; please use subscreen overlay instead (-iidxtdjw)",
|
||||
fmt::ptr(hWnd));
|
||||
SendMessage(hWnd, WM_CLOSE, 0, 0);
|
||||
TDJ_SUBSCREEN_WINDOW = nullptr;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// call original
|
||||
return MoveWindow_orig(hWnd, X, Y, nWidth, nHeight, bRepaint);
|
||||
}
|
||||
@@ -720,7 +837,12 @@ void graphics_hook_window(HWND hWnd, D3DPRESENT_PARAMETERS *pPresentationParamet
|
||||
if (WNDPROC_ORIG == nullptr) {
|
||||
WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
|
||||
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WindowProc));
|
||||
overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = true;
|
||||
|
||||
// NOLEGACY causes WM_CHAR to be not received
|
||||
// reflec beat game engine does not pass WM_CHAR through for some reason (unrelated to SpiceTouch)
|
||||
if (!rawinput::NOLEGACY && !(avs::game::is_model({"KBR", "LBR", "MBR"}))) {
|
||||
overlay::USE_WM_CHAR_FOR_IMGUI_CHAR_INPUT = true;
|
||||
}
|
||||
graphics_capture_initial_window(hWnd);
|
||||
}
|
||||
}
|
||||
@@ -737,6 +859,14 @@ void graphics_remove_wnd_proc(WNDPROC wndProc) {
|
||||
}
|
||||
}
|
||||
|
||||
void graphics_hook_subscreen_window(HWND hWnd) {
|
||||
// hook window procedure
|
||||
if (WSUB_WNDPROC_ORIG == nullptr) {
|
||||
WSUB_WNDPROC_ORIG = reinterpret_cast<WNDPROC>(GetWindowLongPtrA(hWnd, GWLP_WNDPROC));
|
||||
SetWindowLongPtrA(hWnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(WsubWindowProc));
|
||||
}
|
||||
}
|
||||
|
||||
void graphics_screens_register(int screen) {
|
||||
std::lock_guard<std::mutex> lock(GRAPHICS_SCREENS_M);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user