From 1ea29b0e62029b7e0c936b7fbcafc99c61bb2ecc Mon Sep 17 00:00:00 2001 From: "Jake.Stine" Date: Mon, 30 Nov 2009 20:52:09 +0000 Subject: [PATCH] Lilypad: Implemented full support for child-window GS viewports (fixes windows messaging being broken from the prev rev). DevNotes: The main change here was to turn WndProcEater into a class and create multiple instances of it, so that it could manage the WndProcs for multiple windows concurrently. The "frame" (top-level window) gets a WndProc that sets title and handles screensaver/alt-enter hacks. The "viewport" (provided by PCSX2) gets the usual keyboard input handler WndProc. Config buttons also have their own WndProc that avoid fuzzy logic conflicts with the other two. git-svn-id: http://pcsx2.googlecode.com/svn/trunk@2277 96395faa-99c1-11dd-bbfe-3dabce05a288 --- plugins/LilyPad/Config.cpp | 24 ++++-- plugins/LilyPad/Diagnostics.cpp | 4 +- plugins/LilyPad/InputManager.cpp | 2 + plugins/LilyPad/InputManager.h | 13 +++- plugins/LilyPad/KeyboardHook.cpp | 17 +++-- plugins/LilyPad/LilyPad.cpp | 108 +++++++++++++++++---------- plugins/LilyPad/RawInput.cpp | 39 +++++----- plugins/LilyPad/WindowsMessaging.cpp | 31 +++----- plugins/LilyPad/WndProcEater.cpp | 102 ++++++++++++++----------- plugins/LilyPad/WndProcEater.h | 32 +++++++- 10 files changed, 230 insertions(+), 142 deletions(-) diff --git a/plugins/LilyPad/Config.cpp b/plugins/LilyPad/Config.cpp index eb49e8e3ce..e18eb7d55d 100644 --- a/plugins/LilyPad/Config.cpp +++ b/plugins/LilyPad/Config.cpp @@ -1250,7 +1250,7 @@ void EndBinding(HWND hWnd) { dm->ReleaseInput(); ClearKeyQueue(); - ReleaseEatenProc(); + hWndButtonProc.Release(); // Safest to do this last. if (needRefreshDevices) { @@ -1300,6 +1300,9 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l } break; case WM_TIMER: + // ignore generic timer callback and handle the hwnd-specific one which comes later + if(hWnd == 0) return 0; + if (!selected || selected == 0xFF) { // !selected is mostly for device added/removed when binding. selected = 0xFF; @@ -1308,7 +1311,15 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l else { unsigned int uid; int value; - InitInfo info = {selected==0x7F, 1, hWndProp, hWnd, GetDlgItem(hWnd, selected)}; + + // The old code re-bound our button hWndProcEater to GetDlgItem(hWnd, selected). But at best hWnd + // was null (WM_TIMER is passed twice, once with a null parameter, and a second time that is hWnd + // specific), and at worst 'selected' is a post-processed code "based" on cmd, so GetDlgItem + // *always* returned NULL anyway. This resulted in hWndButton being null, which meant Device code + // used hWnd instead. This may have caused odd behavior since the callbacks were still all eaten + // by the initial GetDlgItem(hWnd, cmd) selection made when the timer was initialized. + + InitInfo info = {selected==0x7F, 1, hWndProp, &hWndButtonProc}; Device *dev = dm->GetActiveDevice(&info, &uid, &index, &value); if (dev) { int command = selected; @@ -1517,8 +1528,8 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l if (selIndex >= 0) { if (GetBinding(port, slot, selIndex, dev, b, ffb)) { selected = 0xFF; - InitInfo info = {0, 1, hWndProp, hWnd, GetDlgItem(hWnd, cmd)}; - EatWndProc(info.hWndButton, DoNothingWndProc, 0); + hWndButtonProc.SetWndHandle(GetDlgItem(hWnd, cmd)); + InitInfo info = {0, 1, hWndProp, &hWndButtonProc}; for (int i=0; inumDevices; i++) { if (dm->devices[i] != dev) { dm->DisableDevice(i); @@ -1554,8 +1565,9 @@ INT_PTR CALLBACK DialogProc(HWND hWnd, unsigned int msg, WPARAM wParam, LPARAM l } } - InitInfo info = {selected==0x7F, 1, hWndProp, hWnd, GetDlgItem(hWnd, cmd)}; - EatWndProc(info.hWndButton, DoNothingWndProc, 0); + hWndButtonProc.SetWndHandle(GetDlgItem(hWnd, cmd)); + hWndButtonProc.Eat(DoNothingWndProc, 0); + InitInfo info = {selected==0x7F, 1, hWndProp, &hWndButtonProc}; int w = timeGetTime(); dm->Update(&info); dm->PostRead(); diff --git a/plugins/LilyPad/Diagnostics.cpp b/plugins/LilyPad/Diagnostics.cpp index bbbdf087be..2d1fe3a73c 100644 --- a/plugins/LilyPad/Diagnostics.cpp +++ b/plugins/LilyPad/Diagnostics.cpp @@ -4,6 +4,7 @@ #include "resource.h" #include "InputManager.h" +#include "WndProcEater.h" Device *dev; @@ -39,7 +40,8 @@ INT_PTR CALLBACK DiagDialog(HWND hWnd, unsigned int uMsg, WPARAM wParam, LPARAM //break; case WM_TIMER: { - InitInfo info = {0, 1, hWnd, hWnd, hWndList}; + hWndButtonProc.SetWndHandle(hWndList); + InitInfo info = {0, 1, hWnd, &hWndButtonProc}; dm->Update(&info); LVITEMW item; item.mask = LVIF_TEXT; diff --git a/plugins/LilyPad/InputManager.cpp b/plugins/LilyPad/InputManager.cpp index 2055d30ec4..9b2d70db2c 100644 --- a/plugins/LilyPad/InputManager.cpp +++ b/plugins/LilyPad/InputManager.cpp @@ -37,6 +37,8 @@ Device::Device(DeviceAPI api, DeviceType d, const wchar_t *displayName, const wc attached = 1; enabled = 0; + hWndProc = 0; + virtualControls = 0; numVirtualControls = 0; virtualControlState = 0; diff --git a/plugins/LilyPad/InputManager.h b/plugins/LilyPad/InputManager.h index bd53c5b004..3507d4d34f 100644 --- a/plugins/LilyPad/InputManager.h +++ b/plugins/LilyPad/InputManager.h @@ -171,6 +171,8 @@ struct PadBindings { int numFFBindings; }; +class WndProcEater; + struct InitInfo { // 1 when binding key to ignore. int bindingIgnore; @@ -178,9 +180,11 @@ struct InitInfo { int binding; HWND hWndTop; - HWND hWnd; + // For config screen, need to eat button's message handling. - HWND hWndButton; + //HWND hWndButton; + + WndProcEater* hWndProc; }; @@ -194,6 +198,11 @@ public: char attached; // Based on input modes. char enabled; + + // Not all devices need to subclass the windproc, but most do so might as well + // put it here... --air + WndProcEater* hWndProc; + union { // Allows for one loop to compare all 3 in order. wchar_t *IDs[3]; diff --git a/plugins/LilyPad/KeyboardHook.cpp b/plugins/LilyPad/KeyboardHook.cpp index 4e17d1880c..3bd0a2e76f 100644 --- a/plugins/LilyPad/KeyboardHook.cpp +++ b/plugins/LilyPad/KeyboardHook.cpp @@ -40,10 +40,12 @@ public: int Activate(InitInfo *initInfo) { if (ikhd) ikhd->Deactivate(); binding = initInfo->bindingIgnore; - if (initInfo->hWndButton) - EatWndProc(initInfo->hWndButton, StartHooksWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); - else - EatWndProc(initInfo->hWnd, StartHooksWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); + hWndProc = initInfo->hWndProc; + + return 0; + printf( "(Lilypad) StartHook\n" ); + hWndProc->Eat(StartHooksWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); + InitState(); ikhd = this; active = 1; @@ -51,6 +53,8 @@ public: } void Deactivate() { + printf( "(Lilypad) KillHook\n" ); + FreeState(); if (active) { if (hHook) { @@ -74,9 +78,11 @@ ExtraWndProcResult StartHooksWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM static int counter = 0; if (ikhd && !ikhd->hHook && ikhd->active) { counter = 0; - ikhd->hHook = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreKeyboardHook, hInst, 0); + printf( "(Lilypad) SetHook\n" ); + ikhd->hHook = SetWindowsHookEx(WH_KEYBOARD_LL, IgnoreKeyboardHook, hInst, 0);//GetCurrentThreadId()); if (ikhd->hHook == 0) ikhd->Deactivate(); } + printf( "(Lilypad) HookThinking!\n" ); counter ++; if (counter % 1000 == 0) return CONTINUE_BLISSFULLY_AND_RELEASE_PROC; @@ -87,6 +93,7 @@ ExtraWndProcResult StartHooksWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM LRESULT CALLBACK IgnoreKeyboardHook(int code, WPARAM wParam, LPARAM lParam) { HHOOK hHook = 0; if (ikhd) { + printf( "(Lilypad) Hooked!!\n" ); hHook = ikhd->hHook; if (hHook) { if (code == HC_ACTION) { diff --git a/plugins/LilyPad/LilyPad.cpp b/plugins/LilyPad/LilyPad.cpp index 5db7dea66b..80d9169a0c 100644 --- a/plugins/LilyPad/LilyPad.cpp +++ b/plugins/LilyPad/LilyPad.cpp @@ -24,6 +24,14 @@ HINSTANCE hInst; HWND hWnd; +HWND hWndTop; + +WndProcEater hWndGSProc; +WndProcEater hWndTopProc; + +// ButtonProc is used mostly by the Config panel for eating the procedures of the +// button with keyboard focus. +WndProcEater hWndButtonProc; // Keeps the various sources for Update polling (PADpoll, PADupdate, etc) from wreaking // havoc on each other... @@ -447,7 +455,7 @@ void Update(unsigned int port, unsigned int slot) { s[i&1][i>>1] = pads[i&1][i>>1].lockedSum; } InitInfo info = { - 0, 0, hWnd, hWnd, 0 + 0, 0, hWndTop, &hWndGSProc }; dm->Update(&info); @@ -801,9 +809,40 @@ static const u8 queryMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const u8 setNativeMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A}; -// Implements a couple of the hacks, also responsible for monitoring device addition/removal and focus -// changes. -ExtraWndProcResult HackWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output) { +// Implements a couple of the hacks that affect whatever top-level window +// the GS viewport belongs to (title, screensaver) +ExtraWndProcResult TitleHackWndProc(HWND hWndTop, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output) { + switch (uMsg) { + case WM_SETTEXT: + if (config.saveStateTitle) { + wchar_t text[200]; + int len; + if (IsWindowUnicode(hWndTop)) { + len = wcslen((wchar_t*) lParam); + if (len < sizeof(text)/sizeof(wchar_t)) wcscpy(text, (wchar_t*) lParam); + } + else { + len = MultiByteToWideChar(CP_ACP, 0, (char*) lParam, -1, text, sizeof(text)/sizeof(wchar_t)); + } + if (len > 0 && len < 150 && !wcsstr(text, L" | State ")) { + wsprintfW(text+len, L" | State %i", saveStateIndex); + SetWindowText(hWndTop, text); + return NO_WND_PROC; + } + } + break; + case WM_SYSCOMMAND: + if ((wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) && config.disableScreenSaver) + return NO_WND_PROC; + break; + default: + break; + } + return CONTINUE_BLISSFULLY; +} + +// responsible for monitoring device addition/removal, focus changes, and viewport closures. +ExtraWndProcResult StatusWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output) { switch (uMsg) { case WMA_FORCE_UPDATE: if (wParam == FORCE_UPDATE_WPARAM && lParam == FORCE_UPDATE_LPARAM) { @@ -813,24 +852,6 @@ ExtraWndProcResult HackWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara } return NO_WND_PROC; } - case WM_SETTEXT: - if (config.saveStateTitle) { - wchar_t text[200]; - int len; - if (IsWindowUnicode(hWnd)) { - len = wcslen((wchar_t*) lParam); - if (len < sizeof(text)/sizeof(wchar_t)) wcscpy(text, (wchar_t*) lParam); - } - else { - len = MultiByteToWideChar(CP_ACP, 0, (char*) lParam, -1, text, sizeof(text)/sizeof(wchar_t)); - } - if (len > 0 && len < 150 && !wcsstr(text, L" | State ")) { - wsprintfW(text+len, L" | State %i", saveStateIndex); - SetWindowText(hWnd, text); - return NO_WND_PROC; - } - } - break; case WM_DEVICECHANGE: if (wParam == DBT_DEVNODES_CHANGED) { UpdateEnabledDevices(1); @@ -855,10 +876,6 @@ ExtraWndProcResult HackWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara return NO_WND_PROC; } break; - case WM_SYSCOMMAND: - if ((wParam == SC_SCREENSAVE || wParam == SC_MONITORPOWER) && config.disableScreenSaver) - return NO_WND_PROC; - break; case WM_DESTROY: QueueKeyEvent(VK_ESCAPE, KEYPRESS); break; @@ -897,12 +914,12 @@ void CALLBACK PADconfigure() { DWORD WINAPI RenameWindowThreadProc(void *lpParameter) { wchar_t newTitle[200]; - if (hWnd) { - int len = GetWindowTextW(hWnd, newTitle, 200); + if (hWndTop) { + int len = GetWindowTextW(hWndTop, newTitle, 200); if (len > 0 && len < 199) { wchar_t *end; if (end = wcsstr(newTitle, L" | State ")) *end = 0; - SetWindowTextW(hWnd, newTitle); + SetWindowTextW(hWndTop, newTitle); } } return 0; @@ -940,26 +957,33 @@ s32 CALLBACK PADopen(void *pDsp) { "Non-LilyPad Error", MB_OK | MB_ICONERROR); return -1; } - while (GetWindowLong (hWnd, GWL_STYLE) & WS_CHILD) - hWnd = GetParent (hWnd); - // Implements most hacks, as well as enabling/disabling mouse - // capture when focus changes. - updateQueued = 0; - if (!EatWndProc(hWnd, HackWndProc, 0)) { + hWndTop = hWnd; + while (GetWindowLong (hWndTop, GWL_STYLE) & WS_CHILD) + hWndTop = GetParent (hWndTop); + + if (!hWndGSProc.SetWndHandle(hWnd) || !hWndTopProc.SetWndHandle(hWndTop)) { openCount = 0; return -1; } + + // Implements most hacks, as well as enabling/disabling mouse + // capture when focus changes. + updateQueued = 0; + hWndGSProc.Eat(StatusWndProc, 0); + + hWndTopProc.Eat(TitleHackWndProc, 0); + if (config.forceHide) { - EatWndProc(hWnd, HideCursorProc, 0); + hWndGSProc.Eat(HideCursorProc, 0); } SaveStateChanged(); - windowThreadId = GetWindowThreadProcessId(hWnd, 0); + windowThreadId = GetWindowThreadProcessId(hWndTop, 0); } if (restoreFullScreen) { - if (!IsWindowMaximized(hWnd)) { - HANDLE hThread = CreateThread(0, 0, MaximizeWindowThreadProc, hWnd, 0, 0); + if (!IsWindowMaximized(hWndTop)) { + HANDLE hThread = CreateThread(0, 0, MaximizeWindowThreadProc, hWndTop, 0, 0); if (hThread) CloseHandle(hThread); } restoreFullScreen = 0; @@ -989,9 +1013,11 @@ void CALLBACK PADclose() { if (openCount && !--openCount) { DEBUG_TEXT_OUT("LilyPad closed\n\n"); updateQueued = 0; - ReleaseEatenProc(); + hWndGSProc.Release(); + hWndTopProc.Release(); dm->ReleaseInput(); hWnd = 0; + hWndTop = 0; ClearKeyQueue(); } } @@ -1327,7 +1353,7 @@ keyEvent* CALLBACK PADkeyEvent() { if (!GetQueuedKeyEvent(&ev)) return 0; if ((ev.key == VK_ESCAPE || (int)ev.key == -2) && ev.evt == KEYPRESS && config.escapeFullscreenHack) { static int t; - if ((int)ev.key != -2 && IsWindowMaximized(hWnd)) { + if ((int)ev.key != -2 && IsWindowMaximized(hWndTop)) { t = timeGetTime(); QueueKeyEvent(-2, KEYPRESS); HANDLE hThread = CreateThread(0, 0, MaximizeWindowThreadProc, 0, 0, 0); diff --git a/plugins/LilyPad/RawInput.cpp b/plugins/LilyPad/RawInput.cpp index 23bfc88b59..8df6db392e 100644 --- a/plugins/LilyPad/RawInput.cpp +++ b/plugins/LilyPad/RawInput.cpp @@ -69,24 +69,22 @@ static int rawMouseActivatedCount = 0; class RawInputKeyboard : public WindowsKeyboard { public: HANDLE hDevice; - + RawInputKeyboard(HANDLE hDevice, wchar_t *name, wchar_t *instanceID=0) : WindowsKeyboard(RAW, name, instanceID) { this->hDevice = hDevice; } int Activate(InitInfo *initInfo) { Deactivate(); - HWND hWnd = initInfo->hWnd; - if (initInfo->hWndButton) { - hWnd = initInfo->hWndButton; - } + + hWndProc = initInfo->hWndProc; + active = 1; if (!rawKeyboardActivatedCount++) { - if (!rawMouseActivatedCount && !EatWndProc(hWnd, RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES)) { - Deactivate(); - return 0; - } - if (!GetRawKeyboards(hWnd)) { + if (!rawMouseActivatedCount) + hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); + + if (!GetRawKeyboards(hWndProc->hWndEaten)) { Deactivate(); return 0; } @@ -104,7 +102,7 @@ public: if (!rawKeyboardActivatedCount) { ReleaseRawKeyboards(); if (!rawMouseActivatedCount) - ReleaseExtraProc(RawInputWndProc); + hWndProc->ReleaseExtraProc(RawInputWndProc); } } } @@ -120,10 +118,8 @@ public: int Activate(InitInfo *initInfo) { Deactivate(); - HWND hWnd = initInfo->hWnd; - if (initInfo->hWndButton) { - hWnd = initInfo->hWndButton; - } + + hWndProc = initInfo->hWndProc; active = 1; @@ -131,12 +127,11 @@ public: // EatWndProc fail. In all other cases, no unmatched initialization/cleanup // lines. if (!rawMouseActivatedCount++) { - GetMouseCapture(hWnd); - if (!rawKeyboardActivatedCount && !EatWndProc(hWnd, RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES)) { - Deactivate(); - return 0; - } - if (!GetRawMice(hWnd)) { + GetMouseCapture(hWndProc->hWndEaten); + if (!rawKeyboardActivatedCount) + hWndProc->Eat(RawInputWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); + + if (!GetRawMice(hWndProc->hWndEaten)) { Deactivate(); return 0; } @@ -155,7 +150,7 @@ public: ReleaseRawMice(); ReleaseMouseCapture(); if (!rawKeyboardActivatedCount) { - ReleaseExtraProc(RawInputWndProc); + hWndProc->ReleaseExtraProc(RawInputWndProc); } } } diff --git a/plugins/LilyPad/WindowsMessaging.cpp b/plugins/LilyPad/WindowsMessaging.cpp index c827899c61..43dffec550 100644 --- a/plugins/LilyPad/WindowsMessaging.cpp +++ b/plugins/LilyPad/WindowsMessaging.cpp @@ -25,14 +25,11 @@ public: // Redundant. Should match the next line. // Deactivate(); if (wmk) wmk->Deactivate(); - HWND hWnd = initInfo->hWnd; - if (initInfo->hWndButton) { - hWnd = initInfo->hWndButton; - } - if (!wmm && !EatWndProc(hWnd, WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES)) { - Deactivate(); - return 0; - } + + hWndProc = initInfo->hWndProc; + + if (!wmm) + hWndProc->Eat(WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); wmk = this; InitState(); @@ -44,7 +41,7 @@ public: void Deactivate() { if (active) { if (!wmm) - ReleaseExtraProc(WindowsMessagingWndProc); + hWndProc->ReleaseExtraProc(WindowsMessagingWndProc); wmk = 0; active = 0; FreeState(); @@ -67,16 +64,12 @@ public: // Redundant. Should match the next line. // Deactivate(); if (wmm) wmm->Deactivate(); - HWND hWnd = initInfo->hWnd; - if (initInfo->hWndButton) { - hWnd = initInfo->hWndButton; - } + hWndProc = initInfo->hWndProc; - if (!wmk && !EatWndProc(hWnd, WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES)) { - Deactivate(); - return 0; - } - GetMouseCapture(hWnd); + if (!wmk) + hWndProc->Eat(WindowsMessagingWndProc, EATPROC_NO_UPDATE_WHILE_UPDATING_DEVICES); + + GetMouseCapture(hWndProc->hWndEaten); active = 1; @@ -89,7 +82,7 @@ public: void Deactivate() { if (active) { if (!wmk) - ReleaseExtraProc(WindowsMessagingWndProc); + hWndProc->ReleaseExtraProc(WindowsMessagingWndProc); ReleaseMouseCapture(); wmm = 0; active = 0; diff --git a/plugins/LilyPad/WndProcEater.cpp b/plugins/LilyPad/WndProcEater.cpp index b9a018bc6d..370da80d45 100644 --- a/plugins/LilyPad/WndProcEater.cpp +++ b/plugins/LilyPad/WndProcEater.cpp @@ -1,24 +1,31 @@ #include "Global.h" #include "WndProcEater.h" -static HWND hWndEaten = 0; -static WNDPROC eatenWndProc = 0; +WndProcEater::WndProcEater() +{ + hWndEaten = 0; + eatenWndProc = 0; -struct ExtraWndProcInfo { - ExtraWndProc proc; - DWORD flags; -}; + extraProcs = 0; + numExtraProcs = 0; -static ExtraWndProcInfo* extraProcs = 0; -static int numExtraProcs = 0; + hMutex = CreateMutex(0, 0, L"LilyPad"); +} -void ReleaseExtraProc(ExtraWndProc proc) { +WndProcEater::~WndProcEater() throw() +{ + if (hMutex) { + ReleaseMutex(hMutex); + CloseHandle(hMutex); + } +} + +void WndProcEater::ReleaseExtraProc(ExtraWndProc proc) { // Probably isn't needed, but just in case... - // Creating and destroying the mutex adds some inefficiency, - // but this function is only called on emulation start and on focus/unfocus. - HANDLE hMutex = CreateMutexA(0, 0, "LilyPad"); if (hMutex) WaitForSingleObject(hMutex, 100); + //printf( "(Lilypad) Regurgitating! -> 0x%x\n", proc ); + for (int i=0; i_OverrideWndProc( hWnd, uMsg, wParam, lParam ); +} + +bool WndProcEater::SetWndHandle(HWND hWnd) +{ + if(hWnd == hWndEaten) return true; + + //printf( "(Lilypad) (Re)-Setting window handle! -> this=0x%08x, hWnd=0x%08x\n", this, hWnd ); + + Release(); + SetProp(hWnd, L"LilyHaxxor", (HANDLE)this); + + eatenWndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)OverrideWndProc); + hWndEaten = (eatenWndProc) ? hWnd : 0; + + return !!hWndEaten; +} + +void WndProcEater::Eat(ExtraWndProc proc, DWORD flags) { + + // check if Subclassing failed to init during SetWndHandle + if (!hWndEaten) return; -int EatWndProc(HWND hWnd, ExtraWndProc proc, DWORD flags) { // Probably isn't needed, but just in case... - // Creating and destroying the mutex adds some inefficiency, - // but this function is only called on emulation start and on focus/unfocus. - HANDLE hMutex = CreateMutexA(0, 0, "LilyPad"); if (hMutex) WaitForSingleObject(hMutex, 100); - if (hWnd != hWndEaten) { - ReleaseEatenProc(); - eatenWndProc = (WNDPROC) SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)OverrideWndProc); - // ??? - if (eatenWndProc) - hWndEaten = hWnd; - } - if (hWndEaten == hWnd) { - extraProcs = (ExtraWndProcInfo*) realloc(extraProcs, sizeof(ExtraWndProcInfo)*(numExtraProcs+1)); - extraProcs[numExtraProcs].proc = proc; - extraProcs[numExtraProcs].flags = flags; - numExtraProcs++; - } + //printf( "(Lilypad) EatingWndProc! -> 0x%x\n", proc ); - if (hMutex) { - ReleaseMutex(hMutex); - CloseHandle(hMutex); - } - - return hWndEaten == hWnd; + extraProcs = (ExtraWndProcInfo*) realloc(extraProcs, sizeof(ExtraWndProcInfo)*(numExtraProcs+1)); + extraProcs[numExtraProcs].proc = proc; + extraProcs[numExtraProcs].flags = flags; + numExtraProcs++; } diff --git a/plugins/LilyPad/WndProcEater.h b/plugins/LilyPad/WndProcEater.h index b6821a6324..03671308cd 100644 --- a/plugins/LilyPad/WndProcEater.h +++ b/plugins/LilyPad/WndProcEater.h @@ -11,8 +11,34 @@ enum ExtraWndProcResult { }; typedef ExtraWndProcResult (*ExtraWndProc)(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *out); -int EatWndProc(HWND hWnd, ExtraWndProc proc, DWORD flags); -void ReleaseExtraProc(ExtraWndProc proc); -void ReleaseEatenProc(); +struct ExtraWndProcInfo { + ExtraWndProc proc; + DWORD flags; +}; +class WndProcEater +{ +public: + HWND hWndEaten; + WNDPROC eatenWndProc; + ExtraWndProcInfo* extraProcs; + int numExtraProcs; + + HANDLE hMutex; + +public: + WndProcEater(); + virtual ~WndProcEater() throw(); + + bool SetWndHandle(HWND hWnd); + void Eat(ExtraWndProc proc, DWORD flags); + void ReleaseExtraProc(ExtraWndProc proc); + void Release(); + + LRESULT _OverrideWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; + +extern WndProcEater hWndGSProc; +extern WndProcEater hWndTopProc; +extern WndProcEater hWndButtonProc;