touch: restore wintouchemu, fall back to it when native touch hooks fail (#834)

## Link to GitHub Issue or related Pull Request, if one exists
Fixes #833

## Description of change
Last couple PRs - such as #820 #827 #828 - made the native touch hook &
touch injection using `InjectTouchInput` the default path, since it
performs much more reliably with both real touch screens and mouse (or
any other synthetic source).

However, user has reported that WINE lacks `InjectTouchInput` which
means this won't work.

As a fix, revive the old wintouchemu code. Native touch is still the
default, but under following circumstances:

1. if `-touchemuforce` is set, or
2. if any of the required Windows touch APIs are unavailable

then we fail over from native touch to wintouchemu code. 

For Linux, condition #2 would be hit during init, and gracefully switch
over.

Caveat: the poke code for IIDX and Nost will continue to require native
touch, I do not want to maintain two paths for this. This means that
iidx poke will stop working on Linux, unfortunately.

## Testing
Tested on Windows with `-touchemuforce` set. This is mostly reverting
Linux code path back to where we were last release, so this should just
work with wine.
This commit is contained in:
bicarus
2026-07-26 04:29:45 -07:00
committed by GitHub
parent 64600826b7
commit bd2fbfcb67
20 changed files with 435 additions and 56 deletions
+8 -1
View File
@@ -11,6 +11,7 @@
#include "hooks/audio/audio.h"
#include "hooks/audio/mme.h"
#include "hooks/graphics/graphics.h"
#include "misc/wintouchemu.h"
#include "overlay/overlay.h"
#include "touch/native/nativetouchhook.h"
#include "util/cpuutils.h"
@@ -653,7 +654,13 @@ namespace games::gitadora {
// monitor/touch hooks (windowed or full screen)
if (GRAPHICS_PREVENT_SECONDARY_WINDOWS) {
// enable touch hook for subscreen overlay
nativetouch::hook(avs::game::DLL_INSTANCE);
const auto native_touch_ready = !wintouchemu::FORCE &&
nativetouch::hook(avs::game::DLL_INSTANCE);
if (!native_touch_ready) {
wintouchemu::FORCE = true;
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook("GITADORA", avs::game::DLL_INSTANCE);
}
#if !SPICE_XP
+20 -1
View File
@@ -22,6 +22,7 @@
#include "touch/touch.h"
#include "touch/native/nativetouchhook.h"
#include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "util/detour.h"
#include "util/deferlog.h"
#include "util/fileutils.h"
@@ -40,6 +41,7 @@
#include "bi2x_hook.h"
#include "ezusb.h"
#include "io.h"
#include "poke.h"
static decltype(RegCloseKey) *RegCloseKey_orig = nullptr;
static decltype(RegEnumKeyA) *RegEnumKeyA_orig = nullptr;
@@ -62,6 +64,8 @@ namespace games::iidx {
bool TDJ_MODE = false;
bool FORCE_720P = false;
bool DISABLE_ESPEC_IO = false;
bool NATIVE_TOUCH = true;
bool ENABLE_POKE = false;
std::optional<std::string> SOUND_OUTPUT_DEVICE = std::nullopt;
std::optional<std::string> SOUND_OUTPUT_DEVICE_IN_EFFECT = std::nullopt;
std::optional<std::string> ASIO_DRIVER = std::nullopt;
@@ -348,7 +352,16 @@ namespace games::iidx {
// need to hook `avs2-core.dll` so AVS win32fs operations go through rom hook
devicehook_init(avs::core::DLL_INSTANCE);
nativetouch::hook(avs::game::DLL_INSTANCE);
NATIVE_TOUCH = !wintouchemu::FORCE &&
nativetouch::hook(avs::game::DLL_INSTANCE);
if (!NATIVE_TOUCH) {
wintouchemu::FORCE = true;
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends(
"beatmania IIDX",
"main",
avs::game::DLL_INSTANCE);
}
}
// insert BI2X hooks
@@ -525,6 +538,12 @@ namespace games::iidx {
}
}
void IIDXGame::post_attach() {
if (ENABLE_POKE) {
poke::enable();
}
}
void IIDXGame::detach() {
Game::detach();
+3
View File
@@ -28,6 +28,8 @@ namespace games::iidx {
extern bool TDJ_MODE;
extern bool FORCE_720P;
extern bool DISABLE_ESPEC_IO;
extern bool NATIVE_TOUCH;
extern bool ENABLE_POKE;
extern std::optional<std::string> SOUND_OUTPUT_DEVICE;
extern std::optional<std::string> ASIO_DRIVER;
extern uint8_t DIGITAL_TT_SENS;
@@ -52,6 +54,7 @@ namespace games::iidx {
virtual void attach() override;
virtual void pre_attach() override;
virtual void post_attach() override;
virtual void detach() override;
private:
+6
View File
@@ -4,6 +4,7 @@
#include "windows.h"
#include "games/io.h"
#include "games/iidx/iidx.h"
#include "hooks/graphics/graphics.h"
#include "launcher/shutdown.h"
#include "misc/eamuse.h"
@@ -116,6 +117,11 @@ namespace games::iidx::poke {
if (THREAD)
return;
if (!games::iidx::NATIVE_TOUCH) {
log_warning("poke", "keypad touch emulation requires native touch; disabled");
return;
}
// create new thread
THREAD_RUNNING = true;
THREAD = new std::thread([] {
+10 -3
View File
@@ -2,6 +2,7 @@
#include "poke.h"
#include "touch_mode.h"
#include "hooks/setupapihook.h"
#include "misc/wintouchemu.h"
#include "touch/native/nativetouchhook.h"
#include "avs/game.h"
@@ -41,9 +42,15 @@ namespace games::nost {
setupapihook_init(avs::game::DLL_INSTANCE);
setupapihook_add(touch_settings);
nativetouch::hook(avs::game::DLL_INSTANCE);
if (ENABLE_TOUCH_MODE) {
touch_mode::enable();
const auto native_touch_ready = !wintouchemu::FORCE &&
nativetouch::hook(avs::game::DLL_INSTANCE);
if (!native_touch_ready) {
wintouchemu::FORCE = true;
wintouchemu::hook("nostalgia", avs::game::DLL_INSTANCE, 20);
} else {
if (ENABLE_TOUCH_MODE) {
touch_mode::enable();
}
}
}
+6
View File
@@ -9,6 +9,7 @@
#include "rawinput/rawinput.h"
#include "misc/eamuse.h"
#include "touch/native/inject.h"
#include "touch/native/nativetouchhook.h"
#include "util/logging.h"
#include "util/precise_timer.h"
@@ -59,6 +60,11 @@ namespace games::nost::poke {
return;
}
if (!nativetouch::is_hooked()) {
log_warning("poke", "Nostalgia poke requires native touch; disabled");
return;
}
// create new thread
THREAD_RUNNING = true;
THREAD = new std::thread([] {
+14 -1
View File
@@ -16,6 +16,7 @@
#include "launcher/launcher.h"
#include "launcher/logger.h"
#include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "util/sysutils.h"
#include "io.h"
#include "util/deferlog.h"
@@ -24,6 +25,7 @@
namespace games::popn {
bool SHOW_PIKA_MONITOR_WARNING = false;
bool NATIVE_TOUCH = true;
#if SPICE64 && !SPICE_XP
@@ -713,7 +715,18 @@ namespace games::popn {
// 00000100 0000000B 00000001 (button 9)
// set third column to 0 and it will work with BIO2
nativetouch::hook(avs::game::DLL_INSTANCE);
NATIVE_TOUCH = !wintouchemu::FORCE &&
nativetouch::hook(avs::game::DLL_INSTANCE);
if (!NATIVE_TOUCH) {
wintouchemu::FORCE = true;
if (!GRAPHICS_WINDOWED || GRAPHICS_PREVENT_SECONDARY_WINDOWS) {
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends(
"",
"Main Screen",
avs::game::DLL_INSTANCE);
}
}
sysutils::hook_EnumDisplayDevicesA();
+1
View File
@@ -22,6 +22,7 @@ namespace games::popn {
#endif
extern bool SHOW_PIKA_MONITOR_WARNING;
extern bool NATIVE_TOUCH;
class POPNGame : public games::Game {
public:
+13 -1
View File
@@ -26,6 +26,7 @@
#include "util/libutils.h"
#include "util/sysutils.h"
#include "misc/eamuse.h"
#include "misc/wintouchemu.h"
#include "touch/native/nativetouchhook.h"
#include "bi2x_hook.h"
#include "camera.h"
@@ -453,7 +454,18 @@ namespace games::sdvx {
}
if (is_valkyrie_model()) {
nativetouch::hook(avs::game::DLL_INSTANCE);
const auto native_touch_ready = !wintouchemu::FORCE &&
nativetouch::hook(avs::game::DLL_INSTANCE);
if (!native_touch_ready) {
wintouchemu::FORCE = true;
if (!GRAPHICS_WINDOWED) {
wintouchemu::INJECT_MOUSE_AS_WM_TOUCH = true;
wintouchemu::hook_title_ends(
"SOUND VOLTEX",
"Main Screen",
avs::game::DLL_INSTANCE);
}
}
// insert BI2X hooks
bi2x_hook_init();