mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-07 09:00:41 -07:00
7ccd938f9b
## Link to GitHub Issue or related Pull Request, if one exists Fixes #840 ## Description of change Currently, for subscreen games, mouse events are still delivered even when the subscreen overlay window is not visible. Change this so that the subscreen overlay must be active and under the mouse cursor for the mouse-to-touch transformation to occur. Applies to both native and wintouchemu. ## Testing Needs to test everything again.. iidx: - [ ] full screen with overlay - [ ] single window with overlay - [ ] two window Test: mouse, poke, api, real touch screen sdvx: - [ ] full screen with overlay - [ ] windowed popn - [x] full screen with overlay - [x] window with overlay - [x] dedicated window gitadora - [x] single window with overlay - [x] dedicated sub window nostalgia - [x] fullscreen - [x] windowed test: poke wintouchemu - [ ] Do all of the above again with wintouchemu
161 lines
6.0 KiB
C++
161 lines
6.0 KiB
C++
#include "transform.h"
|
|
|
|
#include "hooks/graphics/graphics.h"
|
|
#include "overlay/overlay.h"
|
|
#include "settings.h"
|
|
#include "touch/touch.h"
|
|
|
|
namespace nativetouch::transform {
|
|
|
|
static bool game_client_to_screen(HWND window, POINT *position) {
|
|
RECT client_rect {};
|
|
if (window == nullptr ||
|
|
!GetClientRect(window, &client_rect) ||
|
|
client_rect.right <= 0 || client_rect.bottom <= 0 ||
|
|
!PtInRect(&client_rect, *position)) {
|
|
return false;
|
|
}
|
|
|
|
return ClientToScreen(window, position) != FALSE;
|
|
}
|
|
|
|
static bool screen_to_game_client(HWND window, POINT *position) {
|
|
RECT client_rect {};
|
|
if (window == nullptr ||
|
|
!GetClientRect(window, &client_rect) ||
|
|
client_rect.right <= 0 || client_rect.bottom <= 0 ||
|
|
!ScreenToClient(window, position) ||
|
|
!PtInRect(&client_rect, *position)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool is_tdj_dedicated_subscreen(HWND window) {
|
|
return window != nullptr && GRAPHICS_WINDOWED && GRAPHICS_IIDX_WSUB &&
|
|
window == TDJ_SUBSCREEN_WINDOW;
|
|
}
|
|
|
|
// convert game touch coordinates to Windows desktop coordinates
|
|
bool game_to_screen(HWND window, POINT *position) {
|
|
if (settings::SYNTHETIC_TOUCH_USES_CLIENT_COORDINATES) {
|
|
return game_client_to_screen(window, position);
|
|
}
|
|
|
|
if (!is_tdj_dedicated_subscreen(window)) {
|
|
return true;
|
|
}
|
|
|
|
RECT client_rect {};
|
|
if (!GetClientRect(window, &client_rect) ||
|
|
client_rect.right <= 0 || client_rect.bottom <= 0 ||
|
|
SPICETOUCH_TOUCH_WIDTH <= 0 || SPICETOUCH_TOUCH_HEIGHT <= 0) {
|
|
return false;
|
|
}
|
|
|
|
position->x = MulDiv(
|
|
position->x - SPICETOUCH_TOUCH_X,
|
|
client_rect.right,
|
|
SPICETOUCH_TOUCH_WIDTH);
|
|
position->y = MulDiv(
|
|
position->y - SPICETOUCH_TOUCH_Y,
|
|
client_rect.bottom,
|
|
SPICETOUCH_TOUCH_HEIGHT);
|
|
return ClientToScreen(window, position) != FALSE;
|
|
}
|
|
|
|
static bool has_active_overlay_transform() {
|
|
return overlay::OVERLAY != nullptr &&
|
|
overlay::OVERLAY->get_active() &&
|
|
overlay::OVERLAY->has_subscreen_touch_transform();
|
|
}
|
|
|
|
static bool transform_overlay_touch_position(POINT *position) {
|
|
// convert physical screen coordinates to the window-relative coordinates the overlay expects
|
|
if (GRAPHICS_WINDOWED) {
|
|
position->x -= SPICETOUCH_TOUCH_X;
|
|
position->y -= SPICETOUCH_TOUCH_Y;
|
|
}
|
|
|
|
// ask the overlay to do the game-specific translation
|
|
return overlay::OVERLAY->transform_touch_point(&position->x, &position->y);
|
|
}
|
|
|
|
// convert physical screen coordinates to game touch coordinates for a known target
|
|
bool screen_to_game(HWND window, POINT *position) {
|
|
if (settings::SYNTHETIC_TOUCH_USES_CLIENT_COORDINATES) {
|
|
return screen_to_game_client(window, position);
|
|
}
|
|
|
|
// scale the resized IIDX subscreen client area into the game's touch-display coordinates
|
|
if (is_tdj_dedicated_subscreen(window)) {
|
|
RECT client_rect {};
|
|
if (!GetClientRect(window, &client_rect) ||
|
|
client_rect.right <= 0 || client_rect.bottom <= 0 ||
|
|
SPICETOUCH_TOUCH_WIDTH <= 0 || SPICETOUCH_TOUCH_HEIGHT <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (!ScreenToClient(window, position)) {
|
|
return false;
|
|
}
|
|
if (!PtInRect(&client_rect, *position)) {
|
|
return false;
|
|
}
|
|
position->x = SPICETOUCH_TOUCH_X +
|
|
MulDiv(position->x, SPICETOUCH_TOUCH_WIDTH, client_rect.right);
|
|
position->y = SPICETOUCH_TOUCH_Y +
|
|
MulDiv(position->y, SPICETOUCH_TOUCH_HEIGHT, client_rect.bottom);
|
|
return true;
|
|
}
|
|
|
|
// check if subscreen overlay is active and can transform the touch point;
|
|
// if not, the touch point is valid as-is
|
|
if (!has_active_overlay_transform()) {
|
|
return true;
|
|
}
|
|
|
|
// ask the overlay to transform the touch point into game coordinates
|
|
return transform_overlay_touch_position(position);
|
|
}
|
|
|
|
bool mouse_to_game(HWND window, POINT *position) {
|
|
|
|
// exception: iidx tdj dedicated subscreen window is allowed
|
|
if (is_tdj_dedicated_subscreen(window)) {
|
|
return screen_to_game(window, position);
|
|
}
|
|
|
|
// if this game has a subscreen overlay that can transform touch input
|
|
// but the window is hidden or not under the cursor, reject mouse-as-touch
|
|
// (e.g., iidx/sdvx are rejected here, but nostalgia is allowed)
|
|
if (overlay::OVERLAY != nullptr &&
|
|
overlay::OVERLAY->has_subscreen_touch_transform() &&
|
|
!overlay::OVERLAY->accepts_subscreen_mouse_input()) {
|
|
return false;
|
|
}
|
|
|
|
return screen_to_game(window, position);
|
|
}
|
|
|
|
// route hardware screen coordinates through dedicated or overlay mapping and report the result
|
|
Result hardware_to_game(POINT *position) {
|
|
const auto dedicated_subscreen = is_tdj_dedicated_subscreen(TDJ_SUBSCREEN_WINDOW);
|
|
const auto active_overlay = has_active_overlay_transform();
|
|
|
|
// no dedicated subscreen or active overlay mapping; pass the point through unchanged
|
|
if (!dedicated_subscreen && !active_overlay) {
|
|
return Result::Unchanged;
|
|
}
|
|
|
|
// route through the dedicated subscreen when active, otherwise through the overlay
|
|
const auto valid = screen_to_game(
|
|
dedicated_subscreen ? TDJ_SUBSCREEN_WINDOW : nullptr,
|
|
position);
|
|
|
|
// reject out-of-bounds points and any coordinate conversion failure
|
|
return valid ? Result::Transformed : Result::Rejected;
|
|
}
|
|
}
|