]> gitweb.ps.run Git - autorec/blob - src/main.cpp
Why didnt I commit these
[autorec] / src / main.cpp
1 #ifndef WIN32\r
2   #define WIN32\r
3 #endif\r
4 #include <WinSock2.h>\r
5 #include "win.h"\r
6 #include "ws.h"\r
7 \r
8 #define LAY_IMPLEMENTATION\r
9 #include "layout.h"\r
10 \r
11 #include <fstream>\r
12 #include <vector>\r
13 #include <string>\r
14 \r
15 #include <Psapi.h>\r
16 #include <stdbool.h>\r
17 #include <stdio.h>\r
18 #include <string.h>\r
19 #include <windows.h>\r
20 #include <shlwapi.h>\r
21 \r
22 bool recording = false;\r
23 HANDLE process = NULL;\r
24 HWND hwnd;\r
25 HINSTANCE hInstance;\r
26 HICON icon_white, icon_green, icon_red;\r
27 \r
28 std::vector<std::string> gameExes;\r
29 \r
30 \r
31 NOTIFYICONDATAA niData = { 0 };\r
32 const UINT ICON_MSG = WM_APP+1;\r
33 void\r
34 ShowNotificationIcon()\r
35 {\r
36   Shell_NotifyIconA(NIM_ADD, &niData);\r
37   Shell_NotifyIconA(NIM_SETVERSION, &niData);\r
38 }\r
39 \r
40 void\r
41 HideNotificationIcon()\r
42 {\r
43   Shell_NotifyIconA(NIM_DELETE, &niData);\r
44 }\r
45 \r
46 void changeIcon(HWND hwnd, HICON icon)\r
47 {\r
48   niData.hIcon = icon;\r
49   if (! IsWindowVisible(hwnd))\r
50     Shell_NotifyIconA(NIM_MODIFY, &niData);\r
51   SendMessage(hwnd, WM_SETICON, 0, (LPARAM)icon);\r
52   SendMessage(hwnd, WM_SETICON, 1, (LPARAM)icon);\r
53 }\r
54 \r
55 \r
56 \r
57 void\r
58 startRecording()\r
59 {\r
60   ws::sendRequest("StartRecord");\r
61   changeIcon(hwnd, icon_green);\r
62 }\r
63 \r
64 void\r
65 stopRecording()\r
66 {\r
67   ws::sendRequest("StopRecord");\r
68   changeIcon(hwnd, icon_red);\r
69 }\r
70 \r
71 bool\r
72 checkProcessRunning(HANDLE handle)\r
73 {\r
74   DWORD exit_code;\r
75 \r
76   if (handle != NULL && GetExitCodeProcess(handle, &exit_code)) {\r
77     return exit_code == STILL_ACTIVE;\r
78   }\r
79 \r
80   return false;\r
81 }\r
82 \r
83 HANDLE\r
84 getHwndProcess(HWND hwnd)\r
85 {\r
86   DWORD processId, threadId = GetWindowThreadProcessId(hwnd, &processId);\r
87   return OpenProcess(PROCESS_QUERY_INFORMATION, false, processId);\r
88 }\r
89 \r
90 // HWND getProcessHwnd(HANDLE handle) {}\r
91 \r
92 bool\r
93 checkFullscreenWindow()\r
94 {\r
95   HWND desktopHwnd = GetDesktopWindow();\r
96   HWND fgHwnd = GetForegroundWindow();\r
97 \r
98   if (fgHwnd != desktopHwnd && fgHwnd != GetShellWindow()) {\r
99     RECT windowRect, desktopRect;\r
100     // Get Window and Desktop size\r
101     GetWindowRect(fgHwnd, &windowRect);\r
102     GetWindowRect(desktopHwnd, &desktopRect);\r
103 \r
104     bool fullscreen = windowRect.bottom == desktopRect.bottom &&\r
105                       windowRect.top == desktopRect.top &&\r
106                       windowRect.left == desktopRect.left &&\r
107                       windowRect.right == desktopRect.right;\r
108 \r
109     return fullscreen;\r
110   }\r
111 \r
112   return false;\r
113 }\r
114 \r
115 bool\r
116 checkForegroundProcess(std::string exeName)\r
117 {\r
118   HWND fgHwnd = GetForegroundWindow();\r
119   HANDLE fgHandle = getHwndProcess(fgHwnd);\r
120 \r
121   char filename[MAX_PATH];\r
122   int len = GetModuleFileNameExA(fgHandle, NULL, filename, MAX_PATH);\r
123 \r
124   if (strcmp(filename, exeName.c_str()) == 0)\r
125     return true;\r
126 \r
127   PathStripPathA(filename);\r
128 \r
129   return strcmp(filename, exeName.c_str()) == 0;\r
130 }\r
131 \r
132 void ReadGameExes()\r
133 {\r
134   std::ifstream ifs("games.txt");\r
135 \r
136   gameExes.clear();\r
137 \r
138   while (ifs) {\r
139     std::string str;\r
140     std::getline(ifs, str);\r
141     if (! str.empty())\r
142       gameExes.push_back(str);\r
143   }\r
144 \r
145   ifs.close();\r
146 }\r
147 \r
148 void WriteGameExes()\r
149 {\r
150   std::ofstream ofs("games.txt", std::ios::trunc);\r
151 \r
152   for (const auto &exe : gameExes)\r
153   {\r
154     ofs.write(exe.c_str(), exe.size());\r
155     ofs.write("\n", 1);\r
156   }\r
157 \r
158   ofs.close();\r
159 }\r
160 \r
161 /*\r
162 TODO:\r
163   - Disconnect while recording\r
164 */\r
165 \r
166 \r
167 \r
168 int WINAPI\r
169 WinMain(HINSTANCE hInstance,\r
170         HINSTANCE hPrevInstance,\r
171         LPSTR lpCmdLine,\r
172         int nCmdShow)\r
173 //int main(int argc, char **argv)\r
174 {\r
175   hInstance = GetModuleHandle(0);\r
176 \r
177   icon_white = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_WHITE));\r
178   icon_green = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_GREEN));\r
179   icon_red = LoadIconA(hInstance, MAKEINTRESOURCEA(IDI_ICON_RED));\r
180 \r
181   win::Window window("Title", "MyWindowClass", hInstance);\r
182   hwnd = window.hwnd;\r
183 \r
184   niData.cbSize = sizeof(niData);\r
185   niData.uID = 12345;\r
186   niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;\r
187   niData.hIcon = icon_white;\r
188   niData.hWnd = window.hwnd;\r
189   niData.uCallbackMessage = ICON_MSG;\r
190   niData.uVersion = NOTIFYICON_VERSION_4;\r
191 \r
192   window.handlers[WM_SIZE].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
193     if (wParam == SIZE_MINIMIZED) {\r
194       ShowNotificationIcon();\r
195       ShowWindow(hwnd, false);\r
196     }\r
197   });\r
198   window.handlers[WM_DESTROY].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
199     HideNotificationIcon();\r
200   });  \r
201   window.handlers[ICON_MSG].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
202     if (LOWORD(lParam) == NIN_SELECT) {\r
203       HideNotificationIcon();\r
204       ShowWindow(hwnd, true);\r
205       SetForegroundWindow(hwnd);\r
206       SetActiveWindow(hwnd);\r
207     }\r
208   });\r
209 \r
210   window.handlers[WM_GETMINMAXINFO].push_back([](HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {\r
211           MINMAXINFO *mmInfo = (MINMAXINFO*)lParam;\r
212           mmInfo->ptMinTrackSize.x = 400;\r
213           mmInfo->ptMinTrackSize.y = 200;\r
214   });\r
215 \r
216   lay_context *ctx = &window.ctx;\r
217   lay_id root = window.lId;\r
218 \r
219   lay_id row1 = win::createLayId(&window.ctx, window.lId, 0, 25, LAY_ROW, LAY_LEFT);\r
220   lay_set_margins_ltrb(ctx, row1, 5, 5, 5, 5);\r
221   lay_id row2 = win::createLayId(&window.ctx, window.lId, 0, 0, LAY_ROW, LAY_FILL);\r
222   lay_set_margins_ltrb(ctx, row2, 5, 5, 5, 5);\r
223 \r
224   win::CheckBox cbWindowTitle(&window, "Window Title", row1, 100, 25, 0, 0);\r
225   win::CheckBox cbFullscreenWindow(&window, "Any Fullscreen Application", row1, 200, 25, 0, 0);\r
226 \r
227   win::Button btnConnect(&window, "Connect", row1, 100, 25, 0, 0);\r
228   btnConnect.onClick([&]() {\r
229     if (! ws::isConnected)\r
230       ws::connect("ws://127.0.0.1:4455");\r
231   });\r
232 \r
233   win::ListBox lstActiveProcesses(&window, row2, 0, 0, 0, LAY_FILL);\r
234   \r
235   lay_id col1 = win::createLayId(&window.ctx, row2, 80, 0, LAY_COLUMN, LAY_VCENTER);\r
236   lstActiveProcesses.addStyle(WS_VSCROLL);\r
237 \r
238   lay_set_margins_ltrb(ctx, col1, 5, 0, 5, 0);\r
239 \r
240   win::ListBox lstMonitoredProcesses(&window, row2, 0, 0, 0, LAY_FILL);\r
241   lstMonitoredProcesses.addStyle(WS_VSCROLL);\r
242 \r
243   ReadGameExes();\r
244   for (const auto &exe : gameExes)\r
245     lstMonitoredProcesses.addString(exe);\r
246 \r
247   win::Button btnUpdateWindows(&window, "Update", col1, 85, 25, 0, 0);\r
248   win::Button btnStartMonitoringName(&window, "Exe name >>", col1, 85, 25, 0, 0);\r
249   win::Button btnStartMonitoringPath(&window, "Full path >>", col1, 85, 25, 0, 0);\r
250   win::Button btnStopMonitoring(&window, "Remove", col1, 85, 25, 0, 0);\r
251   btnUpdateWindows.onClick([&]() {\r
252     lstActiveProcesses.clear();\r
253     for (HWND hwnd = GetTopWindow(NULL); hwnd != nullptr;\r
254          hwnd = GetNextWindow(hwnd, GW_HWNDNEXT)) {\r
255       if (!IsWindowVisible(hwnd))\r
256         continue;\r
257 \r
258       RECT rect;\r
259       GetWindowRect(hwnd, &rect);\r
260 \r
261       char str[1024];\r
262       if (GetModuleFileNameExA(getHwndProcess(hwnd), 0, str, 1024) != 0 &&\r
263           lstActiveProcesses.findString(str) == LB_ERR) {\r
264         lstActiveProcesses.addString(str);\r
265       }\r
266     }\r
267   });\r
268   btnStartMonitoringName.onClick([&]() {\r
269     int sel = lstActiveProcesses.getSelectedIndex();\r
270     if (sel < 0) return;\r
271 \r
272     std::string selStr = lstActiveProcesses.getText(sel);\r
273     \r
274     char *filename = new char[selStr.size()+1];\r
275     std::memcpy(filename, selStr.c_str(), selStr.size());\r
276     filename[selStr.size()] = '\0';\r
277     PathStripPathA(filename);\r
278 \r
279     std::string filenameStr(filename);\r
280 \r
281     if (lstMonitoredProcesses.findString(filenameStr) == LB_ERR)\r
282     {\r
283       lstMonitoredProcesses.addString(filenameStr);\r
284       gameExes.push_back(filenameStr);\r
285       WriteGameExes();\r
286     }\r
287 \r
288     delete[] filename;\r
289   });\r
290   btnStartMonitoringPath.onClick([&]() {\r
291     int sel = lstActiveProcesses.getSelectedIndex();\r
292     if (sel < 0) return;\r
293     std::string selStr = lstActiveProcesses.getText(sel);\r
294     if (lstMonitoredProcesses.findString(selStr) == LB_ERR)\r
295     {\r
296       lstMonitoredProcesses.addString(selStr);\r
297       gameExes.push_back(selStr);\r
298       WriteGameExes();  \r
299     }\r
300   });\r
301   btnStopMonitoring.onClick([&]() {\r
302     int sel = lstMonitoredProcesses.getSelectedIndex();\r
303     if (sel < 0) return;\r
304     lstMonitoredProcesses.remove(sel);\r
305     gameExes.erase(gameExes.begin() + sel);\r
306     WriteGameExes();\r
307   });\r
308 \r
309   window.show();\r
310   window.setDefaultFont();\r
311 \r
312   ws::onConnect = [&]() {\r
313     changeIcon(window.hwnd, icon_red);\r
314     btnConnect.setActive(false);\r
315   };\r
316   ws::onClose = [&]() {\r
317     changeIcon(window.hwnd, icon_white);\r
318     btnConnect.setActive(true);\r
319   };\r
320   ws::onError = ws::onClose;\r
321   ws::init();\r
322 \r
323   window.setTimer(1000, [&btnConnect]() {\r
324     if (! ws::isConnected)\r
325       ws::connect("ws://127.0.0.1:4455");\r
326   });\r
327 \r
328   window.setTimer(100, []() {\r
329     if (!recording) {\r
330       for (auto exe : gameExes) {\r
331         if (checkForegroundProcess(exe)) {\r
332           recording = true;\r
333           process = getHwndProcess(GetForegroundWindow());\r
334           startRecording();\r
335         } \r
336       }\r
337     } else {\r
338       if (!checkProcessRunning(process)) {\r
339         recording = false;\r
340         process = NULL;\r
341         stopRecording();\r
342       }\r
343     }\r
344   });\r
345 \r
346   while (window.update()) {\r
347     ws::update();\r
348   }\r
349 \r
350   return 0;\r
351 }\r