From db7243bfcbc740a44c296e62f01df27a00bc480f Mon Sep 17 00:00:00 2001 From: "KP@XX15c" Date: Sun, 22 Feb 2026 12:35:44 +0700 Subject: [PATCH 1/2] =?UTF-8?q?[Win]=20S=E1=BB=ADa=20l=E1=BB=97i=20ph?= =?UTF-8?q?=C3=ADm=20t=E1=BA=AFt=20kh=C3=B4ng=20ho=E1=BA=A1t=20=C4=91?= =?UTF-8?q?=E1=BB=99ng=20sau=20khi=20m=E1=BB=9F=20kh=C3=B3a=20m=C3=A0n=20h?= =?UTF-8?q?=C3=ACnh?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vấn đề: Sau khi unlock màn hình, các phím tắt (Ctrl+Shift+Z, v.v.) không hoạt động nữa. Nguyên nhân: Khi Windows unlock, các keyboard hooks có thể bị invalidate, và biến _lastFlag vẫn giữ giá trị modifier key cũ, gây ra checkHotKey() fail. Giải pháp: 1. Thêm wtsapi32.h và wtsapi32.lib 2. Đăng ký WTS session change notification 3. Khi unlock (WTS_SESSION_UNLOCK), reinitialize hooks 4. Reset _flag, _lastFlag, _keycode, _isFlagKey về 0 Thay đổi files: - stdafx.h: Thêm #include - OpenKey.vcxproj: Thêm wtsapi32.lib dependency - SystemTrayHelper.cpp: Thêm WM_WTSSESSION_CHANGE handler - OpenKey.cpp: Thêm OpenKeyReinitHooks() reset modifier state - OpenKeyManager.h/.cpp: Thêm reinitHooks() method Co-Authored-By: Claude Sonnet 4.6 --- .../OpenKey/win32/OpenKey/OpenKey/OpenKey.cpp | 21 +++++++++++++++++++ .../win32/OpenKey/OpenKey/OpenKey.vcxproj | 4 ++++ .../win32/OpenKey/OpenKey/OpenKeyManager.cpp | 6 ++++++ .../win32/OpenKey/OpenKey/OpenKeyManager.h | 1 + .../OpenKey/OpenKey/SystemTrayHelper.cpp | 12 +++++++++++ .../OpenKey/win32/OpenKey/OpenKey/stdafx.h | 1 + 6 files changed, 45 insertions(+) diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.cpp b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.cpp index faa179c..cceedb5 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.cpp +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.cpp @@ -77,6 +77,27 @@ void OpenKeyFree() { UnhookWinEvent(hSystemEvent); } +void OpenKeyReinitHooks() { + // Unhook existing hooks + UnhookWindowsHookEx(hMouseHook); + UnhookWindowsHookEx(hKeyboardHook); + UnhookWinEvent(hSystemEvent); + + // IMPORTANT: Reset modifier key state to prevent stale state issues + // This fixes the bug where hotkeys don't work after unlock because + // _lastFlag still contains old modifier key values + _flag = 0; + _lastFlag = 0; + _keycode = 0; + _isFlagKey = false; + + // Reinitialize hooks + HINSTANCE hInstance = GetModuleHandle(NULL); + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardHookProcess, hInstance, 0); + hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseHookProcess, hInstance, 0); + hSystemEvent = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, winEventProcCallback, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); +} + void OpenKeyInit() { APP_GET_DATA(vLanguage, 1); APP_GET_DATA(vInputType, 0); diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.vcxproj b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.vcxproj index 69b1e31..4c09617 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.vcxproj +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKey.vcxproj @@ -97,6 +97,7 @@ Windows true AsInvoker + wtsapi32.lib;%(AdditionalDependencies) @@ -111,6 +112,7 @@ Windows true + wtsapi32.lib;%(AdditionalDependencies) @@ -131,6 +133,7 @@ true true AsInvoker + wtsapi32.lib;%(AdditionalDependencies) @@ -151,6 +154,7 @@ true true AsInvoker + wtsapi32.lib;%(AdditionalDependencies) diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.cpp b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.cpp index ea1181b..26fa534 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.cpp +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.cpp @@ -51,6 +51,12 @@ void OpenKeyManager::freeEngine() { OpenKeyFree(); } +void OpenKeyManager::reinitHooks() { + // Reinitialize keyboard hooks after session unlock + extern void OpenKeyReinitHooks(); + OpenKeyReinitHooks(); +} + bool OpenKeyManager::checkUpdate(string& newVersion) { wstring dataW = OpenKeyHelper::getContentOfUrl(L"https://raw.githubusercontent.com/tuyenvm/OpenKey/master/version.json"); string data = wideStringToUtf8(dataW); diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.h b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.h index fc45cf2..0e875ab 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.h +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/OpenKeyManager.h @@ -22,6 +22,7 @@ class OpenKeyManager { static void initEngine(); static void freeEngine(); + static void reinitHooks(); static bool checkUpdate(string& newVersion); diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp b/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp index 55d786e..0cdea4a 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp @@ -79,6 +79,14 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) switch (message) { case WM_CREATE: taskbarCreated = RegisterWindowMessage(_T("TaskbarCreated")); + // Register for session change notifications to handle lock/unlock + WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_THIS_SESSION); + break; + case WM_WTSSESSION_CHANGE: + // Reinitialize keyboard hooks on session unlock (wParam == WTS_SESSION_UNLOCK) + if (wParam == WTS_SESSION_UNLOCK) { + OpenKeyManager::reinitHooks(); + } break; case WM_USER+2019: AppDelegate::getInstance()->onControlPanel(); @@ -169,6 +177,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) Shell_NotifyIcon(NIM_ADD, &nid); } return DefWindowProc(hWnd, message, wParam, lParam); + case WM_DESTROY: + // Unregister session change notifications + WTSUnRegisterSessionNotification(hWnd); + return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/stdafx.h b/Sources/OpenKey/win32/OpenKey/OpenKey/stdafx.h index 8960e21..7a81871 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/stdafx.h +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/stdafx.h @@ -37,6 +37,7 @@ redistribute your new version, it MUST be open source. #include #include #include +#include #include "resource.h" From 0a28652026550b74afa5ead58ae36c83d70ef5ee Mon Sep 17 00:00:00 2001 From: "KP@XX15c" Date: Mon, 23 Feb 2026 11:39:54 +0700 Subject: [PATCH 2/2] =?UTF-8?q?[Win]=20Th=C3=AAm=20timer=2010s=20=C4=91?= =?UTF-8?q?=E1=BB=83=20fix=20l=E1=BB=97i=20keyboard=20hooks=20b=E1=BB=8B?= =?UTF-8?q?=20ng=E1=BA=AFt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vấn đề: Keyboard shortcuts và gõ Tiếng Việt randomly bị stuck, nhưng click icon system tray vẫn toggle được EN/VI được. Nguyên nhân: Keyboard hooks bị Windows remove/invalidate, khiến không nhận được keyboard events. Giải pháp: Thêm timer 10s để tự động reinitialize hooks, giống như khi lock/unlock màn hình. --- .../win32/OpenKey/OpenKey/.claude/settings.local.json | 8 ++++++++ .../win32/OpenKey/OpenKey/SystemTrayHelper.cpp | 11 +++++++++++ 2 files changed, 19 insertions(+) create mode 100644 Sources/OpenKey/win32/OpenKey/OpenKey/.claude/settings.local.json diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/.claude/settings.local.json b/Sources/OpenKey/win32/OpenKey/OpenKey/.claude/settings.local.json new file mode 100644 index 0000000..08d96a1 --- /dev/null +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/.claude/settings.local.json @@ -0,0 +1,8 @@ +{ + "permissions": { + "allow": [ + "Bash(cd C:\\\\Users\\\\vankh\\\\Documents\\\\Sources\\\\OpenKey:*)", + "Bash(curl:*)" + ] + } +} diff --git a/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp b/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp index 0cdea4a..686d17d 100644 --- a/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp +++ b/Sources/OpenKey/win32/OpenKey/OpenKey/SystemTrayHelper.cpp @@ -75,12 +75,15 @@ map menuData = { LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static UINT taskbarCreated; + const UINT_PTR HOOK_HEALTH_TIMER = 1; // Timer ID for hook health check switch (message) { case WM_CREATE: taskbarCreated = RegisterWindowMessage(_T("TaskbarCreated")); // Register for session change notifications to handle lock/unlock WTSRegisterSessionNotification(hWnd, NOTIFY_FOR_THIS_SESSION); + // Set up a 10-second timer to periodically fix stuck keyboard hooks + SetTimer(hWnd, HOOK_HEALTH_TIMER, 10000, NULL); break; case WM_WTSSESSION_CHANGE: // Reinitialize keyboard hooks on session unlock (wParam == WTS_SESSION_UNLOCK) @@ -88,6 +91,12 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) OpenKeyManager::reinitHooks(); } break; + case WM_TIMER: + // Periodic hook health check - reinitialize hooks to fix random stuck issues + if (wParam == HOOK_HEALTH_TIMER) { + OpenKeyManager::reinitHooks(); + } + break; case WM_USER+2019: AppDelegate::getInstance()->onControlPanel(); break; @@ -180,6 +189,8 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case WM_DESTROY: // Unregister session change notifications WTSUnRegisterSessionNotification(hWnd); + // Kill the health check timer + KillTimer(hWnd, HOOK_HEALTH_TIMER); return DefWindowProc(hWnd, message, wParam, lParam); } return 0;