diff --git a/src/spice2x/misc/wintouchemu.cpp b/src/spice2x/misc/wintouchemu.cpp index 8b1eb42..a34a043 100644 --- a/src/spice2x/misc/wintouchemu.cpp +++ b/src/spice2x/misc/wintouchemu.cpp @@ -495,6 +495,14 @@ namespace wintouchemu { if (hWnd != nullptr && USE_MOUSE) { bool button_pressed = get_async_primary_mouse(); + // while the subscreen overlay cannot accept the mouse, treat the button as + // released; this ends any active touch and prevents new mouse touch contacts + if (overlay::OVERLAY && + overlay::OVERLAY->has_subscreen_touch_transform() && + !overlay::OVERLAY->accepts_subscreen_mouse_input()) { + button_pressed = false; + } + // if there was a touch event in the last 500 ms, don't insert new button presses if (button_pressed && (now - last_touch_event) < 500) { button_pressed = false; diff --git a/src/spice2x/overlay/overlay.cpp b/src/spice2x/overlay/overlay.cpp index f0af959..79b5d6c 100644 --- a/src/spice2x/overlay/overlay.cpp +++ b/src/spice2x/overlay/overlay.cpp @@ -908,6 +908,17 @@ bool overlay::SpiceOverlay::get_active() { return this->active; } +bool overlay::SpiceOverlay::is_subscreen_overlay_visible() { + return this->get_active() && + this->window_sub != nullptr && + this->window_sub->get_active(); +} + +bool overlay::SpiceOverlay::accepts_subscreen_mouse_input() { + return this->is_subscreen_overlay_visible() && + this->window_sub->is_mouse_hovered(); +} + bool overlay::SpiceOverlay::has_focus() { return this->get_active() && ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow); } diff --git a/src/spice2x/overlay/overlay.h b/src/spice2x/overlay/overlay.h index a1265c7..ef6f15f 100644 --- a/src/spice2x/overlay/overlay.h +++ b/src/spice2x/overlay/overlay.h @@ -109,6 +109,7 @@ namespace overlay { void show_main_menu(); void set_active(bool active); bool get_active(); + bool accepts_subscreen_mouse_input(); bool has_focus(); bool hotkeys_triggered(); @@ -143,20 +144,20 @@ namespace overlay { return this->hWnd; } - bool can_transform_touch_input() { - return (this->subscreen_mouse_handler != nullptr); + bool has_subscreen_touch_transform() { + return (this->subscreen_touch_transform != nullptr); } bool transform_touch_point(LONG *x, LONG *y) { - if (this->get_active() && this->subscreen_mouse_handler) { - return this->subscreen_mouse_handler(x, y); + if (this->get_active() && this->subscreen_touch_transform) { + return this->subscreen_touch_transform(x, y); } else { return true; } } - void set_subscreen_mouse_handler(const std::function &f) { - this->subscreen_mouse_handler = f; + void set_subscreen_touch_transform(const std::function &f) { + this->subscreen_touch_transform = f; } // renderer @@ -203,7 +204,7 @@ namespace overlay { std::vector> windows; - std::function subscreen_mouse_handler = nullptr; + std::function subscreen_touch_transform = nullptr; bool active = false; bool toggle_down = false; @@ -216,6 +217,7 @@ namespace overlay { // so render() never runs without a matching NewFrame. bool has_pending_frame = false; + bool is_subscreen_overlay_visible(); void init(); void add_font(const char* font, ImFontConfig* config, const ImWchar* glyphs); }; diff --git a/src/spice2x/overlay/window.cpp b/src/spice2x/overlay/window.cpp index 64d043d..8b07f61 100644 --- a/src/spice2x/overlay/window.cpp +++ b/src/spice2x/overlay/window.cpp @@ -69,6 +69,7 @@ void overlay::Window::build() { // check if active if (!this->active) { + this->mouse_hovered = false; return; } @@ -106,10 +107,18 @@ void overlay::Window::build() { // top spot. suppress that so only an explicit focus request (see below) // decides what comes to the front. const std::string window_id = this->title + "###" + to_string(this); - if (ImGui::Begin( + const bool build_contents = ImGui::Begin( window_id.c_str(), &this->active, - this->flags | ImGuiWindowFlags_NoFocusOnAppearing)) { + this->flags | ImGuiWindowFlags_NoFocusOnAppearing); + + // keep the window hovered while its invisible input button is held during a drag + this->mouse_hovered = + ImGui::IsWindowHovered( + ImGuiHoveredFlags_RootAndChildWindows | + ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); + + if (build_contents) { // window attributes - init_pos / init_size are only honored once // (ImGuiCond_Once), so compute them a single time instead of every frame @@ -154,6 +163,9 @@ void overlay::Window::build() { } else { + // raw content does not have an ImGui window to hover + this->mouse_hovered = false; + // add raw content this->build_content(); } @@ -201,3 +213,7 @@ bool overlay::Window::get_active() { // now it depends on us return this->active; } + +bool overlay::Window::is_mouse_hovered() { + return this->mouse_hovered; +} diff --git a/src/spice2x/overlay/window.h b/src/spice2x/overlay/window.h index 7c778ed..732b42b 100644 --- a/src/spice2x/overlay/window.h +++ b/src/spice2x/overlay/window.h @@ -24,6 +24,7 @@ namespace overlay { void toggle_active(); void set_active(bool active); bool get_active(); + bool is_mouse_hovered(); // raise this window to the top of the z-order on its next build. only // call in response to an explicit user action (keyboard toggle, UI @@ -37,6 +38,7 @@ namespace overlay { // set when the window transitions to visible so build() raises it to the // top of the z-order on the next frame bool request_focus = false; + bool mouse_hovered = false; std::vector children; // settings diff --git a/src/spice2x/overlay/windows/generic_sub.cpp b/src/spice2x/overlay/windows/generic_sub.cpp index 942776b..1147d8f 100644 --- a/src/spice2x/overlay/windows/generic_sub.cpp +++ b/src/spice2x/overlay/windows/generic_sub.cpp @@ -42,7 +42,7 @@ namespace overlay::windows { this->texture_width = 0; this->texture_height = 0; - overlay->set_subscreen_mouse_handler([this](LONG *x, LONG *y) -> bool { + overlay->set_subscreen_touch_transform([this](LONG *x, LONG *y) -> bool { // convert to normalized form (relative window coordinates 0.f-1.f) ImVec2 xy; diff --git a/src/spice2x/touch/native/inject_mouse.cpp b/src/spice2x/touch/native/inject_mouse.cpp index 29f0a79..c775e88 100644 --- a/src/spice2x/touch/native/inject_mouse.cpp +++ b/src/spice2x/touch/native/inject_mouse.cpp @@ -41,7 +41,7 @@ namespace nativetouch::inject { } POINT transformed = *position; - return transform::screen_to_game(window, &transformed); + return transform::mouse_to_game(window, &transformed); } // release the active injected contact and its window capture @@ -108,7 +108,7 @@ namespace nativetouch::inject { } POINT transformed = position; - if (!transform::screen_to_game(window, &transformed)) { + if (!transform::mouse_to_game(window, &transformed)) { end_mouse_contact(window); return; } diff --git a/src/spice2x/touch/native/transform.cpp b/src/spice2x/touch/native/transform.cpp index 35140df..267ca1d 100644 --- a/src/spice2x/touch/native/transform.cpp +++ b/src/spice2x/touch/native/transform.cpp @@ -68,7 +68,7 @@ namespace nativetouch::transform { static bool has_active_overlay_transform() { return overlay::OVERLAY != nullptr && overlay::OVERLAY->get_active() && - overlay::OVERLAY->can_transform_touch_input(); + overlay::OVERLAY->has_subscreen_touch_transform(); } static bool transform_overlay_touch_position(POINT *position) { @@ -120,6 +120,25 @@ namespace nativetouch::transform { 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); diff --git a/src/spice2x/touch/native/transform.h b/src/spice2x/touch/native/transform.h index 6bf5d8d..77a71af 100644 --- a/src/spice2x/touch/native/transform.h +++ b/src/spice2x/touch/native/transform.h @@ -12,5 +12,6 @@ namespace nativetouch::transform { bool is_tdj_dedicated_subscreen(HWND window); bool game_to_screen(HWND window, POINT *position); bool screen_to_game(HWND window, POINT *position); + bool mouse_to_game(HWND window, POINT *position); Result hardware_to_game(POINT *position); } diff --git a/src/spice2x/touch/touch.cpp b/src/spice2x/touch/touch.cpp index 0ade823..22756cb 100644 --- a/src/spice2x/touch/touch.cpp +++ b/src/spice2x/touch/touch.cpp @@ -944,7 +944,7 @@ void touch_get_points(std::vector &touch_points, bool overlay) { if (!overlay && overlay::OVERLAY && overlay::OVERLAY->get_active() && - !overlay::OVERLAY->can_transform_touch_input() && + !overlay::OVERLAY->has_subscreen_touch_transform() && ImGui::GetIO().WantCaptureMouse) { return; @@ -971,7 +971,7 @@ void touch_get_events(std::vector &touch_events, bool overlay) { if (!overlay && overlay::OVERLAY && overlay::OVERLAY->get_active() && - !overlay::OVERLAY->can_transform_touch_input() && + !overlay::OVERLAY->has_subscreen_touch_transform() && ImGui::GetIO().WantCaptureMouse) { TOUCH_EVENTS.reset();