#include "win.h"\r
#include "ws.h"\r
\r
-#include "../res/resource.h"\r
-\r
#define LAY_IMPLEMENTATION\r
#include "layout.h"\r
\r
+#include <fstream>\r
+#include <vector>\r
+#include <string>\r
+\r
#include <Psapi.h>\r
#include <stdbool.h>\r
#include <stdio.h>\r
#include <windows.h>\r
#include <shlwapi.h>\r
\r
+bool recording = false;\r
+HANDLE process = NULL;\r
+HWND hwnd;\r
+HINSTANCE hInstance;\r
+HICON icon_white, icon_green, icon_red;\r
+\r
+std::vector<std::string> gameExes;\r
+\r
+\r
+NOTIFYICONDATAA niData = { 0 };\r
+const UINT ICON_MSG = WM_APP+1;\r
+void\r
+ShowNotificationIcon()\r
+{\r
+ Shell_NotifyIconA(NIM_ADD, &niData);\r
+ Shell_NotifyIconA(NIM_SETVERSION, &niData);\r
+}\r
+\r
+void\r
+HideNotificationIcon()\r
+{\r
+ Shell_NotifyIconA(NIM_DELETE, &niData);\r
+}\r
+\r
+void changeIcon(HWND hwnd, HICON icon)\r
+{\r
+ niData.hIcon = icon;\r
+ if (! IsWindowVisible(hwnd))\r
+ Shell_NotifyIconA(NIM_MODIFY, &niData);\r
+ SendMessage(hwnd, WM_SETICON, 0, (LPARAM)icon);\r
+ SendMessage(hwnd, WM_SETICON, 1, (LPARAM)icon);\r
+}\r
+\r
+\r
+\r
void\r
startRecording()\r
{\r
- MessageBoxA(NULL, "Start", "Start Start", MB_OK);\r
+ ws::sendRequest("StartRecord");\r
+ changeIcon(hwnd, icon_green);\r
}\r
\r
void\r
stopRecording()\r
{\r
- MessageBoxA(NULL, "Stop", "Stop Stop", MB_OK);\r
+ ws::sendRequest("StopRecord");\r
+ changeIcon(hwnd, icon_red);\r
}\r
\r
bool\r
}\r
\r
bool\r
-checkNotepadWindow()\r
+checkForegroundProcess(std::string exeName)\r
{\r
HWND fgHwnd = GetForegroundWindow();\r
HANDLE fgHandle = getHwndProcess(fgHwnd);\r
\r
- char filename[1024];\r
- int len = GetModuleFileNameExA(fgHandle, NULL, filename, 1024);\r
+ char filename[MAX_PATH];\r
+ int len = GetModuleFileNameExA(fgHandle, NULL, filename, MAX_PATH);\r
+\r
+ if (strcmp(filename, exeName.c_str()) == 0)\r
+ return true;\r
+\r
+ PathStripPathA(filename);\r
+\r
+ return strcmp(filename, exeName.c_str()) == 0;\r
+}\r
+\r
+void ReadGameExes()\r
+{\r
+ std::ifstream ifs("games.txt");\r
+\r
+ gameExes.clear();\r
+\r
+ while (ifs) {\r
+ std::string str;\r
+ std::getline(ifs, str);\r
+ if (! str.empty())\r
+ gameExes.push_back(str);\r
+ }\r
+\r
+ ifs.close();\r
+}\r
+\r
+void WriteGameExes()\r
+{\r
+ std::ofstream ofs("games.txt", std::ios::trunc);\r
+\r
+ for (const auto &exe : gameExes)\r
+ {\r
+ ofs.write(exe.c_str(), exe.size());\r
+ ofs.write("\n", 1);\r
+ }\r
+\r
+ ofs.close();\r
+}\r
+\r
+PROCESS_INFORMATION StartOBS()\r
+{\r
+ // delete .sentinel folder to stop obs from displaying\r
+ // error message on startup\r
+ system("del %appdata%\\obs-studio\\.sentinel /Q");\r
+\r
+ PROCESS_INFORMATION pi;\r
+ STARTUPINFOA sui;\r
+ GetStartupInfoA(&sui);\r
+ CreateProcessA(nullptr, "C:\\Program Files\\obs-studio\\bin\\64bit\\obs64.exe",\r
+ nullptr, nullptr, false, NORMAL_PRIORITY_CLASS, nullptr, "C:\\Program Files\\obs-studio\\bin\\64bit", &sui, &pi);\r
+ return pi;\r
+}\r
+\r
+void StopOBS(PROCESS_INFORMATION &pi)\r
+{\r
+ EnumWindows([](HWND hwnd, LPARAM lParam) -> BOOL {\r
+ PROCESS_INFORMATION *pi = (PROCESS_INFORMATION*)lParam;\r
+\r
+ DWORD pid, tid;\r
+ tid = GetWindowThreadProcessId(hwnd, &pid);\r
+ if (tid == pi->dwThreadId && pid == pi->dwProcessId) {\r
+\r
+ char title[1024]; GetWindowTextA(hwnd, title, 1024);\r
\r
- return strcmp(filename, "C:\\Windows\\System32\\notepad.exe") == 0;\r
+ if (strncmp(title, "OBS", 3) == 0) {\r
+ PostMessage(hwnd, WM_CLOSE, 0, 0);\r
+ return FALSE; \r
+ }\r
+ }\r
+ return TRUE;\r
+ }, (LPARAM)&pi);\r
}\r
\r
+/*\r
+TODO:\r
+ - Disconnect while recording\r
+*/\r
+\r
+\r
\r
int WINAPI\r
WinMain(HINSTANCE hInstance,\r
HINSTANCE hPrevInstance,\r
LPSTR lpCmdLine,\r
int nCmdShow)\r
+//int main(int argc, char **argv)\r
{\r
- bool recording = false;\r
- HANDLE process = NULL;\r
-\r
- HWND window = win::Window("Title", "MyWindowClass", hInstance);\r
-\r
- lay_id row1 = lay_item(&win::_::ctx);\r
- lay_insert(&win::_::ctx, win::_::root, row1);\r
- lay_set_size_xy(&win::_::ctx, row1, 0, 25);\r
- lay_set_behave(&win::_::ctx, row1, LAY_LEFT);\r
- lay_set_contain(&win::_::ctx, row1, LAY_ROW);\r
- lay_set_margins_ltrb(&win::_::ctx, row1, 5, 5, 5, 5);\r
- lay_id row2 = lay_item(&win::_::ctx);\r
- lay_insert(&win::_::ctx, win::_::root, row2);\r
- lay_set_size_xy(&win::_::ctx, row2, 0, 0);\r
- lay_set_behave(&win::_::ctx, row2, LAY_FILL);\r
- lay_set_contain(&win::_::ctx, row2, LAY_ROW);\r
- lay_id col1 = lay_item(&win::_::ctx);\r
- lay_set_size_xy(&win::_::ctx, col1, 80, 0);\r
- lay_set_behave(&win::_::ctx, col1, LAY_VCENTER);\r
- lay_set_contain(&win::_::ctx, col1, LAY_COLUMN);\r
- lay_set_margins_ltrb(&win::_::ctx, col1, 5, 0, 5, 0);\r
-\r
- HWND cbWindowTitle = win::CheckBox(window, "Window Title", row1, 100, 25, 0, 0);\r
- HWND cbFullscreenWindow = win::CheckBox(window, "Any Fullscreen Application", row1, 200, 25, 0, 0);\r
-\r
- HWND btnConnect = win::Button(window, "Connect", row1, 100, 25, 0, 0);\r
- win::Callback(btnConnect, BN_CLICKED, [&]() {\r
- ws::connect("ws://127.0.0.1:4444");\r
+ hInstance = GetModuleHandle(0);\r
+\r
+ icon_white = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_WHITE));\r
+ icon_green = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_GREEN));\r
+ icon_red = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_RED));\r
+\r
+ win::Window window("Title", "MyWindowClass", hInstance);\r
+ hwnd = window.hwnd;\r
+\r
+ niData.cbSize = sizeof(niData);\r
+ niData.uID = 12345;\r
+ niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\r
+ niData.hIcon = icon_white;\r
+ niData.hWnd = window.hwnd;\r
+ niData.uCallbackMessage = ICON_MSG;\r
+ niData.uVersion = NOTIFYICON_VERSION_4;\r
+\r
+ PROCESS_INFORMATION pi_obs = StartOBS();\r
+\r
+ window.handlers[WM_SIZE].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ if (wParam == SIZE_MINIMIZED) {\r
+ ShowNotificationIcon();\r
+ ShowWindow(hwnd, false);\r
+ }\r
});\r
- \r
- HWND btnIdentify = win::Button(window, "Identify", row1, 100, 25, 0, 0);\r
- win::Callback(btnIdentify, BN_CLICKED, [&]() {\r
- ws::identify();\r
+ window.handlers[WM_DESTROY].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ HideNotificationIcon();\r
+ }); \r
+ window.handlers[ICON_MSG].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ if (LOWORD(lParam) == NIN_SELECT) {\r
+ HideNotificationIcon();\r
+ ShowWindow(hwnd, true);\r
+ SetForegroundWindow(hwnd);\r
+ SetActiveWindow(hwnd);\r
+ }\r
});\r
-\r
- win::Callback(cbWindowTitle, BN_CLICKED, [&]() {\r
- SendMessageA(cbWindowTitle, BM_SETCHECK, SendMessageA(cbWindowTitle, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0);\r
+ window.handlers[WM_GETMINMAXINFO].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;\r
+ mmInfo->ptMinTrackSize.x = 400;\r
+ mmInfo->ptMinTrackSize.y = 200;\r
});\r
- win::Callback(cbFullscreenWindow, BN_CLICKED, [&]() {\r
- SendMessageA(cbFullscreenWindow, BM_SETCHECK, SendMessageA(cbFullscreenWindow, BM_GETCHECK, 0, 0) ? BST_UNCHECKED : BST_CHECKED, 0);\r
+ window.handlers[WM_QUERYENDSESSION].push_back([&pi_obs](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ StopOBS(pi_obs);\r
+ }); window.handlers[WM_ENDSESSION].push_back([&pi_obs](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ StopOBS(pi_obs);\r
+ });\r
+ window.handlers[WM_CLOSE].push_back([&pi_obs](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
+ StopOBS(pi_obs);\r
+ });\r
+\r
+ lay_context *ctx = &window.ctx;\r
+ lay_id root = window.lId;\r
+\r
+ lay_id row1 = win::createLayId(&window.ctx, window.lId, 0, 25, LAY_ROW, LAY_LEFT);\r
+ lay_set_margins_ltrb(ctx, row1, 5, 5, 5, 5);\r
+ lay_id row2 = win::createLayId(&window.ctx, window.lId, 0, 0, LAY_ROW, LAY_FILL);\r
+ lay_set_margins_ltrb(ctx, row2, 5, 5, 5, 5);\r
+\r
+ win::CheckBox cbWindowTitle(&window, "Window Title", row1, 100, 25, 0, 0);\r
+ win::CheckBox cbFullscreenWindow(&window, "Any Fullscreen Application", row1, 200, 25, 0, 0);\r
+\r
+ win::Button btnConnect(&window, "Connect", row1, 100, 25, 0, 0);\r
+ btnConnect.onClick([&]() {\r
+ if (! ws::isConnected)\r
+ ws::connect("ws://127.0.0.1:4455");\r
});\r
\r
- HWND lstActiveProcesses = win::ListBox(window, row2, 0, 0, 0, LAY_FILL);\r
- lay_insert(&win::_::ctx, row2, col1);\r
- HWND lstMonitoredProcesses = win::ListBox(window, row2, 0, 0, 0, LAY_FILL);\r
- win::AddStyle(lstActiveProcesses, WS_VSCROLL);\r
- win::AddStyle(lstMonitoredProcesses, WS_VSCROLL);\r
-\r
- HWND btnUpdateWindows = win::Button(window, "Update", col1, 85, 25, 0, 0);\r
- HWND btnStartMonitoringName = win::Button(window, "Exe name >>", col1, 85, 25, 0, 0);\r
- HWND btnStartMonitoringPath = win::Button(window, "Full path >>", col1, 85, 25, 0, 0);\r
- HWND btnStopMonitoring = win::Button(window, "Remove", col1, 85, 25, 0, 0);\r
- win::Callback(btnUpdateWindows, BN_CLICKED, [&]() {\r
- win::ListClear(lstActiveProcesses);\r
+ win::ListBox lstActiveProcesses(&window, row2, 0, 0, 0, LAY_FILL);\r
+ \r
+ lay_id col1 = win::createLayId(&window.ctx, row2, 80, 0, LAY_COLUMN, LAY_VCENTER);\r
+ lstActiveProcesses.addStyle(WS_VSCROLL);\r
+\r
+ lay_set_margins_ltrb(ctx, col1, 5, 0, 5, 0);\r
+\r
+ win::ListBox lstMonitoredProcesses(&window, row2, 0, 0, 0, LAY_FILL);\r
+ lstMonitoredProcesses.addStyle(WS_VSCROLL);\r
+\r
+ ReadGameExes();\r
+ for (const auto &exe : gameExes)\r
+ lstMonitoredProcesses.addString(exe);\r
+\r
+ win::Button btnUpdateWindows(&window, "Update", col1, 85, 25, 0, 0);\r
+ win::Button btnStartMonitoringName(&window, "Exe name >>", col1, 85, 25, 0, 0);\r
+ win::Button btnStartMonitoringPath(&window, "Full path >>", col1, 85, 25, 0, 0);\r
+ win::Button btnStopMonitoring(&window, "Remove", col1, 85, 25, 0, 0);\r
+ btnUpdateWindows.onClick([&]() {\r
+ lstActiveProcesses.clear();\r
for (HWND hwnd = GetTopWindow(NULL); hwnd != nullptr;\r
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) {\r
if (!IsWindowVisible(hwnd))\r
\r
char str[1024];\r
if (GetModuleFileNameExA(getHwndProcess(hwnd), 0, str, 1024) != 0 &&\r
- win::ListFindString(lstActiveProcesses, str) == LB_ERR) {\r
- win::ListAddString(lstActiveProcesses, str);\r
+ lstActiveProcesses.findString(str) == LB_ERR) {\r
+ lstActiveProcesses.addString(str);\r
}\r
}\r
});\r
- win::Callback(btnStartMonitoringName, BN_CLICKED, [&]() {\r
- int sel = win::ListGetSelectedIndex(lstActiveProcesses);\r
+ btnStartMonitoringName.onClick([&]() {\r
+ int sel = lstActiveProcesses.getSelectedIndex();\r
if (sel < 0) return;\r
\r
- std::string selStr = win::ListGetText(lstActiveProcesses, sel);\r
+ std::string selStr = lstActiveProcesses.getText(sel);\r
\r
- char *filename = new char[selStr.size()];\r
+ char *filename = new char[selStr.size()+1];\r
std::memcpy(filename, selStr.c_str(), selStr.size());\r
+ filename[selStr.size()] = '\0';\r
PathStripPathA(filename);\r
\r
- if (win::ListFindString(lstMonitoredProcesses, std::string(filename)) == LB_ERR)\r
- win::ListAddString(lstMonitoredProcesses, std::string(filename));\r
+ std::string filenameStr(filename);\r
+\r
+ if (lstMonitoredProcesses.findString(filenameStr) == LB_ERR)\r
+ {\r
+ lstMonitoredProcesses.addString(filenameStr);\r
+ gameExes.push_back(filenameStr);\r
+ WriteGameExes();\r
+ }\r
\r
delete[] filename;\r
});\r
- win::Callback(btnStartMonitoringPath, BN_CLICKED, [&]() {\r
- int sel = win::ListGetSelectedIndex(lstActiveProcesses);\r
+ btnStartMonitoringPath.onClick([&]() {\r
+ int sel = lstActiveProcesses.getSelectedIndex();\r
if (sel < 0) return;\r
- std::string selStr = win::ListGetText(lstActiveProcesses, sel);\r
- if (win::ListFindString(lstMonitoredProcesses, selStr) == LB_ERR)\r
- win::ListAddString(lstMonitoredProcesses, selStr);\r
+ std::string selStr = lstActiveProcesses.getText(sel);\r
+ if (lstMonitoredProcesses.findString(selStr) == LB_ERR)\r
+ {\r
+ lstMonitoredProcesses.addString(selStr);\r
+ gameExes.push_back(selStr);\r
+ WriteGameExes(); \r
+ }\r
});\r
- win::Callback(btnStopMonitoring, BN_CLICKED, [&]() {\r
- int sel = win::ListGetSelectedIndex(lstMonitoredProcesses);\r
+ btnStopMonitoring.onClick([&]() {\r
+ int sel = lstMonitoredProcesses.getSelectedIndex();\r
if (sel < 0) return;\r
- win::ListRemove(lstMonitoredProcesses, sel);\r
+ lstMonitoredProcesses.remove(sel);\r
+ gameExes.erase(gameExes.begin() + sel);\r
+ WriteGameExes();\r
});\r
\r
-\r
- win::ShowNotificationIcon(hInstance, window);\r
-\r
- win::ShowWindow(window);\r
-\r
+ window.show();\r
+ window.setDefaultFont();\r
+\r
+ ws::onConnect = [&]() {\r
+ changeIcon(window.hwnd, icon_red);\r
+ btnConnect.setActive(false);\r
+ };\r
+ ws::onClose = [&]() {\r
+ changeIcon(window.hwnd, icon_white);\r
+ btnConnect.setActive(true);\r
+ };\r
+ ws::onError = ws::onClose;\r
ws::init();\r
\r
- while (win::UpdateWindow(window)) {\r
- ws::update();\r
+ window.setTimer(1000, [&btnConnect]() {\r
+ if (! ws::isConnected)\r
+ ws::connect("ws://127.0.0.1:4455");\r
+ });\r
\r
+ window.setTimer(100, []() {\r
if (!recording) {\r
- if (checkNotepadWindow()) {\r
- process = getHwndProcess(GetForegroundWindow());\r
- startRecording();\r
- recording = true;\r
+ for (auto exe : gameExes) {\r
+ if (checkForegroundProcess(exe)) {\r
+ recording = true;\r
+ process = getHwndProcess(GetForegroundWindow());\r
+ startRecording();\r
+ } \r
}\r
} else {\r
if (!checkProcessRunning(process)) {\r
+ recording = false;\r
process = NULL;\r
stopRecording();\r
- recording = false;\r
}\r
}\r
+ });\r
+\r
+ while (window.update()) {\r
+ ws::update();\r
}\r
+\r
+ return 0;\r
}\r