From 081eb00a4635b67c6772bfb725b152be58667a98 Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Thu, 4 Jun 2026 23:54:32 -0500 Subject: [PATCH] Add drive detection and states --- WatchfulEye/resource.rc | 2 +- WatchfulEye/src/Application.cpp | 75 ++++++++++++++++++++++++++++----- WatchfulEye/src/Application.h | 12 ++++-- WatchfulEye/src/main.cpp | 5 ++- WatchfulEye/src/pch.h | 1 + WatchfulEye/src/resource.h | 2 +- 6 files changed, 80 insertions(+), 17 deletions(-) diff --git a/WatchfulEye/resource.rc b/WatchfulEye/resource.rc index 96ec08b..91a9b6d 100644 --- a/WatchfulEye/resource.rc +++ b/WatchfulEye/resource.rc @@ -54,7 +54,7 @@ EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW CAPTION "Dialog" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN - CTEXT "Time Remaining on Tester",IDC_STATICUPPER,7,4,286,22,SS_CENTERIMAGE,WS_EX_TRANSPARENT + CTEXT "Lower",IDC_STATICLOWER,7,85,286,22,SS_CENTERIMAGE,WS_EX_TRANSPARENT END diff --git a/WatchfulEye/src/Application.cpp b/WatchfulEye/src/Application.cpp index 6ffca50..b4d0225 100644 --- a/WatchfulEye/src/Application.cpp +++ b/WatchfulEye/src/Application.cpp @@ -11,19 +11,21 @@ #define WM_UPDATE WM_USER + 1 // Update window message namespace watchfuleye { - Application::Application(const char* appName, const char* appVersion, unsigned int maximumMinutes) + Application::Application(const char* appName, const char* appVersion, unsigned int maximumMinutes, const char* driveToDetect) : m_appName(appName) , m_appVersion(appVersion) , m_mainDlg(nullptr) + , m_running(true) + , m_active(false) + , m_overTime(false) , m_maxMinutes(maximumMinutes) + , m_drive(driveToDetect) , m_startTime() { std::cout << std::format("{} {}\n", m_appName, m_appVersion); } void Application::run() { - m_startTime = Clock::now(); - // Create dialog SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2); @@ -32,19 +34,29 @@ namespace watchfuleye { // Create tray icon createTrayIcon(); + // Create drive query thread + std::thread queryThread(&Application::queryThreadFunction, this); + ShowWindow(m_mainDlg, SW_SHOW); MSG msg = {}; while (GetMessage(&msg, nullptr, 0, 0)) IsDialogMessage(m_mainDlg, &msg); + + m_running = false; + + queryThread.join(); } BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { static Application* app = nullptr; static UINT taskbarCreatedMessage = 0; - static HBRUSH backgroundBrush = CreateSolidBrush(RGB(255, 150, 150)); static HFONT timeFont = nullptr; + static HBRUSH greenBackgroundBrush = CreateSolidBrush(RGB(150, 255, 150)); + static HBRUSH yellowBackgroundBrush = CreateSolidBrush(RGB(255, 255, 150)); + static HBRUSH redBackgroundBrush = CreateSolidBrush(RGB(255, 150, 150)); + switch (msg) { case WM_INITDIALOG: { app = reinterpret_cast(lParam); @@ -55,7 +67,7 @@ namespace watchfuleye { // Spawn in the lower right corner of the virtual screen (might be problematic in some cases) int cornerX = GetSystemMetrics(SM_XVIRTUALSCREEN) + GetSystemMetrics(SM_CXVIRTUALSCREEN); int cornerY = GetSystemMetrics(SM_YVIRTUALSCREEN) + GetSystemMetrics(SM_CYVIRTUALSCREEN); - SetWindowPos(dlg, nullptr, cornerX - 550, cornerY - 340, NULL, NULL, SWP_NOZORDER | SWP_NOSIZE); + SetWindowPos(dlg, nullptr, cornerX - 550, cornerY - 540, NULL, NULL, SWP_NOZORDER | SWP_NOSIZE); taskbarCreatedMessage = RegisterWindowMessage("TaskbarCreated"); @@ -64,7 +76,7 @@ namespace watchfuleye { strcpy(lFont.lfFaceName, "Consolas"); lFont.lfHeight = 45; HFONT upperFont = CreateFontIndirect(&lFont); - SendMessage(GetDlgItem(dlg, IDC_STATICUPPER), WM_SETFONT, reinterpret_cast(upperFont), NULL); + SendMessage(GetDlgItem(dlg, IDC_STATICLOWER), WM_SETFONT, reinterpret_cast(upperFont), NULL); lFont.lfHeight = 200; lFont.lfWeight = FW_BOLD; @@ -77,7 +89,8 @@ namespace watchfuleye { } case WM_TRAYICON: { - if (LOWORD(lParam) == WM_RBUTTONDOWN) { + if (LOWORD(lParam) == WM_LBUTTONDOWN || + LOWORD(lParam) == WM_RBUTTONDOWN) { SetForegroundWindow(dlg); POINT cursor = {}; @@ -106,6 +119,18 @@ namespace watchfuleye { RECT clientRect = {}; GetClientRect(dlg, &clientRect); + + HBRUSH backgroundBrush = nullptr; + + if (!app->m_active) + backgroundBrush = greenBackgroundBrush; + + else if (app->m_overTime) + backgroundBrush = redBackgroundBrush; + + else + backgroundBrush = yellowBackgroundBrush; + FillRect(hDC, &clientRect, backgroundBrush); return TRUE; @@ -141,17 +166,29 @@ namespace watchfuleye { RECT timeRect = {}; GetClientRect(dlg, &timeRect); - timeRect.top += 15, timeRect.bottom += 15; + timeRect.top -= 25, timeRect.bottom -= 25; SetTextColor(hDC, RGB(0, 0, 0)); SetBkMode(hDC, TRANSPARENT); SelectObject(hDC, timeFont); Seconds elapsed = Duration(Clock::now() - app->m_startTime).count(); + if (!app->m_active) + elapsed = 0; + Seconds remaining = app->m_maxMinutes * 60 - elapsed; - unsigned int minutes = remaining % (3600) / 60, seconds = remaining % 60; + if (app->m_overTime) { + SetDlgItemText(dlg, IDC_STATICLOWER, "Please Eject Your USB"); + DrawText(hDC, "STOP", -1, &timeRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER); + } + else { + SetDlgItemText(dlg, IDC_STATICLOWER, "Time Remaining on Tester"); + unsigned int minutes = remaining % (3600) / 60, seconds = remaining % 60; + DrawText(hDC, std::format("{:02}:{:02}", minutes, seconds).c_str(), -1, &timeRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER); + } - DrawText(hDC, std::format("{:02}:{:02}", minutes, seconds).c_str(), -1, &timeRect, DT_SINGLELINE | DT_NOCLIP | DT_CENTER | DT_VCENTER); + if (remaining <= 0) + app->m_overTime = true; EndPaint(dlg, &ps); return TRUE; @@ -186,7 +223,23 @@ namespace watchfuleye { Shell_NotifyIcon(NIM_ADD, &iconData); } - Application::~Application() { + void Application::queryThreadFunction() { + char buff[100] = {}; + while (m_running) { + bool driveDetected = QueryDosDevice(m_drive, buff, 100) > 0; + + if (driveDetected && !m_active) { + m_active = true; + m_startTime = Clock::now(); + } + + else if (!driveDetected && m_active) { + m_active = false; + m_overTime = false; + } + + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } } } diff --git a/WatchfulEye/src/Application.h b/WatchfulEye/src/Application.h index d06df94..ed79e65 100644 --- a/WatchfulEye/src/Application.h +++ b/WatchfulEye/src/Application.h @@ -8,20 +8,26 @@ namespace watchfuleye { using Seconds = int; public: - Application(const char* appName, const char* appVersion, unsigned int maximumMinutes); + Application(const char* appName, const char* appVersion, unsigned int maximumMinutes, const char* driveToDetect); void run(); - - ~Application(); private: static BOOL CALLBACK mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam); void createTrayIcon(); + void queryThreadFunction(); + std::string m_appName, m_appVersion; HWND m_mainDlg; + bool m_running; // Is the application running? + bool m_active; // Is the timer ticking? + bool m_overTime; // Are we out of time? + unsigned int m_maxMinutes; + const char* m_drive; + TimePoint m_startTime; }; } diff --git a/WatchfulEye/src/main.cpp b/WatchfulEye/src/main.cpp index 694d756..8fbd1da 100644 --- a/WatchfulEye/src/main.cpp +++ b/WatchfulEye/src/main.cpp @@ -11,9 +11,12 @@ processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #define APPNAME "Watchful Eye" +#define MAX_MINUTES 1 +#define DRIVE_TO_DETECT "E:" + int main(int argc, char* argv[]) { { - watchfuleye::Application app(APPNAME, APPVERSION, 15); + watchfuleye::Application app(APPNAME, APPVERSION, MAX_MINUTES, DRIVE_TO_DETECT); app.run(); } diff --git a/WatchfulEye/src/pch.h b/WatchfulEye/src/pch.h index 88bb500..26531e0 100644 --- a/WatchfulEye/src/pch.h +++ b/WatchfulEye/src/pch.h @@ -5,6 +5,7 @@ #include #include #include +#include // Windows #define WIN32_LEAN_AND_MEAN diff --git a/WatchfulEye/src/resource.h b/WatchfulEye/src/resource.h index 246a80c..1c5bc4b 100644 --- a/WatchfulEye/src/resource.h +++ b/WatchfulEye/src/resource.h @@ -3,7 +3,7 @@ // Used by C:\Users\Grayson\Documents\Visual Studio 18\Solutions\watchful-eye\WatchfulEye\resource.rc // #define IDD_DIALOGMAIN 101 -#define IDC_STATICUPPER 1000 +#define IDC_STATICLOWER 1000 // Next default values for new objects //