| 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 Purple 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 winpidgin_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 winpidgin_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 winpidgin_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 /* suppress gcc "no previous prototype" warning */ |
|
| 176 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved); |
|
| 177 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) { |
|
| 178 switch(dwReason) { |
|
| 179 case DLL_PROCESS_ATTACH: |
|
| 180 g_hInstance = hInstance; |
|
| 181 g_point.x = 0; |
|
| 182 g_point.y = 0; |
|
| 183 break; |
|
| 184 case DLL_PROCESS_DETACH: |
|
| 185 break; |
|
| 186 } |
|
| 187 return TRUE; |
|
| 188 } |
|