#include "Defines.h" #include #include #include #include #include #include #include #include #include #include #include #pragma warning(disable: 4996) // ReSharper disable CppDeprecatedEntity // ReSharper disable CppClangTidyCertErr33C std::ofstream GLogFile; bool GShouldExit = false; void PrintLog(const std::string& Text); LRESULT CALLBACK MainWindowProc(HWND Window, UINT Message, WPARAM WParam, LPARAM LParam); int WINAPI WinMain(HINSTANCE Instance, HINSTANCE, LPSTR, int) { using namespace std::chrono_literals; const HANDLE Mutex = CreateMutex(nullptr, TRUE, "FocusIME_SingleInstance_Mutex"); if (Mutex == nullptr) { MessageBox(nullptr, "Failed to create mutex.", "FocusIME", MB_OK | MB_ICONERROR); return 1; } if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBox(nullptr, "FocusIME is already running.", "FocusIME", MB_OK | MB_ICONINFORMATION); CloseHandle(Mutex); return 0; } HWND MainWindow = nullptr; WNDCLASS MainWindowClass = { }; MainWindowClass.lpfnWndProc = MainWindowProc; MainWindowClass.hInstance = Instance; MainWindowClass.lpszClassName = "FocusIME_MainWindow"; MainWindowClass.hCursor = LoadCursor(nullptr, IDC_ARROW); MainWindowClass.hbrBackground = reinterpret_cast(COLOR_WINDOW + 1); // NOLINT(performance-no-int-to-ptr) if (!RegisterClass(&MainWindowClass)) { MessageBox(nullptr, "Failed to register main window class.", "FocusIME", MB_OK | MB_ICONERROR); CloseHandle(Mutex); return 1; } MainWindow = CreateWindow( "FocusIME_MainWindow", "FocusIME", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, Instance, nullptr); if (!MainWindow) { MessageBox(nullptr, "Failed to create main window.", "FocusIME", MB_OK | MB_ICONERROR); CloseHandle(Mutex); return 1; } ShowWindow(MainWindow, SW_HIDE); GLogFile.open("Log.txt", std::ios::out | std::ios::app); if (!GLogFile.is_open()) { MessageBox(nullptr, "Failed to open log file.", "FocusIME", MB_OK | MB_ICONERROR); CloseHandle(Mutex); return 1; } PrintLog("FocusIME started successfully"); MSG Message = { }; while (!GShouldExit) { BOOL bResult = GetMessage(&Message, nullptr, 0, 0); if (bResult > 0) { TranslateMessage(&Message); DispatchMessage (&Message); } else if (bResult == 0) break; else { DWORD ErrorCode = GetLastError(); LPSTR MessageBuffer = nullptr; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast(&MessageBuffer), 0, nullptr); std::string ErrorMessage = "Message loop failed with error code " + std::to_string(ErrorCode); if (MessageBuffer) { ErrorMessage += ": " + std::string(MessageBuffer); LocalFree(MessageBuffer); } PrintLog(ErrorMessage); break; } } PrintLog("FocusIME is shutting down..."); GLogFile.close(); DestroyWindow(MainWindow); CloseHandle(Mutex); return 0; } LRESULT CALLBACK MainWindowProc(const HWND Window, const UINT Message, const WPARAM WParam, const LPARAM LParam) { static NOTIFYICONDATA NotifyIconData; constexpr UINT TrayIconMessage = WM_USER + 1; constexpr UINT ExitMessage = 1001; switch (Message) { case WM_CREATE: memset(&NotifyIconData, 0, sizeof(NOTIFYICONDATA)); NotifyIconData.cbSize = sizeof(NOTIFYICONDATA); NotifyIconData.hWnd = Window; NotifyIconData.uID = 1; NotifyIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; NotifyIconData.uCallbackMessage = TrayIconMessage; NotifyIconData.hIcon = LoadIcon(nullptr, IDI_APPLICATION); strcpy(NotifyIconData.szTip, "FocusIME"); if (!Shell_NotifyIcon(NIM_ADD, &NotifyIconData)) return -1; break; case TrayIconMessage: switch (LParam) { case WM_RBUTTONUP: case WM_CONTEXTMENU: POINT Point; GetCursorPos(&Point); if (const HMENU Menu = CreatePopupMenu()) { InsertMenu(Menu, -1, MF_BYPOSITION | MF_STRING, ExitMessage, "Exit(&X)"); SetMenuDefaultItem(Menu, ExitMessage, FALSE); SetForegroundWindow(Window); TrackPopupMenu(Menu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, Point.x, Point.y, 0, Window, nullptr); PostMessage(Window, WM_NULL, 0, 0); DestroyMenu(Menu); } break; default: break; } break; case WM_COMMAND: if (LOWORD(WParam) == ExitMessage) { PrintLog("Exit command received from tray menu"); GShouldExit = true; PostQuitMessage(0); } break; case WM_DESTROY: Shell_NotifyIcon(NIM_DELETE, &NotifyIconData); PostQuitMessage(0); break; default: return DefWindowProc(Window, Message, WParam, LParam); } return 0; } void PrintLog(const std::string& Text) { const auto Now = std::chrono::system_clock::now(); const auto Time = std::chrono::system_clock::to_time_t(Now); const long long Milliseconds = (std::chrono::duration_cast(Now.time_since_epoch()) % 1000).count(); static std::mutex Mutex; std::lock_guard Lock(Mutex); const std::tm* LocalTime = std::localtime(&Time); // NOLINT(concurrency-mt-unsafe) char Buffer[] = "[2025-06-21 20:05:04.305]: "; std::strftime(&Buffer[1], 20, "%Y-%m-%d %H:%M:%S", LocalTime); Buffer[20] = '.'; constexpr char Digits[] = "0123456789"; Buffer[21] = Digits[Milliseconds / 100 % 10]; Buffer[22] = Digits[Milliseconds / 10 % 10]; Buffer[23] = Digits[Milliseconds / 1 % 10]; GLogFile << Buffer << Text << std::endl; } // ReSharper restore CppDeprecatedEntity // ReSharper restore CppClangTidyCertErr33C