mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 14:50:41 -07:00
09ed8b948c
## Link to GitHub Issue or related Pull Request, if one exists #814 ## Description of change Switch over Nostalgia from wintouchemu to native touch hook. Nostalgia has some strict timing requirements (touches must be updated on every acio poll) so this takes a slightly different path to maintain mouse holds. Only a handful of consumers of wintouchemu remain: 1. beatstream - but it's off by default, only enabled as errata for buggy touchscreens, or if the user forces it on (for Show Cursor) 2. gitadora single-window overlay - this is just for mouse so not a big deal. 3. MFC HG mode - not a priority to fix. ## Testing Tested full screen and windowed mode with touch / mouse / poke.
142 lines
5.3 KiB
C++
142 lines
5.3 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->can_transform_touch_input();
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|