From 4e57e75652feea3bcef30c2e8ff1543d7b7d6d13 Mon Sep 17 00:00:00 2001 From: Toni Spets Date: Sun, 24 Oct 2010 01:02:08 +0300 Subject: [PATCH] First take at real windowed mode, includes a hack for CnC and RA mouse --- Makefile | 2 +- main.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++- main.h | 10 +++++ mouse.c | 76 ++++++++++++++++++++++++++++++++ surface.c | 10 ++--- surface.h | 2 + 6 files changed, 218 insertions(+), 8 deletions(-) create mode 100644 mouse.c diff --git a/Makefile b/Makefile index 05174b0..1699c5d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ all: - i586-mingw32msvc-gcc -Wall -Wl,--enable-stdcall-fixup -shared -s -o ddraw.dll main.c palette.c surface.c clipper.c ddraw.def -lgdi32 + i586-mingw32msvc-gcc -Wall -Wl,--enable-stdcall-fixup -shared -s -o ddraw.dll main.c mouse.c palette.c surface.c clipper.c ddraw.def -lgdi32 clean: rm -f ddraw.dll diff --git a/main.c b/main.c index 2265c64..3089079 100644 --- a/main.c +++ b/main.c @@ -23,6 +23,13 @@ #include "surface.h" #include "clipper.h" +/* from mouse.c */ +void mouse_init(HWND); +void mouse_lock(); +void mouse_unlock(); + +IDirectDrawImpl *ddraw = NULL; + HRESULT __stdcall ddraw_Compact(IDirectDrawImpl *This) { printf("DirectDraw::Compact(This=%p)\n", This); @@ -132,6 +139,92 @@ HRESULT __stdcall ddraw_RestoreDisplayMode(IDirectDrawImpl *This) return DD_OK; } +LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch(uMsg) + { + case WM_KEYDOWN: + if(wParam == VK_CONTROL) + { + ddraw->key_ctrl = TRUE; + } + if(wParam == VK_MENU) + { + ddraw->key_alt = TRUE; + } + if(ddraw->key_alt && ddraw->key_ctrl) + { + mouse_unlock(); + } + break; + case WM_KEYUP: + if(wParam == VK_CONTROL) + { + ddraw->key_ctrl = FALSE; + } + if(wParam == VK_MENU) + { + ddraw->key_alt = FALSE; + } + break; + case WM_LBUTTONDOWN: + if(!ddraw->locked) + { + mouse_lock(); + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + break; + case WM_MOUSEMOVE: + if(ddraw->locked) + { + ddraw->cursor.x = LOWORD(lParam); + ddraw->cursor.y = HIWORD(lParam); + } + break; + case WM_SETFOCUS: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + case WM_KILLFOCUS: + mouse_unlock(); + return DefWindowProc(hWnd, uMsg, wParam, lParam); + case WM_PAINT: + if(ddraw_primary) + { + SetEvent(ddraw_primary->flipEvent); + } + return DefWindowProc(hWnd, uMsg, wParam, lParam); + + case WM_MOVE: + ddraw->winpos.x = LOWORD(lParam); + ddraw->winpos.y = HIWORD(lParam); + if(ddraw->winpos.x < 0) + { + ddraw->winpos.x = 0; + } + if(ddraw->winpos.y < 0) + { + ddraw->winpos.y = 0; + } + + if(ddraw_primary) + { + SetEvent(ddraw_primary->flipEvent); + } + break; + + case WM_WINDOWPOSCHANGED: + GetClientRect(ddraw->hWnd, &ddraw->cursorclip); + + POINT pt = { ddraw->cursorclip.left, ddraw->cursorclip.top }; + POINT pt2 = { ddraw->cursorclip.right, ddraw->cursorclip.bottom }; + ClientToScreen(ddraw->hWnd, &pt); + ClientToScreen(ddraw->hWnd, &pt2); + SetRect(&ddraw->cursorclip, pt.x, pt.y, pt2.x, pt2.y); + break; + } + + return ddraw->WndProc(hWnd, uMsg, wParam, lParam); +} + HRESULT __stdcall ddraw_SetCooperativeLevel(IDirectDrawImpl *This, HWND hWnd, DWORD dwFlags) { printf("DirectDraw::SetCooperativeLevel(This=%p, hWnd=0x%08X, dwFlags=0x%08X)\n", This, (unsigned int)hWnd, (unsigned int)dwFlags); @@ -142,8 +235,13 @@ HRESULT __stdcall ddraw_SetCooperativeLevel(IDirectDrawImpl *This, HWND hWnd, DW return DDERR_INVALIDPARAMS; } + mouse_init(hWnd); + This->hWnd = hWnd; + This->WndProc = (LRESULT CALLBACK (*)(HWND, UINT, WPARAM, LPARAM))GetWindowLong(This->hWnd, GWL_WNDPROC); + SetWindowLong(This->hWnd, GWL_WNDPROC, (LONG)WndProc); + #ifndef USE_OPENGL if(IDirectDraw_SetCooperativeLevel(This->real_ddraw, hWnd, DDSCL_NORMAL) != DD_OK) { @@ -159,12 +257,30 @@ HRESULT __stdcall ddraw_SetDisplayMode(IDirectDrawImpl *This, DWORD width, DWORD { printf("DirectDraw::SetDisplayMode(This=%p, width=%d, height=%d, bpp=%d)\n", This, (unsigned int)width, (unsigned int)height, (unsigned int)bpp); + /* currently we only support 8 bit modes */ + if(bpp != 8) + { + return DDERR_INVALIDMODE; + } + This->width = width; This->height = height; This->bpp = bpp; + SetWindowLong(This->hWnd, GWL_STYLE, GetWindowLong(This->hWnd, GWL_STYLE) | WS_POPUPWINDOW | WS_CAPTION); MoveWindow(This->hWnd, 0, 0, This->width, This->height, TRUE); + RECT rcClient, rcWindow; + POINT ptDiff; + GetClientRect(This->hWnd, &rcClient); + GetWindowRect(This->hWnd, &rcWindow); + ptDiff.x = (rcWindow.right - rcWindow.left) - rcClient.right; + ptDiff.y = (rcWindow.bottom - rcWindow.top) - rcClient.bottom; + + MoveWindow(This->hWnd, rcWindow.left, rcWindow.top, This->width + ptDiff.x, This->height + ptDiff.y, TRUE); + + mouse_unlock(); + return DD_OK; } @@ -203,6 +319,7 @@ ULONG __stdcall ddraw_Release(IDirectDrawImpl *This) IDirectDraw_Release(This->real_ddraw); #endif free(This); + ddraw = NULL; return 0; } @@ -250,13 +367,18 @@ HRESULT WINAPI DirectDrawCreate(GUID FAR* lpGUID, LPDIRECTDRAW FAR* lplpDD, IUnk } #endif + if(ddraw) + { + return DDERR_DIRECTDRAWALREADYCREATED; + } + printf("DirectDrawCreate(lpGUID=%p, lplpDD=%p, pUnkOuter=%p)\n", lpGUID, lplpDD, pUnkOuter); - IDirectDrawImpl *This = (IDirectDrawImpl *)HeapAlloc(GetProcessHeap(), 0, sizeof(IDirectDrawImpl)); + IDirectDrawImpl *This = (IDirectDrawImpl *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IDirectDrawImpl)); This->lpVtbl = &iface; - This->hWnd = NULL; printf(" This = %p\n", This); *lplpDD = (LPDIRECTDRAW)This; + ddraw = This; #ifndef USE_OPENGL This->real_dll = LoadLibrary("system32\\ddraw.dll"); diff --git a/main.h b/main.h index 7ad1ab7..0c57b54 100644 --- a/main.h +++ b/main.h @@ -25,6 +25,8 @@ struct IDirectDrawImpl; struct IDirectDrawImplVtbl; +extern struct IDirectDrawImpl *ddraw; + typedef struct IDirectDrawImpl { struct IDirectDrawImplVtbl *lpVtbl; @@ -36,6 +38,14 @@ typedef struct IDirectDrawImpl DWORD bpp; HWND hWnd; + LRESULT CALLBACK (*WndProc)(HWND, UINT, WPARAM, LPARAM); + POINT winpos; + POINT cursor; + RECT cursorclip; + BOOL locked; + + BOOL key_ctrl; + BOOL key_alt; HMODULE real_dll; LPDIRECTDRAW real_ddraw; diff --git a/mouse.c b/mouse.c new file mode 100644 index 0000000..2f0508a --- /dev/null +++ b/mouse.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2010 Toni Spets + * + * 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 +#include +#include "main.h" +#include "surface.h" + +BOOL WINAPI fake_GetCursorPos(LPPOINT lpPoint) +{ + lpPoint->x = ddraw->cursor.x; + lpPoint->y = ddraw->cursor.y; + return TRUE; +} + +void mouse_lock() +{ + if(!ddraw->locked) + { + ddraw->locked = TRUE; + ClipCursor(&ddraw->cursorclip); + while(ShowCursor(FALSE) > 0); + SetEvent(ddraw_primary->flipEvent); + } +} + +void mouse_unlock() +{ + if(ddraw->locked) + { + ShowCursor(TRUE); + } + + ddraw->locked = FALSE; + ClipCursor(NULL); + ddraw->cursor.x = ddraw->width / 2; + ddraw->cursor.y = ddraw->height / 2; + + if(ddraw_primary) + { + SetEvent(ddraw_primary->flipEvent); + } +} + +void mouse_init(HWND hWnd) +{ + DWORD tmp; + HANDLE hProcess; + DWORD dwWritten; + + GetWindowThreadProcessId(hWnd, &tmp); + hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, tmp); + + tmp = (DWORD)fake_GetCursorPos; + + // Command & Conquer + //WriteProcessMemory(hProcess, (void *)0x005B0184, &tmp, 4, &dwWritten); + + // Red Alert + //WriteProcessMemory(hProcess, (void *)0x005E6848, &tmp, 4, &dwWritten); +} diff --git a/surface.c b/surface.c index 51e2490..a1df04a 100644 --- a/surface.c +++ b/surface.c @@ -25,6 +25,8 @@ DWORD WINAPI dd_Thread(IDirectDrawSurfaceImpl *This); void dump_ddsd(DWORD); void dump_ddscaps(DWORD); +IDirectDrawSurfaceImpl *ddraw_primary = NULL; + HRESULT __stdcall ddraw_surface_QueryInterface(IDirectDrawSurfaceImpl *This, REFIID riid, void **obj) { printf("DirectDrawSurface::QueryInterface(This=%p, riid=%08X, obj=%p)\n", This, (unsigned int)riid, obj); @@ -422,6 +424,8 @@ HRESULT __stdcall ddraw_CreateSurface(IDirectDrawImpl *This, LPDDSURFACEDESC lpD { if(lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) { + ddraw_primary = Surface; + Surface->width = This->width; Surface->height = This->height; Surface->hWnd = This->hWnd; @@ -532,7 +536,6 @@ DWORD WINAPI dd_Thread(IDirectDrawSurfaceImpl *This) LPDIRECTDRAWSURFACE primary; LPDIRECTDRAWCLIPPER clipper; DWORD width; - POINT pt; memset(&ddsd, 0, sizeof(DDSURFACEDESC)); ddsd.dwSize = sizeof(DDSURFACEDESC); @@ -560,9 +563,6 @@ DWORD WINAPI dd_Thread(IDirectDrawSurfaceImpl *This) if(!This->dRun) break; - pt.x = pt.y = 0; - //ClientToScreen(This->hWnd, &pt); - if(IDirectDrawSurface_Lock(primary, NULL, &ddsd, DDLOCK_WRITEONLY|DDLOCK_WAIT, NULL) != DD_OK) continue; @@ -571,7 +571,7 @@ DWORD WINAPI dd_Thread(IDirectDrawSurfaceImpl *This) { for(j=0; jwidth; j++) { - ((int *)ddsd.lpSurface)[(i+pt.y)*width+(j+pt.x)] = This->palette->data[((unsigned char *)This->surface)[i*This->lPitch + j*This->lXPitch]]; + ((int *)ddsd.lpSurface)[(i+This->parent->winpos.y)*width+(j+This->parent->winpos.x)] = This->palette->data[((unsigned char *)This->surface)[i*This->lPitch + j*This->lXPitch]]; } } diff --git a/surface.h b/surface.h index dc1c6be..2eea9b4 100644 --- a/surface.h +++ b/surface.h @@ -26,6 +26,8 @@ HRESULT __stdcall ddraw_CreateSurface(IDirectDrawImpl *This, LPDDSURFACEDESC DDS struct IDirectDrawSurfaceImpl; struct IDirectDrawSurfaceImplVtbl; +extern struct IDirectDrawSurfaceImpl *ddraw_primary; + typedef struct IDirectDrawSurfaceImpl { struct IDirectDrawSurfaceImplVtbl *lpVtbl;