| |
1 /* |
| |
2 * idletrack.c |
| |
3 * |
| |
4 * Authors: mrgentry @ http://www.experts-exchange.com |
| |
5 * Herman Bloggs <hermanator12002@yahoo.com> |
| |
6 * Date: February, 2003 |
| |
7 * Description: Track user inactivity. |
| |
8 * |
| |
9 * Andrew Whewell <awhewell@users.sourceforge.net> - 25th June 2004. Added |
| |
10 * support for GetLastInputInfo under Windows 2000 and above. This avoids having |
| |
11 * IDLETRACK.DLL hook itself into every process on the machine, which makes |
| |
12 * upgrades easier. The hook mechanism is also used by key loggers, so not |
| |
13 * using hooks doesn't put the willys up programs that keep an eye out for |
| |
14 * loggers. |
| |
15 * |
| |
16 * Windows 9x doesn't have GetLastInputInfo - when Gaim runs on these machines |
| |
17 * the code silently falls back onto the old hooking scheme. |
| |
18 */ |
| |
19 #define _WIN32_WINNT 0x0500 |
| |
20 #include "idletrack.h" |
| |
21 |
| |
22 #define EXPORT __declspec(dllexport) |
| |
23 |
| |
24 static HANDLE hMapObject = NULL; |
| |
25 static DWORD *lastTime = NULL; |
| |
26 static HHOOK keyHook = NULL; |
| |
27 static HHOOK mouseHook = NULL; |
| |
28 static HINSTANCE g_hInstance = NULL; |
| |
29 static POINT g_point; |
| |
30 |
| |
31 /* GetLastInputInfo address and module - if g_GetLastInputInfo == NULL then |
| |
32 * we fall back on the old "hook the world" method. GetLastInputInfo was brought |
| |
33 * in with Windows 2000 so Windows 9x will still hook everything. |
| |
34 */ |
| |
35 typedef BOOL (WINAPI *GETLASTINPUTINFO)(LASTINPUTINFO *); |
| |
36 static HMODULE g_user32 = NULL; |
| |
37 static GETLASTINPUTINFO g_GetLastInputInfo = NULL; |
| |
38 |
| |
39 static DWORD* setup_shared_mem() { |
| |
40 BOOL fInit; |
| |
41 |
| |
42 /* Set up the shared memory. */ |
| |
43 hMapObject = CreateFileMapping((HANDLE) 0xFFFFFFFF, /* use paging file */ |
| |
44 NULL, /* no security attributes */ |
| |
45 PAGE_READWRITE, /* read/write access */ |
| |
46 0, /* size: high 32-bits */ |
| |
47 sizeof(DWORD), /* size: low 32-bits */ |
| |
48 "timermem"); /* name of map object */ |
| |
49 |
| |
50 if(hMapObject == NULL) |
| |
51 return NULL; |
| |
52 |
| |
53 /* The first process to attach initializes memory. */ |
| |
54 fInit = (GetLastError() != ERROR_ALREADY_EXISTS); |
| |
55 |
| |
56 /* Get a pointer to the file-mapped shared memory. */ |
| |
57 lastTime = (DWORD*) MapViewOfFile(hMapObject, /* object to map view of */ |
| |
58 FILE_MAP_WRITE, /* read/write access */ |
| |
59 0, /* high offset: map from */ |
| |
60 0, /* low offset: beginning */ |
| |
61 0); /* default: map entire file */ |
| |
62 |
| |
63 if(lastTime == NULL) |
| |
64 return NULL; |
| |
65 |
| |
66 *lastTime = GetTickCount(); |
| |
67 |
| |
68 return lastTime; |
| |
69 } |
| |
70 |
| |
71 |
| |
72 static LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { |
| |
73 if(!(code < 0)) { |
| |
74 if(lastTime == NULL) |
| |
75 lastTime = setup_shared_mem(); |
| |
76 |
| |
77 if(lastTime) |
| |
78 *lastTime = GetTickCount(); |
| |
79 } |
| |
80 return CallNextHookEx(keyHook, code, wParam, lParam); |
| |
81 } |
| |
82 |
| |
83 |
| |
84 static LRESULT CALLBACK MouseProc(int code, WPARAM wParam, LPARAM lParam) { |
| |
85 /* We need to verify that the Mouse pointer has actually moved. */ |
| |
86 if(!(code < 0) && |
| |
87 !((g_point.x == ((MOUSEHOOKSTRUCT*) lParam)->pt.x) && |
| |
88 (g_point.y == ((MOUSEHOOKSTRUCT*) lParam)->pt.y))) { |
| |
89 g_point.x = ((MOUSEHOOKSTRUCT*) lParam)->pt.x; |
| |
90 g_point.y = ((MOUSEHOOKSTRUCT*) lParam)->pt.y; |
| |
91 |
| |
92 if(lastTime == NULL) |
| |
93 lastTime = setup_shared_mem(); |
| |
94 |
| |
95 if(lastTime) |
| |
96 *lastTime = GetTickCount(); |
| |
97 } |
| |
98 return CallNextHookEx(mouseHook, code, wParam, lParam); |
| |
99 } |
| |
100 |
| |
101 |
| |
102 EXPORT DWORD wgaim_get_lastactive() { |
| |
103 DWORD result = 0; |
| |
104 |
| |
105 /* If we have GetLastInputInfo then use it, otherwise use the hooks*/ |
| |
106 if(g_GetLastInputInfo != NULL) { |
| |
107 LASTINPUTINFO lii; |
| |
108 memset(&lii, 0, sizeof(lii)); |
| |
109 lii.cbSize = sizeof(lii); |
| |
110 if(g_GetLastInputInfo(&lii)) { |
| |
111 result = lii.dwTime; |
| |
112 } |
| |
113 } else { |
| |
114 if(lastTime == NULL) |
| |
115 lastTime = setup_shared_mem(); |
| |
116 |
| |
117 if(lastTime) |
| |
118 result = *lastTime; |
| |
119 } |
| |
120 |
| |
121 return result; |
| |
122 } |
| |
123 |
| |
124 |
| |
125 EXPORT BOOL wgaim_set_idlehooks() { |
| |
126 /* Is GetLastInputInfo available?*/ |
| |
127 g_user32 = LoadLibrary("user32.dll"); |
| |
128 if(g_user32) { |
| |
129 g_GetLastInputInfo = (GETLASTINPUTINFO) GetProcAddress(g_user32, "GetLastInputInfo"); |
| |
130 } |
| |
131 |
| |
132 /* If we couldn't find GetLastInputInfo then fall back onto the hooking scheme*/ |
| |
133 if(g_GetLastInputInfo == NULL) { |
| |
134 /* Set up the shared memory.*/ |
| |
135 lastTime = setup_shared_mem(); |
| |
136 if(lastTime == NULL) |
| |
137 return FALSE; |
| |
138 *lastTime = GetTickCount(); |
| |
139 |
| |
140 /* Set up the keyboard hook.*/ |
| |
141 keyHook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, g_hInstance, 0); |
| |
142 if(keyHook == NULL) { |
| |
143 UnmapViewOfFile(lastTime); |
| |
144 CloseHandle(hMapObject); |
| |
145 return FALSE; |
| |
146 } |
| |
147 |
| |
148 /* Set up the mouse hook.*/ |
| |
149 mouseHook = SetWindowsHookEx(WH_MOUSE, MouseProc, g_hInstance, 0); |
| |
150 if(mouseHook == NULL) { |
| |
151 UnhookWindowsHookEx(keyHook); |
| |
152 UnmapViewOfFile(lastTime); |
| |
153 CloseHandle(hMapObject); |
| |
154 return FALSE; |
| |
155 } |
| |
156 } |
| |
157 |
| |
158 return TRUE; |
| |
159 } |
| |
160 |
| |
161 |
| |
162 EXPORT void wgaim_remove_idlehooks() { |
| |
163 if(g_user32 != NULL) |
| |
164 FreeLibrary(g_user32); |
| |
165 if(keyHook) |
| |
166 UnhookWindowsHookEx(keyHook); |
| |
167 if(mouseHook) |
| |
168 UnhookWindowsHookEx(mouseHook); |
| |
169 if(lastTime) |
| |
170 UnmapViewOfFile(lastTime); |
| |
171 if(hMapObject) |
| |
172 CloseHandle(hMapObject); |
| |
173 } |
| |
174 |
| |
175 int WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { |
| |
176 switch(dwReason) { |
| |
177 case DLL_PROCESS_ATTACH: |
| |
178 g_hInstance = hInstance; |
| |
179 g_point.x = 0; |
| |
180 g_point.y = 0; |
| |
181 break; |
| |
182 case DLL_PROCESS_DETACH: |
| |
183 break; |
| |
184 } |
| |
185 return TRUE; |
| |
186 } |