sao: improve touch hook

This commit is contained in:
Dniel97
2026-03-09 21:35:40 +01:00
parent 6c5a0affff
commit b3c4fa9a21
11 changed files with 338 additions and 80 deletions
+11
View File
@@ -14,3 +14,14 @@ void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename)
cfg->enable = GetPrivateProfileIntW(L"dvd", L"enable", 1, filename);
}
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"touch", L"enable", 1, filename);
cfg->remap = GetPrivateProfileIntW(L"touch", L"remap", 1, filename);
cfg->cursor = GetPrivateProfileIntW(L"touch", L"cursor", 1, filename);
cfg->setwndptr = GetPrivateProfileIntW(L"touch", L"setwndptr", 0, filename);
}
+2
View File
@@ -3,5 +3,7 @@
#include <stddef.h>
#include "hooklib/dvd.h"
#include "hooklib/touch.h"
void dvd_config_load(struct dvd_config *cfg, const wchar_t *filename);
void touch_screen_config_load(struct touch_screen_config *cfg, const wchar_t *filename);
+2
View File
@@ -26,5 +26,7 @@ hooklib_lib = static_library(
'setupapi.h',
'spike.c',
'spike.h',
'touch.c',
'touch.h',
],
)
+298
View File
@@ -0,0 +1,298 @@
/*
This part (touch screen hook) is mostly taken from spicetools, which is GPL.
This means there can be some license issues if you do use this code in some other places without including source code.
*/
#include <windows.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include "hook/com-proxy.h"
#include "hook/table.h"
#include "hooklib/config.h"
#include "hooklib/dll.h"
#include "hooklib/touch.h"
#include "util/dprintf.h"
/* API hooks */
static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
static ATOM WINAPI hook_RegisterClassExA(
WNDCLASSEXA* wndClass
);
static int WINAPI hook_GetSystemMetrics(
int nIndex
);
static BOOL WINAPI hook_RegisterTouchWindow(
HWND hwnd,
ULONG ulFlags
);
static BOOL WINAPI hook_GetTouchInputInfo(
HANDLE hTouchInput,
UINT cInputs,
PTOUCHINPUT pInputs,
int cbSize
);
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor);
static int WINAPI hook_ShowCursor(BOOL bShow);
static LONG_PTR WINAPI hook_SetWindowLongPtrA(HWND hWnd, int nIndex, LONG_PTR dwNewLong);
/* Link pointers */
static ATOM (WINAPI *next_RegisterClassExA)(
const WNDCLASSEXA* wndClass
);
static int (WINAPI *next_GetSystemMetrics)(
int nIndex
);
static BOOL (WINAPI *next_RegisterTouchWindow)(
HWND hwnd,
ULONG ulFlags
);
static BOOL (WINAPI *next_GetTouchInputInfo)(
HANDLE hTouchInput,
UINT cInputs,
PTOUCHINPUT pInputs,
int cbSize
);
static HCURSOR(WINAPI *next_SetCursor)(HCURSOR cursor);
static int (WINAPI *next_ShowCursor)(BOOL bShow);
static LONG_PTR (WINAPI *next_SetWindowLongPtrA)(HWND hWnd, int nIndex, LONG_PTR dwNewLong);
static bool touch_hook_initted;
static bool touch_held;
static HWND registered_hWnd;
static struct touch_screen_config touch_config;
static WNDPROC orig_wndProc;
static HCURSOR defaultCursor;
static const struct hook_symbol touch_hooks[] = {
{
.name = "RegisterClassExA",
.patch = hook_RegisterClassExA,
.link = (void**)&next_RegisterClassExA
},
{
.name = "GetSystemMetrics",
.patch = hook_GetSystemMetrics,
.link = (void **) &next_GetSystemMetrics
},
{
.name = "RegisterTouchWindow",
.patch = hook_RegisterTouchWindow,
.link = (void **) &next_RegisterTouchWindow
},
{
.name = "GetTouchInputInfo",
.patch = hook_GetTouchInputInfo,
.link = (void **) &next_GetTouchInputInfo
},
{
.name = "ShowCursor",
.patch = hook_ShowCursor,
.link = (void **) &next_ShowCursor
},
{
.name = "SetCursor",
.patch = hook_SetCursor,
.link = (void **) &next_SetCursor
},
{
.name = "SetWindowLongPtrA",
.patch = hook_SetWindowLongPtrA,
.link = (void**) &next_SetWindowLongPtrA
},
};
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self)
{
assert(cfg != NULL);
if (!cfg->enable) {
return;
}
if (touch_hook_initted) {
return;
}
touch_hook_initted = true;
defaultCursor = LoadCursorA(NULL, IDC_CROSS);
memcpy(&touch_config, cfg, sizeof(*cfg));
touch_hook_insert_hooks(NULL);
dprintf("TOUCH: hook enabled.\n");
}
void touch_hook_insert_hooks(HMODULE target)
{
hook_table_apply(
target,
"user32.dll",
touch_hooks,
_countof(touch_hooks));
}
static int WINAPI hook_ShowCursor(BOOL bShow)
{
if (touch_config.cursor) {
return 1;
}
return next_ShowCursor(bShow);
}
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
if (cursor == 0 && touch_config.cursor)
return next_SetCursor(defaultCursor);
return next_SetCursor(cursor);
}
// remap mouse events to touch events
static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) {
if (hWnd == registered_hWnd && (Msg == WM_LBUTTONDOWN || Msg == WM_LBUTTONUP || (touch_held && Msg == WM_MOUSEMOVE))) {
orig_wndProc(hWnd, WM_TOUCH, 1, 1);
}
if (Msg == WM_SETCURSOR && touch_config.cursor) {
SetCursor(defaultCursor);
return TRUE;
}
return orig_wndProc(hWnd, Msg, wParam, lParam);
}
static ATOM WINAPI hook_RegisterClassExA(
WNDCLASSEXA* wndClass
) {
if (!touch_config.setwndptr && wndClass->lpfnWndProc) {
orig_wndProc = wndClass->lpfnWndProc;
wndClass->lpfnWndProc = (WNDPROC) hook_wndProc;
}
return next_RegisterClassExA(wndClass);
}
// Spicetools misc/wintouchemu.cpp
static int WINAPI hook_GetSystemMetrics(
int nIndex
)
{
if (nIndex == 94) return 0x01 | 0x02 | 0x40 | 0x80;
int orig = next_GetSystemMetrics(nIndex);
return orig;
}
static BOOL WINAPI hook_RegisterTouchWindow(
HWND hwnd,
ULONG ulFlags
)
{
registered_hWnd = hwnd;
return true;
}
// Soul Reverse uses this to initialize wndprocs handling input
static LONG_PTR WINAPI hook_SetWindowLongPtrA(HWND hWnd, int nIndex, LONG_PTR dwNewLong) {
if (touch_config.setwndptr && nIndex == -4) {
orig_wndProc = (WNDPROC) dwNewLong;
dwNewLong = (LONG_PTR) hook_wndProc;
}
return next_SetWindowLongPtrA(hWnd, nIndex, dwNewLong);
}
// Converting mouse event to touch event
static BOOL WINAPI hook_GetTouchInputInfo(
HANDLE hTouchInput,
UINT cInputs,
PTOUCHINPUT pInputs,
int cbSize
)
{
bool result = false;
int sw, sh, cw, ch;
RECT cRect;
sw = GetSystemMetrics(SM_CXSCREEN);
sh = GetSystemMetrics(SM_CYSCREEN);
GetClientRect(registered_hWnd, &cRect);
cw = cRect.right - cRect.left;
ch = cRect.bottom - cRect.top;
static bool mouse_state_old = false;
for (UINT input = 0; input < cInputs; input++) {
TOUCHINPUT *touch_input = &pInputs[input];
touch_input->x = 0;
touch_input->y = 0;
touch_input->hSource = NULL;
touch_input->dwID = 0;
touch_input->dwFlags = 0;
touch_input->dwMask = 0;
touch_input->dwTime = 0;
touch_input->dwExtraInfo = 0;
touch_input->cxContact = 0;
touch_input->cyContact = 0;
bool mouse_state = (GetKeyState(VK_LBUTTON) & 0x100) != 0;
if (mouse_state || mouse_state_old) {
POINT cursorPos;
GetCursorPos(&cursorPos);
if (touch_config.remap) {
ScreenToClient(registered_hWnd, &cursorPos);
cursorPos.x = (long)(cursorPos.x * ((double)sw / cw));
cursorPos.y = (long)(cursorPos.y * ((double)sh / ch));
}
result = true;
touch_input->x = cursorPos.x * 100;
touch_input->y = cursorPos.y * 100;
touch_input->hSource = hTouchInput;
touch_input->dwID = 1;
touch_input->dwFlags = 0;
if (mouse_state && !mouse_state_old) {
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
touch_held = true;
} else if (mouse_state && mouse_state_old) {
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
} else if (!mouse_state && mouse_state_old) {
touch_input->dwFlags |= TOUCHEVENTF_UP;
touch_held = false;
}
touch_input->dwMask = 0;
touch_input->dwTime = 0;
touch_input->dwExtraInfo = 0;
touch_input->cxContact = 0;
touch_input->cyContact = 0;
}
mouse_state_old = mouse_state;
}
return result;
}
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
struct touch_screen_config {
bool enable;
bool remap;
bool cursor;
bool setwndptr;
};
/* Init is not thread safe because API hook init is not thread safe blah
blah blah you know the drill by now. */
void touch_screen_hook_init(const struct touch_screen_config *cfg, HINSTANCE self);
void touch_hook_insert_hooks(HMODULE target);
+3 -13
View File
@@ -4,6 +4,8 @@
#include "saohook/config.h"
#include "hooklib/config.h"
#include "platform/config.h"
void sao_dll_config_load(
@@ -41,18 +43,6 @@ void systype_config_load(
);
}
void sao_touch_config_load(
struct sao_touch_config *cfg,
const wchar_t *filename)
{
cfg->enable = GetPrivateProfileIntW(
L"touch",
L"enable",
1,
filename
);
}
void sao_hook_config_load(
struct sao_hook_config *cfg,
const wchar_t *filename)
@@ -67,6 +57,6 @@ void sao_hook_config_load(
qr_config_load(&cfg->qr, filename);
usio_config_load(&cfg->usio, filename);
systype_config_load(&cfg->systype, filename);
sao_touch_config_load(&cfg->touch, filename);
touch_screen_config_load(&cfg->touch, filename);
vfd_config_load(&cfg->vfd, filename);
}
+2 -7
View File
@@ -5,11 +5,11 @@
#include "saohook/sao-dll.h"
#include "platform/config.h"
#include "hooklib/touch.h"
#include "gfxhook/config.h"
#include "amcus/config.h"
#include "board/config.h"
#include "saohook/systype.h"
#include "saohook/touch.h"
struct sao_hook_config {
struct platform_config platform;
@@ -20,7 +20,7 @@ struct sao_hook_config {
struct qr_config qr;
struct usio_config usio;
struct systype_config systype;
struct sao_touch_config touch;
struct touch_screen_config touch;
struct vfd_config vfd;
};
@@ -39,8 +39,3 @@ void sao_hook_config_load(
void systype_config_load(
struct systype_config *cfg,
const wchar_t *filename);
void sao_touch_config_load(
struct sao_touch_config *cfg,
const wchar_t *filename);
+2 -7
View File
@@ -6,13 +6,13 @@
#include "saohook/usio.h"
#include "saohook/unity.h"
#include "saohook/systype.h"
#include "saohook/touch.h"
#include "amcus/amcus.h"
#include "hook/process.h"
#include "hooklib/serial.h"
#include "hooklib/touch.h"
#include "board/sg-reader.h"
#include "board/vfd.h"
@@ -35,6 +35,7 @@ static DWORD CALLBACK sao_pre_startup(void)
sao_hook_config_load(&sao_hook_cfg, L".\\bananatools.ini");
touch_screen_hook_init(&sao_hook_cfg.touch, sao_hook_mod);
serial_hook_init();
struct dongle_info dinfo;
@@ -79,12 +80,6 @@ static DWORD CALLBACK sao_pre_startup(void)
hr = systype_hook_init(&sao_hook_cfg.systype, &sao_hook_cfg.platform.dongle);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
hr = sao_touch_hook_init(&sao_hook_cfg.touch);
if (FAILED(hr)) {
ExitProcess(EXIT_FAILURE);
}
-2
View File
@@ -29,8 +29,6 @@ shared_library(
'sao-dll.h',
'systype.c',
'systype.h',
'touch.c',
'touch.h',
'usio.c',
'usio.h',
'unity.c',
-42
View File
@@ -1,42 +0,0 @@
#include <windows.h>
#include <winuser.h>
#include <stdlib.h>
#include "hook/table.h"
#include "hooklib/reg.h"
#include "util/dprintf.h"
#include "saohook/touch.h"
static int WINAPI my_GetSystemMetrics(int nIndex);
static int (WINAPI *next_GetSystemMetrics)(int nIndex);
static const struct hook_symbol touch_user32_syms[] = {
{
.name = "GetSystemMetrics",
.patch = my_GetSystemMetrics,
.link = (void **) &next_GetSystemMetrics,
},
};
HRESULT sao_touch_hook_init(const struct sao_touch_config *cfg)
{
if (!cfg->enable) {
return S_OK;
}
hook_table_apply(
NULL,
"User32.dll",
touch_user32_syms,
_countof(touch_user32_syms));
return S_OK;
}
static int WINAPI my_GetSystemMetrics(int nIndex)
{
if (nIndex == SM_DIGITIZER) {
return NID_MULTI_INPUT;
}
return next_GetSystemMetrics(nIndex);
}
-9
View File
@@ -1,9 +0,0 @@
#pragma once
#include <windows.h>
#include <stdbool.h>
struct sao_touch_config {
bool enable;
};
HRESULT sao_touch_hook_init(const struct sao_touch_config *cfg);