feat(master): hook focus changed event

This commit is contained in:
2025-06-21 21:45:32 +08:00
parent 1ceb8cda01
commit 523be0930a

View File

@ -2,27 +2,32 @@
#include <windows.h>
#include <shellapi.h>
#include <psapi.h>
#include <iostream>
#include <fstream>
#include <thread>
#include <chrono>
#include <string>
#include <filesystem>
#include <ctime>
#include <iomanip>
#include <mutex>
#include <atomic>
#pragma comment(lib, "psapi.lib")
#pragma warning(disable: 4996)
// ReSharper disable CppDeprecatedEntity
// ReSharper disable CppClangTidyCertErr33C
std::mutex GLogMutex;
std::ofstream GLogFile;
bool GShouldExit = false;
std::atomic<bool> GShouldExit = false;
void PrintLog(const std::string& Text);
void CALLBACK FocusEventHookProc(HWINEVENTHOOK, DWORD Event, HWND Window, LONG, LONG, DWORD, DWORD);
LRESULT CALLBACK MainWindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam);
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
@ -47,8 +52,6 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
return 0;
}
HWND MainWindow = nullptr;
WNDCLASS MainWindowClass = { };
MainWindowClass.lpfnWndProc = MainWindowProc;
@ -66,7 +69,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
return 1;
}
MainWindow = CreateWindow(
const HWND MainWindow = CreateWindow(
"FocusIME_MainWindow",
"FocusIME",
WS_OVERLAPPEDWINDOW,
@ -74,7 +77,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
CW_USEDEFAULT, CW_USEDEFAULT,
nullptr, nullptr, Instance, nullptr);
if (!MainWindow)
if (MainWindow == nullptr)
{
MessageBox(nullptr, "Failed to create main window.", "FocusIME", MB_OK | MB_ICONERROR);
@ -85,6 +88,24 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
ShowWindow(MainWindow, SW_HIDE);
const HWINEVENTHOOK FocusEventHook = SetWinEventHook(
EVENT_OBJECT_FOCUS, EVENT_OBJECT_FOCUS,
nullptr,
FocusEventHookProc,
0, 0,
WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
if (FocusEventHook == nullptr)
{
MessageBox(nullptr, "Failed to set focus event hook.", "FocusIME", MB_OK | MB_ICONWARNING);
DestroyWindow(MainWindow);
CloseHandle(Mutex);
return 1;
}
GLogFile.open("Log.txt", std::ios::out | std::ios::app);
if (!GLogFile.is_open())
@ -140,7 +161,13 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
PrintLog("FocusIME is shutting down...");
GLogFile.close();
{
std::lock_guard Lock(GLogMutex);
GLogFile.close();
}
UnhookWinEvent(FocusEventHook);
DestroyWindow(MainWindow);
@ -237,6 +264,59 @@ LRESULT CALLBACK MainWindowProc(const HWND Window, const UINT Message, const WPA
return 0;
}
void CALLBACK FocusEventHookProc(HWINEVENTHOOK, const DWORD Event, const HWND Window, LONG, LONG, DWORD, DWORD)
{
if (Event == EVENT_OBJECT_FOCUS && Window != nullptr)
{
std::string ProcessName;
do
{
DWORD PID = 0;
GetWindowThreadProcessId(Window, &PID);
const HANDLE ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, PID);
if (ProcessHandle == nullptr)
{
ProcessName = "Unknown";
break;
}
char Buffer[MAX_PATH] = { };
if (GetModuleBaseName(ProcessHandle, nullptr, Buffer, sizeof(Buffer)) == 0)
{
CloseHandle(ProcessHandle);
ProcessName = "Unknown";
break;
}
CloseHandle(ProcessHandle);
ProcessName = Buffer;
}
while (false);
char Title[1024] = { };
GetWindowText(Window, Title, sizeof(Title));
std::string MessageBuffer = "Focus changed to: " + ProcessName;
if (strlen(Title) > 0)
{
MessageBuffer += " (" + std::string(Title) + ")";
}
PrintLog(MessageBuffer);
}
}
void PrintLog(const std::string& Text)
{
const auto Now = std::chrono::system_clock::now();
@ -244,7 +324,9 @@ void PrintLog(const std::string& Text)
const long long Milliseconds = (std::chrono::duration_cast<std::chrono::milliseconds>(Now.time_since_epoch()) % 1000).count();
static std::mutex Mutex; std::lock_guard Lock(Mutex);
std::lock_guard Lock(GLogMutex);
if (!GLogFile.is_open()) return;
const std::tm* LocalTime = std::localtime(&Time); // NOLINT(concurrency-mt-unsafe)
@ -261,6 +343,8 @@ void PrintLog(const std::string& Text)
Buffer[23] = Digits[Milliseconds / 1 % 10];
GLogFile << Buffer << Text << std::endl;
GLogFile.flush();
}
// ReSharper restore CppDeprecatedEntity