2010-10-24 01:02:08 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2010 Toni Spets <toni.spets@iki.fi>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* This is a special mouse coordinate fix for games that use GetCursorPos and expect to be in fullscreen */
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "main.h"
|
|
|
|
#include "surface.h"
|
|
|
|
|
2010-11-10 19:25:05 +02:00
|
|
|
#define MAX_HOOKS 16
|
2010-10-24 09:48:43 +03:00
|
|
|
|
2010-11-10 19:25:05 +02:00
|
|
|
BOOL mouse_active = FALSE;
|
2018-03-09 13:50:56 +01:00
|
|
|
int yAdjust = 0;
|
2010-11-10 19:25:05 +02:00
|
|
|
|
|
|
|
BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint)
|
|
|
|
{
|
2018-03-23 03:21:16 +01:00
|
|
|
POINT pt, realpt;
|
2018-03-11 21:23:22 +01:00
|
|
|
|
|
|
|
if (!GetCursorPos(&pt))
|
|
|
|
return FALSE;
|
|
|
|
|
2018-03-23 03:21:16 +01:00
|
|
|
realpt.x = pt.x;
|
|
|
|
realpt.y = pt.y;
|
|
|
|
|
2018-03-11 21:23:22 +01:00
|
|
|
if(ddraw->locked && (!ddraw->windowed || ScreenToClient(ddraw->hWnd, &pt)))
|
2011-09-11 19:09:15 +03:00
|
|
|
{
|
2018-06-02 12:59:54 +02:00
|
|
|
//fallback solution for possible ClipCursor failure
|
|
|
|
int diffx = 0, diffy = 0;
|
2018-06-02 13:21:00 +02:00
|
|
|
int maxWidth = ddraw->adjmouse ? ddraw->render.viewport.width : ddraw->width;
|
|
|
|
int maxHeight = ddraw->adjmouse ? ddraw->render.viewport.height : ddraw->height;
|
2018-06-02 12:59:54 +02:00
|
|
|
|
|
|
|
if (pt.x < 0)
|
|
|
|
{
|
2018-06-02 13:21:00 +02:00
|
|
|
diffx = pt.x;
|
2018-06-02 12:59:54 +02:00
|
|
|
pt.x = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pt.y < 0)
|
|
|
|
{
|
2018-06-02 13:21:00 +02:00
|
|
|
diffy = pt.y;
|
2018-06-02 12:59:54 +02:00
|
|
|
pt.y = 0;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:21:00 +02:00
|
|
|
if (pt.x > maxWidth)
|
|
|
|
{
|
|
|
|
diffx = pt.x - maxWidth;
|
|
|
|
pt.x = maxWidth;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pt.y > maxHeight)
|
|
|
|
{
|
|
|
|
diffy = pt.y - maxHeight;
|
|
|
|
pt.y = maxHeight;
|
|
|
|
}
|
|
|
|
|
2018-06-02 12:59:54 +02:00
|
|
|
if (diffx || diffy)
|
2018-06-02 13:21:00 +02:00
|
|
|
SetCursorPos(realpt.x - diffx, realpt.y - diffy);
|
2018-06-02 12:59:54 +02:00
|
|
|
|
|
|
|
|
2018-03-11 21:23:22 +01:00
|
|
|
if(ddraw->adjmouse)
|
|
|
|
{
|
2018-03-15 20:49:27 +01:00
|
|
|
ddraw->cursor.x = pt.x * ((float)ddraw->width / ddraw->render.viewport.width);
|
|
|
|
ddraw->cursor.y = pt.y * ((float)ddraw->height / ddraw->render.viewport.height);
|
2018-03-11 21:23:22 +01:00
|
|
|
}
|
|
|
|
else
|
2018-03-09 18:20:09 +01:00
|
|
|
{
|
|
|
|
ddraw->cursor.x = pt.x;
|
|
|
|
ddraw->cursor.y = pt.y;
|
|
|
|
}
|
2018-06-02 12:59:54 +02:00
|
|
|
|
2018-03-23 23:10:49 +01:00
|
|
|
if (ddraw->vhack && (ddraw->iscnc1 || ddraw->isredalert) && ddraw->incutscene)
|
2018-03-23 03:21:16 +01:00
|
|
|
{
|
2018-06-02 12:59:54 +02:00
|
|
|
diffx = 0;
|
|
|
|
diffy = 0;
|
2018-03-23 03:21:16 +01:00
|
|
|
|
|
|
|
if (ddraw->cursor.x > CUTSCENE_WIDTH)
|
|
|
|
{
|
|
|
|
diffx = ddraw->cursor.x - CUTSCENE_WIDTH;
|
|
|
|
ddraw->cursor.x = CUTSCENE_WIDTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ddraw->cursor.y > CUTSCENE_HEIGHT)
|
|
|
|
{
|
|
|
|
diffy = ddraw->cursor.y - CUTSCENE_HEIGHT;
|
|
|
|
ddraw->cursor.y = CUTSCENE_HEIGHT;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (diffx || diffy)
|
|
|
|
SetCursorPos(realpt.x - diffx, realpt.y - diffy);
|
|
|
|
}
|
2018-03-11 21:23:22 +01:00
|
|
|
}
|
2018-03-15 20:49:27 +01:00
|
|
|
|
2018-03-11 21:23:22 +01:00
|
|
|
if (lpPoint)
|
|
|
|
{
|
2018-03-19 01:11:54 +01:00
|
|
|
if (ddraw->fakecursorpos)
|
2018-03-19 00:32:13 +01:00
|
|
|
{
|
2018-03-19 01:11:54 +01:00
|
|
|
lpPoint->x = (int)ddraw->cursor.x;
|
|
|
|
lpPoint->y = (int)ddraw->cursor.y;
|
2018-03-19 00:32:13 +01:00
|
|
|
}
|
2018-03-19 01:11:54 +01:00
|
|
|
else if (ddraw->locked || ddraw->devmode)
|
|
|
|
{
|
2018-03-23 03:21:16 +01:00
|
|
|
lpPoint->x = realpt.x;
|
|
|
|
lpPoint->y = realpt.y;
|
2018-03-19 01:11:54 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
return FALSE;
|
2011-09-11 19:09:15 +03:00
|
|
|
}
|
2018-03-14 13:15:34 +01:00
|
|
|
|
2010-11-10 19:25:05 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI fake_ClipCursor(const RECT *lpRect)
|
|
|
|
{
|
2010-11-26 21:44:31 +02:00
|
|
|
if(lpRect)
|
|
|
|
{
|
|
|
|
/* hack for 640x480 mode */
|
2018-03-09 13:50:56 +01:00
|
|
|
if (lpRect->bottom == 400 && ddraw->height == 480)
|
|
|
|
yAdjust = 40;
|
2010-11-26 21:44:31 +02:00
|
|
|
}
|
2010-11-10 19:25:05 +02:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int WINAPI fake_ShowCursor(BOOL bShow)
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
HCURSOR WINAPI fake_SetCursor(HCURSOR hCursor)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-08-06 09:33:27 +02:00
|
|
|
void HookIAT(HMODULE hMod, char *moduleName, char *functionName, PROC newFunction)
|
2010-10-24 09:48:43 +03:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
if (!hMod || hMod == INVALID_HANDLE_VALUE || !newFunction)
|
|
|
|
return;
|
2010-10-24 09:48:43 +03:00
|
|
|
|
2018-08-06 09:33:27 +02:00
|
|
|
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
|
|
|
|
if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)pDosHeader + (DWORD)pDosHeader->e_lfanew);
|
|
|
|
if (pNTHeaders->Signature != IMAGE_NT_SIGNATURE)
|
|
|
|
return;
|
|
|
|
|
|
|
|
PIMAGE_IMPORT_DESCRIPTOR pImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)((DWORD)pDosHeader +
|
|
|
|
(DWORD)(pNTHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress));
|
|
|
|
|
|
|
|
if (pImportDescriptor == (PIMAGE_IMPORT_DESCRIPTOR)pNTHeaders)
|
|
|
|
return;
|
|
|
|
|
|
|
|
while (pImportDescriptor->FirstThunk)
|
2010-11-10 19:25:05 +02:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
char *impModuleName = (char *)((DWORD)pDosHeader + (DWORD)(pImportDescriptor->Name));
|
|
|
|
|
|
|
|
if (_stricmp(impModuleName, moduleName) == 0)
|
2010-11-10 19:25:05 +02:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
PIMAGE_THUNK_DATA pFirstThunk =
|
|
|
|
(PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->FirstThunk);
|
|
|
|
|
|
|
|
PIMAGE_THUNK_DATA pOrigFirstThunk =
|
|
|
|
(PIMAGE_THUNK_DATA)((DWORD)pDosHeader + (DWORD)pImportDescriptor->OriginalFirstThunk);
|
|
|
|
|
|
|
|
while (pFirstThunk->u1.Function && pOrigFirstThunk->u1.AddressOfData)
|
2010-11-10 19:25:05 +02:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
PIMAGE_IMPORT_BY_NAME pImport =
|
|
|
|
(PIMAGE_IMPORT_BY_NAME)((DWORD)pDosHeader + pOrigFirstThunk->u1.AddressOfData);
|
2010-11-10 19:25:05 +02:00
|
|
|
|
2018-08-06 09:33:27 +02:00
|
|
|
if ((pOrigFirstThunk->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0 &&
|
|
|
|
_stricmp((const char *)pImport->Name, functionName) == 0)
|
2010-11-10 19:25:05 +02:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
DWORD oldProtect;
|
|
|
|
MEMORY_BASIC_INFORMATION mbi;
|
|
|
|
|
|
|
|
if (VirtualQuery(&pFirstThunk->u1.Function, &mbi, sizeof(MEMORY_BASIC_INFORMATION)))
|
2010-11-10 19:25:05 +02:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
if (VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_READWRITE, &oldProtect))
|
|
|
|
{
|
|
|
|
pFirstThunk->u1.Function = (DWORD)newFunction;
|
|
|
|
VirtualProtect(mbi.BaseAddress, mbi.RegionSize, oldProtect, &oldProtect);
|
|
|
|
}
|
2010-11-10 19:25:05 +02:00
|
|
|
}
|
2018-08-06 09:33:27 +02:00
|
|
|
|
|
|
|
break;
|
2010-11-10 19:25:05 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 09:33:27 +02:00
|
|
|
pFirstThunk++;
|
|
|
|
pOrigFirstThunk++;
|
2010-11-10 19:25:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-06 09:33:27 +02:00
|
|
|
pImportDescriptor++;
|
|
|
|
}
|
2010-11-10 19:25:05 +02:00
|
|
|
}
|
2010-10-24 19:47:51 +03:00
|
|
|
|
2010-10-24 01:02:08 +03:00
|
|
|
void mouse_lock()
|
|
|
|
{
|
2010-11-17 18:57:22 +02:00
|
|
|
RECT rc;
|
|
|
|
|
2012-08-09 14:35:28 +03:00
|
|
|
if (ddraw->devmode)
|
|
|
|
{
|
|
|
|
while(ShowCursor(FALSE) > 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mouse_active && !ddraw->locked)
|
2010-10-24 01:02:08 +03:00
|
|
|
{
|
2018-03-09 13:50:56 +01:00
|
|
|
// Get the window client area.
|
|
|
|
GetClientRect(ddraw->hWnd, &rc);
|
|
|
|
|
2018-03-15 20:49:27 +01:00
|
|
|
if(ddraw->adjmouse)
|
|
|
|
{
|
|
|
|
rc.right = ddraw->render.viewport.width;
|
|
|
|
rc.bottom = ddraw->render.viewport.height;
|
|
|
|
}
|
|
|
|
else
|
2018-03-11 21:23:22 +01:00
|
|
|
{
|
2018-03-15 20:49:27 +01:00
|
|
|
rc.right = ddraw->width;
|
|
|
|
rc.bottom = ddraw->height;
|
2018-03-11 21:23:22 +01:00
|
|
|
}
|
2018-03-09 13:50:56 +01:00
|
|
|
|
|
|
|
// Convert the client area to screen coordinates.
|
|
|
|
POINT pt = { rc.left, rc.top };
|
|
|
|
POINT pt2 = { rc.right, rc.bottom };
|
|
|
|
ClientToScreen(ddraw->hWnd, &pt);
|
|
|
|
ClientToScreen(ddraw->hWnd, &pt2);
|
|
|
|
|
|
|
|
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
|
2010-11-17 18:57:22 +02:00
|
|
|
|
2018-03-15 20:49:27 +01:00
|
|
|
rc.bottom -= (yAdjust * 2) * ((float)ddraw->render.viewport.height / ddraw->height);
|
2018-03-11 21:23:22 +01:00
|
|
|
|
|
|
|
if(ddraw->adjmouse)
|
|
|
|
{
|
|
|
|
SetCursorPos(
|
2018-03-15 20:49:27 +01:00
|
|
|
rc.left + (ddraw->cursor.x * ((float)ddraw->render.viewport.width / ddraw->width)),
|
|
|
|
rc.top + ((ddraw->cursor.y - yAdjust) * ((float)ddraw->render.viewport.height / ddraw->height)));
|
2018-03-11 21:23:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
SetCursorPos(rc.left + ddraw->cursor.x, rc.top + ddraw->cursor.y - yAdjust);
|
|
|
|
}
|
2010-11-17 18:57:22 +02:00
|
|
|
|
|
|
|
SetCapture(ddraw->hWnd);
|
|
|
|
ClipCursor(&rc);
|
|
|
|
|
2010-10-24 01:02:08 +03:00
|
|
|
while(ShowCursor(FALSE) > 0);
|
2010-11-17 18:57:22 +02:00
|
|
|
ddraw->locked = TRUE;
|
2010-10-24 01:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void mouse_unlock()
|
|
|
|
{
|
2011-09-11 16:10:43 +03:00
|
|
|
RECT rc;
|
|
|
|
|
2012-08-09 14:35:28 +03:00
|
|
|
if (ddraw->devmode)
|
|
|
|
{
|
|
|
|
while(ShowCursor(TRUE) < 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-24 19:47:51 +03:00
|
|
|
if(!mouse_active)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-10-24 01:02:08 +03:00
|
|
|
if(ddraw->locked)
|
|
|
|
{
|
2011-07-08 18:22:43 +03:00
|
|
|
ddraw->locked = FALSE;
|
|
|
|
|
2018-03-09 13:50:56 +01:00
|
|
|
// Get the window client area.
|
|
|
|
GetClientRect(ddraw->hWnd, &rc);
|
|
|
|
|
|
|
|
// Convert the client area to screen coordinates.
|
|
|
|
POINT pt = { rc.left, rc.top };
|
|
|
|
POINT pt2 = { rc.right, rc.bottom };
|
|
|
|
ClientToScreen(ddraw->hWnd, &pt);
|
|
|
|
ClientToScreen(ddraw->hWnd, &pt2);
|
|
|
|
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);
|
|
|
|
|
2010-11-08 19:23:39 +02:00
|
|
|
while(ShowCursor(TRUE) < 0);
|
|
|
|
SetCursor(LoadCursor(NULL, IDC_ARROW));
|
2010-11-17 18:57:22 +02:00
|
|
|
|
|
|
|
ClipCursor(NULL);
|
|
|
|
ReleaseCapture();
|
2018-03-09 13:50:56 +01:00
|
|
|
|
|
|
|
SetCursorPos(
|
2018-03-15 20:49:27 +01:00
|
|
|
rc.left + ddraw->render.viewport.x +
|
|
|
|
(ddraw->cursor.x * ((float)ddraw->render.viewport.width / ddraw->width)),
|
|
|
|
rc.top + ddraw->render.viewport.y +
|
|
|
|
((ddraw->cursor.y + yAdjust) * ((float)ddraw->render.viewport.height / ddraw->height)));
|
2010-11-17 18:57:22 +02:00
|
|
|
|
2010-10-24 01:02:08 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-20 01:26:53 +01:00
|
|
|
void mouse_init()
|
2010-10-24 01:02:08 +03:00
|
|
|
{
|
2018-08-06 09:33:27 +02:00
|
|
|
HookIAT(GetModuleHandle(NULL), "user32.dll", "GetCursorPos", (PROC)fake_GetCursorPos);
|
|
|
|
HookIAT(GetModuleHandle(NULL), "user32.dll", "ClipCursor", (PROC)fake_ClipCursor);
|
|
|
|
HookIAT(GetModuleHandle(NULL), "user32.dll", "ShowCursor", (PROC)fake_ShowCursor);
|
|
|
|
HookIAT(GetModuleHandle(NULL), "user32.dll", "SetCursor", (PROC)fake_SetCursor);
|
2018-03-09 13:50:56 +01:00
|
|
|
mouse_active = TRUE;
|
2010-10-24 01:02:08 +03:00
|
|
|
}
|