feat: add tray icon
This commit is contained in:
+53
-3
@@ -1,4 +1,5 @@
|
|||||||
#include "win-platform.h"
|
#include "win-platform.h"
|
||||||
|
#include "tray-icon.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "spoofer.h"
|
#include "spoofer.h"
|
||||||
#include "log-sink.h"
|
#include "log-sink.h"
|
||||||
@@ -103,11 +104,36 @@ bool run()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
mainLog.info("Proxy running, Ctrl+C to stop.");
|
mainLog.info("Setting up system tray icon");
|
||||||
|
|
||||||
|
TrayIcon tray;
|
||||||
|
tray.setExitCallback([&]() {
|
||||||
|
running = false;
|
||||||
|
mainLog.info("Exit requested from system tray.");
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!tray.init())
|
||||||
|
{
|
||||||
|
mainLog.error("Failed to initialize system tray icon.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND consoleWnd = GetConsoleWindow();
|
||||||
|
if (consoleWnd)
|
||||||
|
{
|
||||||
|
HMENU menuHandle = GetSystemMenu(consoleWnd, FALSE);
|
||||||
|
if (menuHandle) RemoveMenu(menuHandle, SC_CLOSE, MF_BYCOMMAND);
|
||||||
|
}
|
||||||
|
|
||||||
|
mainLog.info("Proxy running, Ctrl+C to stop. Check system tray for options.");
|
||||||
while (running)
|
while (running)
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
{
|
||||||
|
tray.processMessages();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||||
|
}
|
||||||
|
|
||||||
mainLog.info("Shutting down...");
|
mainLog.info("Shutting down...");
|
||||||
|
tray.shutdown();
|
||||||
proxy->shutdown();
|
proxy->shutdown();
|
||||||
cleaner->shutdown();
|
cleaner->shutdown();
|
||||||
|
|
||||||
@@ -116,11 +142,35 @@ bool run()
|
|||||||
delete conf;
|
delete conf;
|
||||||
conf = nullptr;
|
conf = nullptr;
|
||||||
|
|
||||||
|
ReleaseMutex(mtx);
|
||||||
|
CloseHandle(mtx);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int WINAPI WinMain(HINSTANCE /*hInstance*/, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
|
||||||
{
|
{
|
||||||
|
AllocConsole();
|
||||||
|
|
||||||
|
/*
|
||||||
|
ansi seequences
|
||||||
|
*/
|
||||||
|
HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||||
|
if (outHandle == INVALID_HANDLE_VALUE) return 1;
|
||||||
|
|
||||||
|
DWORD conMode = 0;
|
||||||
|
if (!GetConsoleMode(outHandle, &conMode)) return 1;
|
||||||
|
|
||||||
|
conMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
|
||||||
|
SetConsoleMode(outHandle, conMode);
|
||||||
|
|
||||||
|
/*
|
||||||
|
io
|
||||||
|
*/
|
||||||
|
FILE* dummy;
|
||||||
|
freopen_s(&dummy, "CONIN$", "r", stdin);
|
||||||
|
freopen_s(&dummy, "CONOUT$", "w", stdout);
|
||||||
|
freopen_s(&dummy, "CONOUT$", "w", stderr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
handlers for cleaning proxy conf on exit / crash / taskkill / whatever
|
handlers for cleaning proxy conf on exit / crash / taskkill / whatever
|
||||||
|
|||||||
@@ -0,0 +1,168 @@
|
|||||||
|
#include "tray-icon.h"
|
||||||
|
#include "win-platform.h"
|
||||||
|
|
||||||
|
#include <shellapi.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define WM_TRAYICON (WM_USER + 1)
|
||||||
|
#define ID_TRAY_APP_ICON 1001
|
||||||
|
#define ID_TRAY_EXIT 1002
|
||||||
|
#define ID_TRAY_CONTROL_PANEL 1003
|
||||||
|
|
||||||
|
TrayIcon* TrayIcon::instance = nullptr;
|
||||||
|
|
||||||
|
TrayIcon::TrayIcon() : _hwnd(nullptr), _isConsoleVisible(true)
|
||||||
|
{
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
TrayIcon::~TrayIcon()
|
||||||
|
{
|
||||||
|
shutdown();
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* TrayIcon::windowProc(void* h, unsigned int msg, unsigned long long wParam, long long lParam)
|
||||||
|
{
|
||||||
|
HWND hwnd = reinterpret_cast<HWND>(h);
|
||||||
|
|
||||||
|
if (msg == WM_DESTROY)
|
||||||
|
{
|
||||||
|
PostQuitMessage(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg == WM_TRAYICON)
|
||||||
|
{
|
||||||
|
if (lParam == WM_LBUTTONUP && instance)
|
||||||
|
instance->onToggleConsole();
|
||||||
|
else if (lParam == WM_RBUTTONUP)
|
||||||
|
{
|
||||||
|
POINT curPoint;
|
||||||
|
GetCursorPos(&curPoint);
|
||||||
|
|
||||||
|
HMENU popupHandle = CreatePopupMenu();
|
||||||
|
InsertMenuA(popupHandle, 0, MF_BYPOSITION | MF_STRING, ID_TRAY_CONTROL_PANEL, "Open Control Panel");
|
||||||
|
InsertMenuA(popupHandle, 1, MF_BYPOSITION | MF_STRING, ID_TRAY_EXIT, "Exit");
|
||||||
|
|
||||||
|
SetForegroundWindow(hwnd);
|
||||||
|
|
||||||
|
UINT clicked =
|
||||||
|
TrackPopupMenu(popupHandle, TPM_RETURNCMD | TPM_NONOTIFY, curPoint.x, curPoint.y, 0, hwnd, NULL);
|
||||||
|
|
||||||
|
if (clicked == ID_TRAY_CONTROL_PANEL && instance)
|
||||||
|
instance->onOpenControlPanel();
|
||||||
|
else if (clicked == ID_TRAY_EXIT && instance)
|
||||||
|
instance->onExit();
|
||||||
|
|
||||||
|
DestroyMenu(popupHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reinterpret_cast<void*>(DefWindowProcA(hwnd, msg, wParam, lParam));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TrayIcon::init()
|
||||||
|
{
|
||||||
|
WNDCLASSEXA wc = {0};
|
||||||
|
wc.cbSize = sizeof(WNDCLASSEX);
|
||||||
|
wc.lpfnWndProc = (WNDPROC)windowProc;
|
||||||
|
wc.hInstance = GetModuleHandle(NULL);
|
||||||
|
wc.lpszClassName = "HexUnlockedTrayIconClass";
|
||||||
|
|
||||||
|
if (!RegisterClassExA(&wc)) return false;
|
||||||
|
|
||||||
|
HWND window = CreateWindowExA(0, "HexUnlockedTrayIconClass", "HexUnlocked", 0, 0, 0, 0, 0, HWND_MESSAGE, NULL,
|
||||||
|
wc.hInstance, NULL);
|
||||||
|
if (!window) return false;
|
||||||
|
|
||||||
|
this->_hwnd = window;
|
||||||
|
|
||||||
|
NOTIFYICONDATAA nid = {0};
|
||||||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||||||
|
nid.hWnd = window;
|
||||||
|
nid.uID = ID_TRAY_APP_ICON;
|
||||||
|
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
|
||||||
|
nid.uCallbackMessage = WM_TRAYICON;
|
||||||
|
|
||||||
|
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
|
||||||
|
strncpy_s(nid.szTip, "HexUnlocked", sizeof(nid.szTip) - 1);
|
||||||
|
nid.szTip[sizeof(nid.szTip) - 1] = '\0';
|
||||||
|
|
||||||
|
Shell_NotifyIconA(NIM_ADD, &nid);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::shutdown()
|
||||||
|
{
|
||||||
|
if (_hwnd)
|
||||||
|
{
|
||||||
|
NOTIFYICONDATAA nid = {0};
|
||||||
|
nid.cbSize = sizeof(NOTIFYICONDATA);
|
||||||
|
nid.hWnd = reinterpret_cast<HWND>(_hwnd);
|
||||||
|
nid.uID = ID_TRAY_APP_ICON;
|
||||||
|
Shell_NotifyIconA(NIM_DELETE, &nid);
|
||||||
|
|
||||||
|
DestroyWindow(reinterpret_cast<HWND>(_hwnd));
|
||||||
|
UnregisterClassA("HexUnlockedTrayIconClass", GetModuleHandle(NULL));
|
||||||
|
_hwnd = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::processMessages() {
|
||||||
|
MSG msg;
|
||||||
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
if (msg.message == WM_QUIT) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
HWND consoleWnd = GetConsoleWindow();
|
||||||
|
if (consoleWnd && IsIconic(consoleWnd)) {
|
||||||
|
ShowWindow(consoleWnd, SW_HIDE);
|
||||||
|
_isConsoleVisible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::onToggleConsole() {
|
||||||
|
HWND consoleWnd = GetConsoleWindow();
|
||||||
|
if (!consoleWnd) return;
|
||||||
|
|
||||||
|
if (_isConsoleVisible) {
|
||||||
|
ShowWindow(consoleWnd, SW_HIDE);
|
||||||
|
_isConsoleVisible = false;
|
||||||
|
} else {
|
||||||
|
ShowWindow(consoleWnd, SW_RESTORE);
|
||||||
|
|
||||||
|
HWND hCurWnd = GetForegroundWindow();
|
||||||
|
DWORD dwMyID = GetCurrentThreadId();
|
||||||
|
DWORD dwCurID = GetWindowThreadProcessId(hCurWnd, NULL);
|
||||||
|
AttachThreadInput(dwCurID, dwMyID, TRUE);
|
||||||
|
SetWindowPos(consoleWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
SetWindowPos(consoleWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
|
||||||
|
SetForegroundWindow(consoleWnd);
|
||||||
|
SetFocus(consoleWnd);
|
||||||
|
SetActiveWindow(consoleWnd);
|
||||||
|
AttachThreadInput(dwCurID, dwMyID, FALSE);
|
||||||
|
|
||||||
|
_isConsoleVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::onOpenControlPanel()
|
||||||
|
{
|
||||||
|
ShellExecuteA(NULL, "open", "https://dbd.neru.rip", NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::onExit()
|
||||||
|
{
|
||||||
|
if (_exitCallback)
|
||||||
|
_exitCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrayIcon::setExitCallback(std::function<void()> callback)
|
||||||
|
{
|
||||||
|
_exitCallback = callback;
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
class TrayIcon {
|
||||||
|
public:
|
||||||
|
TrayIcon();
|
||||||
|
~TrayIcon();
|
||||||
|
|
||||||
|
bool init();
|
||||||
|
void shutdown();
|
||||||
|
void processMessages();
|
||||||
|
|
||||||
|
void onToggleConsole();
|
||||||
|
void onOpenControlPanel();
|
||||||
|
void onExit();
|
||||||
|
|
||||||
|
void setExitCallback(std::function<void()> callback);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void* windowProc(void* hwnd, unsigned int msg, unsigned long long wParam, long long lParam);
|
||||||
|
static TrayIcon* instance;
|
||||||
|
|
||||||
|
void* _hwnd;
|
||||||
|
bool _isConsoleVisible;
|
||||||
|
std::function<void()> _exitCallback;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user