feat(master): hook focus changed event
This commit is contained in:
@ -2,27 +2,32 @@
|
|||||||
|
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#include <psapi.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <thread>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iomanip>
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#pragma comment(lib, "psapi.lib")
|
||||||
|
|
||||||
#pragma warning(disable: 4996)
|
#pragma warning(disable: 4996)
|
||||||
|
|
||||||
// ReSharper disable CppDeprecatedEntity
|
// ReSharper disable CppDeprecatedEntity
|
||||||
// ReSharper disable CppClangTidyCertErr33C
|
// ReSharper disable CppClangTidyCertErr33C
|
||||||
|
|
||||||
|
std::mutex GLogMutex;
|
||||||
std::ofstream GLogFile;
|
std::ofstream GLogFile;
|
||||||
|
|
||||||
bool GShouldExit = false;
|
std::atomic<bool> GShouldExit = false;
|
||||||
|
|
||||||
void PrintLog(const std::string& Text);
|
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);
|
LRESULT CALLBACK MainWindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam);
|
||||||
|
|
||||||
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
||||||
@ -47,8 +52,6 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWND MainWindow = nullptr;
|
|
||||||
|
|
||||||
WNDCLASS MainWindowClass = { };
|
WNDCLASS MainWindowClass = { };
|
||||||
|
|
||||||
MainWindowClass.lpfnWndProc = MainWindowProc;
|
MainWindowClass.lpfnWndProc = MainWindowProc;
|
||||||
@ -66,7 +69,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MainWindow = CreateWindow(
|
const HWND MainWindow = CreateWindow(
|
||||||
"FocusIME_MainWindow",
|
"FocusIME_MainWindow",
|
||||||
"FocusIME",
|
"FocusIME",
|
||||||
WS_OVERLAPPEDWINDOW,
|
WS_OVERLAPPEDWINDOW,
|
||||||
@ -74,7 +77,7 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
|||||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||||
nullptr, nullptr, Instance, nullptr);
|
nullptr, nullptr, Instance, nullptr);
|
||||||
|
|
||||||
if (!MainWindow)
|
if (MainWindow == nullptr)
|
||||||
{
|
{
|
||||||
MessageBox(nullptr, "Failed to create main window.", "FocusIME", MB_OK | MB_ICONERROR);
|
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);
|
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);
|
GLogFile.open("Log.txt", std::ios::out | std::ios::app);
|
||||||
|
|
||||||
if (!GLogFile.is_open())
|
if (!GLogFile.is_open())
|
||||||
@ -140,7 +161,13 @@ int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int)
|
|||||||
|
|
||||||
PrintLog("FocusIME is shutting down...");
|
PrintLog("FocusIME is shutting down...");
|
||||||
|
|
||||||
GLogFile.close();
|
{
|
||||||
|
std::lock_guard Lock(GLogMutex);
|
||||||
|
|
||||||
|
GLogFile.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
UnhookWinEvent(FocusEventHook);
|
||||||
|
|
||||||
DestroyWindow(MainWindow);
|
DestroyWindow(MainWindow);
|
||||||
|
|
||||||
@ -237,6 +264,59 @@ LRESULT CALLBACK MainWindowProc(const HWND Window, const UINT Message, const WPA
|
|||||||
return 0;
|
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)
|
void PrintLog(const std::string& Text)
|
||||||
{
|
{
|
||||||
const auto Now = std::chrono::system_clock::now();
|
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();
|
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)
|
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];
|
Buffer[23] = Digits[Milliseconds / 1 % 10];
|
||||||
|
|
||||||
GLogFile << Buffer << Text << std::endl;
|
GLogFile << Buffer << Text << std::endl;
|
||||||
|
|
||||||
|
GLogFile.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReSharper restore CppDeprecatedEntity
|
// ReSharper restore CppDeprecatedEntity
|
||||||
|
Reference in New Issue
Block a user