feat(tray): add tray icon control
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
#include "Defines.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <thread>
|
||||
@ -18,6 +19,224 @@
|
||||
|
||||
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<HBRUSH>(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<LPSTR>(&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();
|
||||
@ -44,64 +263,5 @@ void PrintLog(const std::string& Text)
|
||||
GLogFile << Buffer << Text << std::endl;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE, 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;
|
||||
}
|
||||
|
||||
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 (true)
|
||||
{
|
||||
BOOL bResult = GetMessage(&Message, nullptr, 0, 0);
|
||||
|
||||
if (bResult > 0)
|
||||
{
|
||||
TranslateMessage(&Message);
|
||||
DispatchMessage (&Message);
|
||||
}
|
||||
|
||||
else break;
|
||||
}
|
||||
|
||||
PrintLog("FocusIME is shutting down...");
|
||||
|
||||
GLogFile.close();
|
||||
|
||||
CloseHandle(Mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ReSharper restore CppDeprecatedEntity
|
||||
// ReSharper restore CppClangTidyCertErr33C
|
||||
|
Reference in New Issue
Block a user