2023-07-13 22:59:10 +00:00
|
|
|
/*
|
|
|
|
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 */
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
static LRESULT hook_wndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
|
|
|
|
|
|
|
|
static ATOM WINAPI hook_RegisterClassExA(
|
|
|
|
WNDCLASSEXA* wndClass
|
|
|
|
);
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
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
|
|
|
|
);
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor);
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
/* Link pointers */
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
static ATOM (WINAPI *next_RegisterClassExA)(
|
|
|
|
const WNDCLASSEXA* wndClass
|
|
|
|
);
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
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
|
|
|
|
);
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
static HCURSOR(WINAPI *next_SetCursor)(HCURSOR cursor);
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
static bool touch_hook_initted;
|
2023-08-15 15:28:19 +00:00
|
|
|
static bool touch_held;
|
|
|
|
static HWND registered_hWnd;
|
2023-07-13 22:59:10 +00:00
|
|
|
static struct touch_screen_config touch_config;
|
2023-08-15 15:28:19 +00:00
|
|
|
static WNDPROC orig_wndProc;
|
2023-07-13 22:59:10 +00:00
|
|
|
|
|
|
|
static const struct hook_symbol touch_hooks[] = {
|
2023-08-15 15:28:19 +00:00
|
|
|
{
|
|
|
|
.name = "RegisterClassExA",
|
|
|
|
.patch = hook_RegisterClassExA,
|
|
|
|
.link = (void**)&next_RegisterClassExA
|
|
|
|
},
|
2023-07-13 22:59:10 +00:00
|
|
|
{
|
|
|
|
.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
|
|
|
|
},
|
2023-08-15 15:28:19 +00:00
|
|
|
{
|
|
|
|
.name = "SetCursor",
|
|
|
|
.patch = hook_SetCursor,
|
|
|
|
.link = (void **) &next_SetCursor
|
|
|
|
},
|
2023-07-13 22:59:10 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
memcpy(&touch_config, cfg, sizeof(*cfg));
|
|
|
|
hook_table_apply(NULL, "user32.dll", touch_hooks, _countof(touch_hooks));
|
|
|
|
dprintf("TOUCH: hook enabled.\n");
|
|
|
|
}
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
static HCURSOR WINAPI hook_SetCursor(HCURSOR cursor) {
|
|
|
|
if (cursor == 0 && touch_config.cursor)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
return orig_wndProc(hWnd, Msg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
static ATOM WINAPI hook_RegisterClassExA(
|
|
|
|
WNDCLASSEXA* wndClass
|
|
|
|
) {
|
|
|
|
if (wndClass->lpfnWndProc) {
|
|
|
|
orig_wndProc = wndClass->lpfnWndProc;
|
|
|
|
wndClass->lpfnWndProc = (WNDPROC) hook_wndProc;
|
|
|
|
}
|
|
|
|
|
|
|
|
return next_RegisterClassExA(wndClass);
|
|
|
|
}
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
// 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
|
|
|
|
)
|
|
|
|
{
|
2023-08-15 15:28:19 +00:00
|
|
|
registered_hWnd = hwnd;
|
2023-07-13 22:59:10 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Converting mouse event to touch event
|
|
|
|
static BOOL WINAPI hook_GetTouchInputInfo(
|
|
|
|
HANDLE hTouchInput,
|
|
|
|
UINT cInputs,
|
|
|
|
PTOUCHINPUT pInputs,
|
|
|
|
int cbSize
|
|
|
|
)
|
|
|
|
{
|
|
|
|
bool result = false;
|
2023-08-15 15:28:19 +00:00
|
|
|
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;
|
2023-07-13 22:59:10 +00:00
|
|
|
static bool mouse_state_old = false;
|
2023-08-15 15:28:19 +00:00
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
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;
|
2023-08-15 15:28:19 +00:00
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
GetCursorPos(&cursorPos);
|
|
|
|
|
2023-08-15 15:28:19 +00:00
|
|
|
if (touch_config.remap) {
|
|
|
|
ScreenToClient(registered_hWnd, &cursorPos);
|
|
|
|
cursorPos.x = (long)(cursorPos.x * ((double)sw / cw));
|
|
|
|
cursorPos.y = (long)(cursorPos.y * ((double)sh / ch));
|
|
|
|
}
|
|
|
|
|
2023-07-13 22:59:10 +00:00
|
|
|
result = true;
|
|
|
|
touch_input->x = cursorPos.x * 100;
|
|
|
|
touch_input->y = cursorPos.y * 100;
|
|
|
|
touch_input->hSource = hTouchInput;
|
|
|
|
touch_input->dwID = 0;
|
|
|
|
touch_input->dwFlags = 0;
|
|
|
|
if (mouse_state && !mouse_state_old) {
|
|
|
|
touch_input->dwFlags |= TOUCHEVENTF_DOWN;
|
2023-08-15 15:28:19 +00:00
|
|
|
touch_held = true;
|
2023-07-13 22:59:10 +00:00
|
|
|
} else if (mouse_state && mouse_state_old) {
|
|
|
|
touch_input->dwFlags |= TOUCHEVENTF_MOVE;
|
|
|
|
} else if (!mouse_state && mouse_state_old) {
|
|
|
|
touch_input->dwFlags |= TOUCHEVENTF_UP;
|
2023-08-15 15:28:19 +00:00
|
|
|
touch_held = false;
|
2023-07-13 22:59:10 +00:00
|
|
|
}
|
|
|
|
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;
|
2023-08-15 15:28:19 +00:00
|
|
|
}
|