Skip to content

Commit f3ff4a6

Browse files
authored
Merge pull request #1 from 321Proteus/development
Feature: Update 1.1 - filenames, Unicode support & more
2 parents a9aa8a4 + c2b5b24 commit f3ff4a6

5 files changed

Lines changed: 141 additions & 12 deletions

File tree

README.md

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# wmw-desktop
22
What's My Window (WMW) is a simple C++ utility for detecting active application from the OS, designed to display activity in code editors in the Internet.
33

4-
WMW uses Windows API to get the foreground window and output its name and elapsed time using the following scheme:
4+
WMW uses Windows API to get the foreground window and output its name and elapsed time using (by default) the following scheme:
55
```
66
MyAppName hh:mm:ss
77
```
@@ -20,18 +20,32 @@ WMW can be widely personalised to the user's needs by changing the values in `se
2020

2121
`unsigned int interval` - the interval between two window requests in miliseconds (default: `1000`)
2222

23+
`string format` - the format of the WMW output.
24+
Available placeholders:
25+
- `%name` - current application name
26+
- `%time` - current application time
27+
- `%pname` - current process name
28+
- `%pid` - current process ID
29+
- `%file` - current file name
30+
- `%project` - current project name
31+
32+
Default: `%name %time`
33+
2334
`string windowStartup` - the text to display on application startup (used for future translation purposes)
2435

2536
`codeEditors` - a list of key/value pairs of the applications' process names and the corresponding window titles\
2637
(Tip: process names can be obtained via the details tab of the Task Manager)
2738

39+
`titleFormats` - a list of key/value pairs of the process names and the corresponding user-defined window title formats, used to detect file and project names.\
40+
(Tip: as formats may contain Unicode characters, detecting them by hand may be difficult. If you're experiencing problems with the title detection, use the debug funtion at lines 112-114 to read the title as integer values letter by letter)
41+
2842
**Remember**: the settings are stored in the WMW binary and you have to rebuild it to apply the changes!
2943

3044
# To Do
3145

32-
- Add file name/project name detection for the code editors - the window title usually contains them
46+
- ~~Add file name/project name detection for the code editors - the window title usually contains them~~
3347
- Improve the example project by making it refresh automatically every second
34-
- Add the ability to personalise the output structure in the config, e.g. adding the process name or the PID
48+
- ~~Add the ability to personalise the output structure in the config, e.g. adding the process name or the PID~~
3549

3650
Feel free to open a pull request if you develop a solution of one of these (new ideas are also welcome)!
3751

example/main.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const { spawn } = require("child_process");
22
const express = require("express");
33

44
const app = express()
5-
const wmw = spawn("test.exe", { stdio: "pipe" });
5+
const wmw = spawn("wmw_1.0-release.exe", { stdio: "pipe" });
66

77
var text = "";
88

main.cpp

Lines changed: 106 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
#include <iostream>
22
#include <string>
3+
#include <regex>
34
#include <windows.h>
5+
#include <io.h>
6+
#include <fcntl.h>
7+
#include <locale>
48

59
#include "settings.hpp"
610
#include "processInfo.cpp"
@@ -9,26 +13,122 @@ using namespace std;
913

1014
activeWindowData previousData;
1115

16+
void formatOutput(wstring& text, activeWindowData data) {
17+
18+
int idx = 0;
19+
20+
wstring time_w(data.time.begin(), data.time.end());
21+
wstring name_w(data.name.begin(), data.name.end());
22+
wstring pname_w(data.pname.begin(), data.pname.end());
23+
string pidString = to_string(data.pid);
24+
wstring pid_w(pidString.begin(), pidString.end());
25+
26+
while (text.find('%') != string::npos) {
27+
28+
idx = text.find('%', idx);
29+
30+
wstring temp = text.substr(idx, 4);
31+
32+
if (temp == L"%pid") text.replace(idx, 4, pid_w);
33+
else if (temp == L"%nam") text.replace(idx, 5, name_w);
34+
else if (temp == L"%tim") text.replace(idx, 5, time_w);
35+
else if (temp == L"%pna") text.replace(idx, 6, pname_w);
36+
else if (temp == L"%fil") text.replace(idx, 5, data.file);
37+
else if (temp == L"%pro") text.replace(idx, 8, data.project);
38+
39+
else break;
40+
41+
}
42+
43+
44+
}
45+
46+
bool getWindowTitleData(wstring& title, wstring format, wstring& file, wstring& project) {
47+
48+
wstring regexString = format;
49+
50+
regexString = regex_replace(regexString, wregex(L"%file"), L"(.*?)");
51+
regexString = L"^" + regex_replace(regexString, wregex(L"%project"), L"(.*?)") + L"$";
52+
53+
//swcout << regexString << L" ";
54+
55+
wsmatch matches;
56+
57+
if (regex_search(title, matches, wregex(regexString))) {
58+
59+
if (matches.size() == 3) {
60+
61+
if (format.find(L"%file") < format.find(L"%project")) {
62+
file = matches[1].str();
63+
project = matches[2].str();
64+
} else {
65+
file = matches[1].str();
66+
project = matches[2].str();
67+
}
68+
69+
return true;
70+
71+
} else if (matches.size() == 2) {
72+
73+
if (format.find(L"%file") != string::npos) {
74+
file = matches[1].str();
75+
} else if (format.find(L"%project") != string::npos) {
76+
project = matches[1].str();
77+
}
78+
79+
return true;
80+
}
81+
}
82+
return false;
83+
84+
}
85+
1286
int main() {
13-
// HWND hwnd = GetConsoleWindow();
14-
// ShowWindow(hwnd, SW_HIDE);
1587

88+
_setmode(_fileno(stdout), 0x40000);
1689

17-
cout << windowStartup << endl;
90+
HWND hwnd = GetConsoleWindow();
91+
ShowWindow(hwnd, SW_HIDE);
1892

1993

94+
cout << windowStartup << endl;
95+
2096
while (true) {
2197

98+
// Open the active window
2299
HWND target = GetForegroundWindow();
23100

24101
// Acquire the application name, time and PID
25102
activeWindowData data = fetchWindowInfo(target);
26-
string fullData = data.name + " " + data.time;
103+
104+
// Get the window title
105+
wchar_t titleBuffer[256]{};
106+
int y = GetWindowTextW(target, titleBuffer, 256);
107+
wstring title(titleBuffer);
108+
109+
110+
/* Debug function to print unicode title letter by letter.
111+
Useful for finding title formats */
112+
// for (auto el : title) {
113+
// cout << (int)el << ' ';
114+
// }
115+
116+
wstring file, project;
117+
118+
// Read file and project information from the title using the corresponding format
119+
getWindowTitleData(title, titleFormats[data.pname], file, project);
120+
121+
data.file = file;
122+
data.project = project;
123+
124+
125+
// Print the found values to the template from settings.hpp
126+
wstring a(format.begin(), format.end());
127+
formatOutput(a, data);
27128

28129
/* Check if the PID is not equal to the previously acquired PID
29130
so the output is only printed when the window changes */
30-
31-
if (data.name != "") cout << fullData << endl;
131+
if (data.name != "") wcout << a << endl;// << file << " " << project << endl;
32132
previousData = data;
33133

34134
Sleep(interval);

processInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ activeWindowData fetchWindowInfo(HWND window) {
7474
info.pid = int(pid);
7575
info.name = appName;
7676
info.time = string(formattedTime);
77+
info.pname = processName;
7778

7879
return info;
7980
}

settings.hpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,22 @@ namespace {
1313

1414

1515
// Translations
16-
string windowStartup = "WMW v1.0 Started\n";
16+
string windowStartup = "WMW v1.1 Started\n";
1717

1818

1919
/* A structure for the fetched windows' data.
20-
Consists of the window name, PID and the calculated window time. */
20+
Consists of the window name, process name, PID and the calculated window time. */
2121
struct activeWindowData {
2222
int pid;
2323
string name;
2424
string time;
25+
string pname;
26+
wstring file;
27+
wstring project;
2528
};
2629

30+
string format = "%name %time";
31+
2732

2833
// A function to format the active window data to an array that could be used by the JS code
2934
string processInfo(activeWindowData data);
@@ -40,4 +45,13 @@ namespace {
4045
{"devenv.exe", "Visual Studio 2019"} // This one has a weird name
4146

4247
};
48+
49+
/* This is the list of applications' window title formats.
50+
Regex definitions are allowed. %file and %project are replaced by (.*?) */
51+
map <string, wstring> titleFormats = {
52+
{"idea64.exe", L"%project \u2013 %file"}, // this one doesn't work for some reason
53+
{"Code.exe", L"%file - %project - Visual Studio Code"},
54+
{"codeblocks.exe", L"%file \\[%project\\] - Code::Blocks 20.03"},
55+
{"devenv.exe", L"%project - Microsoft Visual Studio"}
56+
};
4357
}

0 commit comments

Comments
 (0)