Skip to content

Commit df060bf

Browse files
committed
CTRL SHIFT L fix
1 parent b1d8825 commit df060bf

2 files changed

Lines changed: 57 additions & 69 deletions

File tree

Overlay/src/HotkeyHandler.cpp

Lines changed: 53 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,26 @@
1212
namespace HotkeyHandler {
1313

1414
static HWND hwndHotkey = nullptr;
15-
static const UINT HOTKEY_ID_UNLOCK_ALL = 1;
15+
static const UINT HOTKEY_ID_UNLOCK_ALL = 1;
1616
static const UINT HOTKEY_ID_UNLOCK_LIST = 2;
1717
static std::atomic<bool> keepRunning{false};
1818
static std::thread messageThread;
1919

20-
// Helper: trim whitespace
2120
static std::string trim(const std::string& s) {
2221
size_t start = s.find_first_not_of(" \t\r\n");
2322
if (start == std::string::npos) return "";
2423
size_t end = s.find_last_not_of(" \t\r\n");
2524
return s.substr(start, end - start + 1);
2625
}
2726

28-
// Unlock all achievements
2927
static void UnlockAllAchievements() {
3028
if (Overlay::achievements) {
3129
int count = 0;
3230
for (auto& ach : *Overlay::achievements) {
3331
if (ach.UnlockState == UnlockState::Locked) {
3432
Overlay::unlockAchievement(&ach);
3533
count++;
36-
Logger::info("[HOTKEY] Unlocking all: %s", ach.AchievementId);
34+
Logger::info("[HOTKEY] Unlocking: %s", ach.AchievementId);
3735
}
3836
}
3937
Logger::info("[HOTKEY] Unlocked %d achievements.", count);
@@ -42,7 +40,6 @@ namespace HotkeyHandler {
4240
}
4341
}
4442

45-
// Unlock from file (unlock_list.txt in game folder)
4643
static void UnlockFromFile() {
4744
char path[MAX_PATH];
4845
GetModuleFileNameA(NULL, path, MAX_PATH);
@@ -75,7 +72,6 @@ namespace HotkeyHandler {
7572
Logger::info("[HOTKEY] Unlocked %d achievements from %s", count, listFile.c_str());
7673
}
7774

78-
// Window procedure for the hidden message window
7975
LRESULT CALLBACK HotkeyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
8076
if (msg == WM_HOTKEY) {
8177
if (wParam == HOTKEY_ID_UNLOCK_ALL) {
@@ -89,75 +85,77 @@ namespace HotkeyHandler {
8985
return DefWindowProc(hwnd, msg, wParam, lParam);
9086
}
9187

92-
// Message loop – runs in its own thread
88+
// FIX (Bug 3): The window, RegisterHotKey, and GetMessage must all live on the
89+
// same thread. We do all three here inside the message loop thread itself.
9390
static void MessageLoop() {
94-
MSG msg;
95-
while (keepRunning) {
96-
// Use GetMessage (blocks) instead of PeekMessage to reduce CPU usage
97-
if (GetMessage(&msg, NULL, 0, 0)) {
98-
TranslateMessage(&msg);
99-
DispatchMessage(&msg);
100-
}
101-
}
102-
Logger::info("Hotkey message loop exiting.");
103-
}
104-
105-
void Start() {
106-
if (keepRunning) {
107-
Logger::info("Hotkey handler already running.");
108-
return;
109-
}
110-
11191
// Register window class
112-
WNDCLASSEX wc = {0};
113-
wc.cbSize = sizeof(WNDCLASSEX);
114-
wc.lpfnWndProc = HotkeyWndProc;
115-
wc.hInstance = GetModuleHandle(NULL);
92+
WNDCLASSEX wc = {};
93+
wc.cbSize = sizeof(WNDCLASSEX);
94+
wc.lpfnWndProc = HotkeyWndProc;
95+
wc.hInstance = GetModuleHandle(NULL);
11696
wc.lpszClassName = L"ScreamAPI_HotkeyWindow";
11797
if (!RegisterClassEx(&wc)) {
118-
Logger::error("Failed to register hotkey window class (error %d)", GetLastError());
119-
return;
98+
DWORD err = GetLastError();
99+
// ERROR_CLASS_ALREADY_EXISTS (1410) is fine if Start() was somehow called twice
100+
if (err != ERROR_CLASS_ALREADY_EXISTS) {
101+
Logger::error("[HOTKEY] Failed to register window class (error %d)", err);
102+
keepRunning = false;
103+
return;
104+
}
120105
}
121106

122-
// Create hidden message-only window
123-
hwndHotkey = CreateWindowEx(0, wc.lpszClassName, L"HotkeyWindow", 0, 0, 0, 0, 0,
124-
HWND_MESSAGE, NULL, wc.hInstance, NULL);
107+
hwndHotkey = CreateWindowEx(0, wc.lpszClassName, L"HotkeyWindow", 0,
108+
0, 0, 0, 0, HWND_MESSAGE, NULL, wc.hInstance, NULL);
125109
if (!hwndHotkey) {
126-
Logger::error("Failed to create hotkey window (error %d)", GetLastError());
110+
Logger::error("[HOTKEY] Failed to create message window (error %d)", GetLastError());
111+
keepRunning = false;
127112
return;
128113
}
129114

130-
// Register hotkeys
131-
if (!RegisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_ALL, MOD_CONTROL | MOD_SHIFT, 'U')) {
132-
Logger::error("Failed to register hotkey Ctrl+Shift+U (error %d)", GetLastError());
133-
} else {
134-
Logger::info("Global hotkey Ctrl+Shift+U registered successfully.");
135-
}
115+
// RegisterHotKey on THIS thread — WM_HOTKEY will arrive in this thread's queue
116+
if (!RegisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_ALL, MOD_CONTROL | MOD_SHIFT | MOD_NOREPEAT, 'U'))
117+
Logger::error("[HOTKEY] Failed to register Ctrl+Shift+U (error %d)", GetLastError());
118+
else
119+
Logger::info("[HOTKEY] Ctrl+Shift+U registered.");
136120

137-
if (!RegisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_LIST, MOD_CONTROL | MOD_SHIFT, 'L')) {
138-
Logger::error("Failed to register hotkey Ctrl+Shift+L (error %d)", GetLastError());
139-
} else {
140-
Logger::info("Global hotkey Ctrl+Shift+L registered successfully.");
121+
if (!RegisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_LIST, MOD_CONTROL | MOD_SHIFT | MOD_NOREPEAT, 'L'))
122+
Logger::error("[HOTKEY] Failed to register Ctrl+Shift+L (error %d)", GetLastError());
123+
else
124+
Logger::info("[HOTKEY] Ctrl+Shift+L registered.");
125+
126+
MSG msg;
127+
while (keepRunning) {
128+
// GetMessage blocks until a message arrives for THIS thread
129+
BOOL ret = GetMessage(&msg, NULL, 0, 0);
130+
if (ret == 0 || ret == -1) break; // WM_QUIT or error
131+
TranslateMessage(&msg);
132+
DispatchMessage(&msg);
141133
}
142134

143-
// Start message loop thread
144-
keepRunning = true;
135+
UnregisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_ALL);
136+
UnregisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_LIST);
137+
DestroyWindow(hwndHotkey);
138+
hwndHotkey = nullptr;
139+
Logger::info("[HOTKEY] Message loop exited.");
140+
}
141+
142+
void Start() {
143+
// FIX (Bug 2): guard with keepRunning so double-calls are silently ignored
144+
if (keepRunning.exchange(true)) {
145+
Logger::info("[HOTKEY] Already running, ignoring duplicate Start().");
146+
return;
147+
}
145148
messageThread = std::thread(MessageLoop);
146149
messageThread.detach();
147-
Logger::info("Hotkey message loop thread started.");
150+
Logger::info("[HOTKEY] Message loop thread started.");
148151
}
149152

150153
void Stop() {
151154
keepRunning = false;
152155
if (hwndHotkey) {
153-
// Post a quit message to wake up GetMessage
154156
PostMessage(hwndHotkey, WM_QUIT, 0, 0);
155-
UnregisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_ALL);
156-
UnregisterHotKey(hwndHotkey, HOTKEY_ID_UNLOCK_LIST);
157-
DestroyWindow(hwndHotkey);
158-
hwndHotkey = nullptr;
159157
}
160-
// The message thread will exit when keepRunning is false and GetMessage returns false
161-
Logger::info("Hotkey handler stopped.");
158+
Logger::info("[HOTKEY] Stopped.");
162159
}
163-
}
160+
161+
}

Overlay/src/Overlay.cpp

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,6 @@ void AccumulateMouseWheel(float delta) {
134134
}
135135

136136
HRESULT WINAPI hookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) {
137-
static bool hotkeyStarted = false;
138-
139137
if (!bInit) {
140138
Logger::ovrly("hookedPresent: Initializing overlay");
141139
if (SUCCEEDED(pSwapChain->GetDevice(__uuidof(ID3D11Device), (void**)&gD3D11Device))) {
@@ -172,11 +170,7 @@ HRESULT WINAPI hookedPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT
172170
}
173171
else {
174172
Logger::error("hookedPresent: Failed to get D3D11 device");
175-
if (!hotkeyStarted) {
176-
hotkeyStarted = true;
177-
Logger::ovrly("D3D11 unavailable - starting global hotkey (Ctrl+Shift+U)");
178-
HotkeyHandler::Start();
179-
}
173+
// Hotkeys already started in Init() — nothing extra needed here
180174
bInit = true;
181175
return originalPresent(pSwapChain, SyncInterval, Flags);
182176
}
@@ -225,13 +219,9 @@ void Init(HMODULE hMod, Achievements* pAchievements, UnlockAchievementFunction*
225219
achievements = pAchievements;
226220
unlockAchievement = fnUnlockAchievement;
227221

228-
// Start global hotkeys unconditionally (works for all games: D3D11, OpenGL, Vulkan, Java)
229-
static bool hotkeysStarted = false;
230-
if (!hotkeysStarted && Config::EnableOverlay()) {
231-
HotkeyHandler::Start();
232-
hotkeysStarted = true;
233-
Logger::ovrly("Global hotkeys started (Ctrl+Shift+U / Ctrl+Shift+L)");
234-
}
222+
// Hotkeys always start regardless of EnableOverlay — the INI flag controls
223+
// the ImGui window only, not the Ctrl+Shift+U / Ctrl+Shift+L functionality.
224+
HotkeyHandler::Start(); // internally guarded: safe to call multiple times
235225

236226
Logger::ovrly("Overlay::Init: Starting async initialization");
237227
static auto initJob = std::async(std::launch::async, []() {

0 commit comments

Comments
 (0)