@@ -37,7 +37,6 @@ namespace WndProc
3737 LRESULT CallWndProc (WNDPROC lpPrevWndFunc, HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
3838 LRESULT DefWndProc (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
3939 bool IsExecutableAddress (void * address);
40- inline bool CheckFocusLoss (WINDOWPOS* wp);
4140
4241 bool SwitchingResolution = false ;
4342
@@ -188,15 +187,29 @@ LRESULT WndProc::DefWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
188187bool WndProc::ShouldHook (HWND hWnd)
189188{
190189 if (!IsWindow (hWnd))
190+ {
191191 return false ;
192+ }
193+
194+ const LONG_PTR style = GetWindowLongPtr (hWnd, GWL_STYLE);
192195
193- // Must be top-level (child windows never receive WM_ACTIVATE)
194- if (GetParent (hWnd) != NULL )
196+ // Child windows can NEVER be foreground
197+ if (style & WS_CHILD)
198+ {
195199 return false ;
200+ }
196201
197- // Message-only windows never activate
198- if (hWnd == HWND_MESSAGE)
202+ // Message-only windows can NEVER activate
203+ if (GetAncestor (hWnd, GA_PARENT) == HWND_MESSAGE)
204+ {
199205 return false ;
206+ }
207+
208+ // Must be true top-level
209+ if (GetAncestor (hWnd, GA_ROOT) != hWnd)
210+ {
211+ return false ;
212+ }
200213
201214 return true ;
202215}
@@ -269,12 +282,9 @@ WndProc::DATASTRUCT* WndProc::AddWndProc(HWND hWnd)
269282 WndProcList.push_back (NewEntry);
270283
271284 // Handle keyboard layout
272- if (Config.ForceKeyboardLayout )
285+ if (Config.ForceKeyboardLayout && hWnd == GetForegroundWindow () )
273286 {
274- if (hWnd == GetActiveWindow () || hWnd == GetFocus ())
275- {
276- PostMessage (hWnd, WM_APP_SET_KEYBOARD_LAYOUT, (WPARAM)NewWndProc, WM_MAKE_KEY (hWnd, NewWndProc));
277- }
287+ PostMessage (hWnd, WM_APP_SET_KEYBOARD_LAYOUT, (WPARAM)NewWndProc, WM_MAKE_KEY (hWnd, NewWndProc));
278288 }
279289
280290 // Return
@@ -307,18 +317,22 @@ WndProc::DATASTRUCT* WndProc::GetWndProctStruct(HWND hWnd)
307317
308318DWORD WndProc::MakeKey (DWORD Val1, DWORD Val2)
309319{
310- DWORD Result = 0 ;
311- for (DWORD Val : { Val1, Val2 } )
312- {
313- for (int x = 1 ; x < 8 ; x++)
314- {
315- Val = Val ^ (Val << 20 );
316- Val = Val ^ (Val >> 12 );
317- Val = (Val << 15 ) + (Val >> 17 );
318- }
319- Result += Val;
320- }
321- return Result % 8 ? Result ^ 0xAAAAAAAA : Result ^ 0x55555555 ;
320+ // Single-step mixer
321+ auto Mix = [](DWORD v) -> DWORD {
322+ v ^= v >> 16 ;
323+ v *= 0x7feb352d ;
324+ v ^= v >> 15 ;
325+ v *= 0x846ca68b ;
326+ v ^= v >> 16 ;
327+ return v;
328+ };
329+
330+ // Combine two inputs in a simple, asymmetric way
331+ DWORD Result = Mix (Val1) + 0x9E3779B9 ; // add golden ratio constant
332+ Result ^= Mix (Val2) + (Result << 6 ) + (Result >> 2 );
333+
334+ // Final avalanche
335+ return Mix (Result);
322336}
323337
324338void WndProc::SetKeyboardLayoutFocus (HWND hWnd, bool IsActivating)
@@ -329,27 +343,22 @@ void WndProc::SetKeyboardLayoutFocus(HWND hWnd, bool IsActivating)
329343 PostMessage (hWnd, WM_APP_SET_KEYBOARD_LAYOUT, (WPARAM)hWnd, WM_MAKE_KEY (hWnd, hWnd));
330344 }
331345 // On Deactivation
332- else if (IsKeyboardActive)
346+ else if (IsKeyboardActive && hWnd == GetForegroundWindow () )
333347 {
334348 IsKeyboardActive = false ;
335349 KeyboardLayout::UnSetForcedKeyboardLayout ();
336350 }
337351}
338352
339- bool WndProc::CheckFocusLoss (WINDOWPOS* wp )
353+ void WndProc::DisableForcedKeyboardLayout ( )
340354{
341- if (!wp)
355+ HWND hWnd = GetForegroundWindow ();
356+ if (GetWndProctStruct (hWnd))
342357 {
343- return false ;
358+ PostMessage (hWnd, WM_APP_DISABLE_KEYBOARD_LAYOUT, (WPARAM)hWnd, WM_MAKE_KEY (hWnd, hWnd)) ;
344359 }
345360
346- // Window is being hidden
347- if (wp->flags & SWP_HIDEWINDOW)
348- {
349- return true ;
350- }
351-
352- return false ;
361+ KeyboardLayout::DisableForcedKeyboardLayout ();
353362}
354363
355364LRESULT CALLBACK WndProc::Handler (HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam, WNDPROCSTRUCT* AppWndProcInstance)
@@ -393,7 +402,7 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
393402 case WM_APP_SET_KEYBOARD_LAYOUT:
394403 if (WM_MAKE_KEY (hWnd, wParam) == lParam)
395404 {
396- if (Config.ForceKeyboardLayout )
405+ if (Config.ForceKeyboardLayout && hWnd == GetForegroundWindow () && AppWndProcInstance-> IsActive () )
397406 {
398407 IsKeyboardActive = true ;
399408 KeyboardLayout::SetForcedKeyboardLayout ();
@@ -402,6 +411,17 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
402411 }
403412 break ;
404413
414+ case WM_APP_DISABLE_KEYBOARD_LAYOUT:
415+ if (WM_MAKE_KEY (hWnd, wParam) == lParam)
416+ {
417+ if (Config.ForceKeyboardLayout && hWnd == GetForegroundWindow ())
418+ {
419+ KeyboardLayout::DisableForcedKeyboardLayout ();
420+ }
421+ return NULL ;
422+ }
423+ break ;
424+
405425 case WM_ACTIVATEAPP:
406426 // Handle keyboard layout
407427 if (Config.ForceKeyboardLayout && hWnd == hWndInstance)
@@ -436,19 +456,13 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
436456 // Filter duplicate messages when using DirectDraw
437457 if (pDataStruct->IsDirectDraw )
438458 {
439- if (pDataStruct->IsActive == LOWORD (wParam))
459+ if (pDataStruct->IsWindowActive == LOWORD (wParam))
440460 {
441461 LOG_LIMIT (3 , __FUNCTION__ << " Warning: filtering duplicate WM_ACTIVATE: " << LOWORD (wParam));
442462 return DefWndProc (hWnd, Msg, wParam, lParam);
443463 }
444- pDataStruct->IsActive = LOWORD (wParam);
464+ pDataStruct->IsWindowActive = LOWORD (wParam);
445465 }
446- // Filter messages for loss of focus or minimize
447- if (Config.HideWindowFocusChanges && LOWORD (wParam) == WA_INACTIVE)
448- {
449- return DefWndProc (hWnd, Msg, wParam, lParam);
450- }
451-
452466 // Special handling for iconic state to prevent issues with some games
453467 if (pDataStruct->IsDirectDraw && IsIconic (hWnd))
454468 {
@@ -469,6 +483,11 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
469483 return DefWndProc (hWnd, Msg, wParam, lParam);
470484 }
471485 }
486+ // Filter messages for loss of focus or minimize
487+ if (Config.HideWindowFocusChanges && LOWORD (wParam) == WA_INACTIVE)
488+ {
489+ return DefWndProc (hWnd, Msg, wParam, lParam);
490+ }
472491 break ;
473492
474493 case WM_NCACTIVATE:
@@ -508,6 +527,11 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
508527 break ;
509528
510529 case WM_SHOWWINDOW:
530+ // Handle keyboard layout
531+ if (Config.ForceKeyboardLayout && hWnd == hWndInstance)
532+ {
533+ SetKeyboardLayoutFocus (hWnd, wParam != FALSE );
534+ }
511535 // Filter messages for loss of focus or minimize
512536 if (Config.HideWindowFocusChanges && wParam == FALSE )
513537 {
@@ -521,11 +545,13 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
521545 case WM_EXITSIZEMOVE:
522546 case WM_SIZING:
523547 case WM_SIZE:
524- case WM_WINDOWPOSCHANGING:
548+ // Handle keyboard layout
549+ if (Config.ForceKeyboardLayout && hWnd == hWndInstance && Msg == WM_SIZE)
550+ {
551+ SetKeyboardLayoutFocus (hWnd, wParam != SIZE_MINIMIZED);
552+ }
525553 // Filter messages for loss of focus or minimize
526- if (Config.HideWindowFocusChanges &&
527- ((Msg == WM_SIZE && wParam == SIZE_MINIMIZED) ||
528- (Msg == WM_WINDOWPOSCHANGING && CheckFocusLoss (reinterpret_cast <WINDOWPOS*>(lParam)))))
554+ if (Config.HideWindowFocusChanges && Msg == WM_SIZE && wParam == SIZE_MINIMIZED)
529555 {
530556 return DefWndProc (hWnd, Msg, wParam, lParam);
531557 }
@@ -538,22 +564,32 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
538564 }
539565 break ;
540566
567+ case WM_WINDOWPOSCHANGING:
541568 case WM_WINDOWPOSCHANGED:
542- // Filter messages for loss of focus or minimize
543- if (Config.HideWindowFocusChanges && CheckFocusLoss (reinterpret_cast <WINDOWPOS*>(lParam)))
544- {
545- return DefWndProc (hWnd, Msg, wParam, lParam);
546- }
547569 // Handle exclusive mode cases where the window is resized to be different than the display size
548570 if (pDataStruct->IsDirectDraw && pDataStruct->IsExclusiveMode )
549571 {
550572 m_IDirectDrawX::CheckWindowPosChange (hWnd, (WINDOWPOS*)lParam);
551573 }
574+ if (lParam)
575+ {
576+ const DWORD posFlags = reinterpret_cast <WINDOWPOS*>(lParam)->flags ;
552577
578+ // Handle keyboard layout
579+ if (Config.ForceKeyboardLayout && hWnd == hWndInstance && (posFlags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW)))
580+ {
581+ SetKeyboardLayoutFocus (hWnd, (posFlags & SWP_SHOWWINDOW));
582+ }
583+ // Filter messages for loss of focus or minimize
584+ if (Config.HideWindowFocusChanges && (posFlags & SWP_HIDEWINDOW))
585+ {
586+ return DefWndProc (hWnd, Msg, wParam, lParam);
587+ }
588+ }
553589 // Filter some messages while forcing windowed mode
554590 if (pDataStruct->IsCreatingDevice && IsForcingWindowedMode)
555591 {
556- LOG_LIMIT (3 , __FUNCTION__ << " Warning: filtering WM_WINDOWPOSCHANGED when forcing windowed mode. " <<
592+ LOG_LIMIT (3 , __FUNCTION__ << " Warning: filtering WM_WINDOWPOSCHANGE messages when forcing windowed mode. " <<
557593 hWnd << " " << Logging::hex (Msg) << " " << wParam << " " << lParam << " IsIconic: " << IsIconic (hWnd));
558594 return DefWndProc (hWnd, Msg, wParam, lParam);
559595 }
@@ -585,6 +621,11 @@ LRESULT CALLBACK WndProc::Handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lPa
585621 {
586622 AppWndProcInstance->SetInactive ();
587623 }
624+ // Handle keyboard layout
625+ if (Config.ForceKeyboardLayout && hWnd == hWndInstance && ((wParam & 0xFFF0 ) == SC_MINIMIZE || (wParam & 0xFFF0 ) == SC_MAXIMIZE))
626+ {
627+ SetKeyboardLayoutFocus (hWnd, (wParam & 0xFFF0 ) == SC_MAXIMIZE);
628+ }
588629 // Filter messages for loss of focus or minimize
589630 if (Config.HideWindowFocusChanges && (wParam & 0xFFF0 ) == SC_MINIMIZE)
590631 {
0 commit comments