Skip to content

Commit 9d8acb9

Browse files
committed
Better enable/disable for ForcedKeyboardLayout
#464
1 parent 186dbd2 commit 9d8acb9

File tree

5 files changed

+128
-58
lines changed

5 files changed

+128
-58
lines changed

Dllmain/BuildNo.rc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
#define BUILD_NUMBER 8172
1+
#define BUILD_NUMBER 8173

Dllmain/Dllmain.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,8 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD fdwReason, LPVOID lpReserved)
859859
// Unhook keyboard layout
860860
if (Config.ForceKeyboardLayout)
861861
{
862-
KeyboardLayout::DisableForcedKeyboardLayout();
862+
// Use WndProc for disabling so it can be done from the foreground window
863+
WndProc::DisableForcedKeyboardLayout();
863864
}
864865

865866
// Unload exception handler

GDI/WndProc.cpp

Lines changed: 93 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
188187
bool 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

308318
DWORD 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

324338
void 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

355364
LRESULT 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
{

GDI/WndProc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#define WM_APP_CREATE_D3D9_DEVICE (WM_APP + 0xFFF - 0x123)
77
#define WM_APP_SET_KEYBOARD_LAYOUT (WM_APP + 0xFFF - 0x124)
8+
#define WM_APP_DISABLE_KEYBOARD_LAYOUT (WM_APP + 0xFFF - 0x125)
89

910
#define WM_MAKE_KEY(Val1, Val2) \
1011
(LPARAM)WndProc::MakeKey((DWORD)Val1, (DWORD)Val2)
@@ -17,7 +18,7 @@ namespace WndProc
1718
bool IsCreatingDevice = false;
1819
bool IsExclusiveMode = false;
1920
bool NoWindowChanges = false;
20-
WORD IsActive = WA_INACTIVE;
21+
WORD IsWindowActive = WA_INACTIVE;
2122
DWORD DirectXVersion = 0;
2223
};
2324

@@ -29,4 +30,5 @@ namespace WndProc
2930
DATASTRUCT* GetWndProctStruct(HWND hWnd);
3031
DWORD MakeKey(DWORD Val1, DWORD Val2);
3132
WNDPROC CheckWndProc(HWND hWnd, LONG dwNewLong);
33+
void DisableForcedKeyboardLayout();
3234
}

Utils/ForceKeyboardLayout.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <sstream>
2121
#include "External\Hooking\Hook.h"
2222
#include "Utils.h"
23+
#include "Settings\Settings.h"
2324
#include "Logging\Logging.h"
2425

2526
namespace {
@@ -93,7 +94,11 @@ void KeyboardLayout::ForceKeyboardLayout(DWORD layoutID)
9394

9495
void KeyboardLayout::SetForcedKeyboardLayout()
9596
{
96-
if (g_Enabled)
97+
if (Config.Exiting)
98+
{
99+
DisableForcedKeyboardLayout();
100+
}
101+
else if (g_Enabled)
97102
{
98103
LOG_LIMIT(100, __FUNCTION__ << " Forcing keyboard layout!");
99104

@@ -106,7 +111,7 @@ void KeyboardLayout::SetForcedKeyboardLayout()
106111
}
107112
}
108113

109-
void KeyboardLayout::UnSetForcedKeyboardLayout()
114+
static void UnSetLayout()
110115
{
111116
if (g_PreviousHKL)
112117
{
@@ -116,11 +121,32 @@ void KeyboardLayout::UnSetForcedKeyboardLayout()
116121
}
117122
}
118123

124+
void KeyboardLayout::UnSetForcedKeyboardLayout()
125+
{
126+
if (Config.Exiting)
127+
{
128+
DisableForcedKeyboardLayout();
129+
}
130+
else
131+
{
132+
UnSetLayout();
133+
}
134+
}
135+
119136
void KeyboardLayout::DisableForcedKeyboardLayout()
120137
{
121138
if (g_Enabled)
122139
{
123140
g_Enabled = false;
124-
UnSetForcedKeyboardLayout();
141+
142+
HWND hwndForeground = GetForegroundWindow();
143+
DWORD fgThread = GetWindowThreadProcessId(hwndForeground, NULL);
144+
DWORD curThread = GetCurrentThreadId();
145+
146+
AttachThreadInput(curThread, fgThread, TRUE);
147+
148+
UnSetLayout();
149+
150+
AttachThreadInput(curThread, fgThread, FALSE);
125151
}
126152
}

0 commit comments

Comments
 (0)