From 6e7980b0ad162bbb526b3d52acbc1639c2b11760 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Fri, 20 Jul 2012 10:43:41 +0000 Subject: Import, KeyboardNotify: changed folder structure git-svn-id: http://svn.miranda-ng.org/main/trunk@1071 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/KeyboardNotify/src/AggressiveOptimize.h | 165 +++ plugins/KeyboardNotify/src/EnumProc.cpp | 260 ++++ plugins/KeyboardNotify/src/EnumProc.h | 27 + plugins/KeyboardNotify/src/constants.h | 85 ++ plugins/KeyboardNotify/src/flash.cpp | 438 +++++++ plugins/KeyboardNotify/src/flash.h | 28 + plugins/KeyboardNotify/src/ignore.cpp | 389 ++++++ plugins/KeyboardNotify/src/ignore.h | 20 + plugins/KeyboardNotify/src/keyboard.cpp | 120 ++ plugins/KeyboardNotify/src/keyboard.h | 21 + plugins/KeyboardNotify/src/keypresses.cpp | 77 ++ plugins/KeyboardNotify/src/keypresses.h | 20 + plugins/KeyboardNotify/src/main.cpp | 1448 +++++++++++++++++++++ plugins/KeyboardNotify/src/options.cpp | 1565 +++++++++++++++++++++++ plugins/KeyboardNotify/src/protolist.h | 34 + plugins/KeyboardNotify/src/resource.h | 120 ++ plugins/KeyboardNotify/src/trigger.cpp | 178 +++ plugins/KeyboardNotify/src/trigger.h | 20 + plugins/KeyboardNotify/src/utils.cpp | 52 + plugins/KeyboardNotify/src/utils.h | 20 + 20 files changed, 5087 insertions(+) create mode 100644 plugins/KeyboardNotify/src/AggressiveOptimize.h create mode 100644 plugins/KeyboardNotify/src/EnumProc.cpp create mode 100644 plugins/KeyboardNotify/src/EnumProc.h create mode 100644 plugins/KeyboardNotify/src/constants.h create mode 100644 plugins/KeyboardNotify/src/flash.cpp create mode 100644 plugins/KeyboardNotify/src/flash.h create mode 100644 plugins/KeyboardNotify/src/ignore.cpp create mode 100644 plugins/KeyboardNotify/src/ignore.h create mode 100644 plugins/KeyboardNotify/src/keyboard.cpp create mode 100644 plugins/KeyboardNotify/src/keyboard.h create mode 100644 plugins/KeyboardNotify/src/keypresses.cpp create mode 100644 plugins/KeyboardNotify/src/keypresses.h create mode 100644 plugins/KeyboardNotify/src/main.cpp create mode 100644 plugins/KeyboardNotify/src/options.cpp create mode 100644 plugins/KeyboardNotify/src/protolist.h create mode 100644 plugins/KeyboardNotify/src/resource.h create mode 100644 plugins/KeyboardNotify/src/trigger.cpp create mode 100644 plugins/KeyboardNotify/src/trigger.h create mode 100644 plugins/KeyboardNotify/src/utils.cpp create mode 100644 plugins/KeyboardNotify/src/utils.h (limited to 'plugins/KeyboardNotify/src') diff --git a/plugins/KeyboardNotify/src/AggressiveOptimize.h b/plugins/KeyboardNotify/src/AggressiveOptimize.h new file mode 100644 index 0000000000..34c6074320 --- /dev/null +++ b/plugins/KeyboardNotify/src/AggressiveOptimize.h @@ -0,0 +1,165 @@ +////////////////////////////// +// Version 1.40 +// October 22nd, 2002 - .NET (VC7, _MSC_VER=1300) support! +// Version 1.30 +// Nov 24th, 2000 +// Version 1.20 +// Jun 9th, 2000 +// Version 1.10 +// Jan 23rd, 2000 +// Version 1.00 +// May 20th, 1999 +// Todd C. Wilson, Fresh Ground Software +// (todd@nopcode.com) +// This header file will kick in settings for Visual C++ 5 and 6 that will (usually) +// result in smaller exe's. +// The "trick" is to tell the compiler to not pad out the function calls; this is done +// by not using the /O1 or /O2 option - if you do, you implicitly use /Gy, which pads +// out each and every function call. In one single 500k dll, I managed to cut out 120k +// by this alone! +// The other two "tricks" are telling the Linker to merge all data-type segments together +// in the exe file. The relocation, read-only (constants) data, and code section (.text) +// sections can almost always be merged. Each section merged can save 4k in exe space, +// since each section is padded out to 4k chunks. This is very noticeable with smaller +// exes, since you could have only 700 bytes of data, 300 bytes of code, 94 bytes of +// strings - padded out, this could be 12k of runtime, for 1094 bytes of stuff! For larger +// programs, this is less overall, but can save at least 4k. +// Note that if you're using MFC static or some other 3rd party libs, you may get poor +// results with merging the readonly (.rdata) section - the exe may grow larger. +// To use this feature, define _MERGE_RDATA_ in your project or before this header is used. +// With Visual C++ 5, the program uses a file alignment of 512 bytes, which results +// in a small exe. Under VC6, the program instead uses 4k, which is the same as the +// section size. The reason (from what I understand) is that 4k is the chunk size of +// the virtual memory manager, and that WinAlign (an end-user tuning tool for Win98) +// will re-align the programs on this boundary. The problem with this is that all of +// Microsoft's system exes and dlls are *NOT* tuned like this, and using 4k causes serious +// exe bloat. This is very noticeable for smaller programs. +// The "trick" for this is to use the undocumented FILEALIGN linker parm to change the +// padding from 4k to 1/2k, which results in a much smaller exe - anywhere from 20%-75% +// depending on the size. Note that this is the same as using /OPT:NOWIN98, which *is* +// a previously documented switch, but was left out of the docs for some reason in VC6 and +// all of the current MSDN's - see KB:Q235956 for more information. +// Microsoft does say that using the 4k alignment will "speed up process loading", +// but I've been unable to notice a difference, even on my P180, with a very large (4meg) exe. +// Please note, however, that this will probably not change the size of the COMPRESSED +// file (either in a .zip file or in an install archive), since this 4k is all zeroes and +// gets compressed away. +// Also, the /ALIGN:4096 switch will "magically" do the same thing, even though this is the +// default setting for this switch. Apparently this sets the same values as the above two +// switches do. We do not use this in this header, since it smacks of a bug and not a feature. +// Thanks to Michael Geary for some additional tips! +// +// Notes about using this header in .NET +// First off, VC7 does not allow a lot of the linker command options in pragma's. There is no +// honest or good reason why Microsoft decided to make this change, it just doesn't. +// So that is why there are a lot of <1300 #if's in the header. +// If you want to take full advantage of the VC7 linker options, you will need to do it on a +// PER PROJECT BASIS; you can no longer use a global header file like this to make it better. +// Items I strongly suggest putting in all your VC7 project linker options command line settings: +// /ignore:4078 /RELEASE +// Compiler options: +// /GL (Whole Program Optimization) +// If you're making an .EXE and not a .DLL, consider adding in: +// /GA (Optimize for Windows Application) +// Some items to consider using in your VC7 projects (not VC6): +// Link-time Code Generation - whole code optimization. Put this in your exe/dll project link settings. +// /LTCG:NOSTATUS +// The classic no-padding and no-bloat compiler C/C++ switch: +// /opt:nowin98 +// +// (C++ command line options: /GL /opt:nowin98 and /GA for .exe files) +// (Link command line options: /ignore:4078 /RELEASE /LTCG:NOSTATUS) +// +// Now, notes on using these options in VC7 vs VC6. +// VC6 consistently, for me, produces smaller code from C++ the exact same sources, +// with or without this header. On average, VC6 produces 5% smaller binaries compared +// to VC7 compiling the exact same project, *without* this header. With this header, VC6 +// will make a 13k file, while VC7 will make a 64k one. VC7 is just bloaty, pure and +// simple - all that managed/unmanaged C++ runtimes, and the CLR stuff must be getting +// in the way of code generation. However, template support is better, so there. +// Both VC6 and VC7 show the same end kind of end result savings - larger binary output +// will shave about 2% off, where as smaller projects (support DLL's, cpl's, +// activex controls, ATL libs, etc) get the best result, since the padding is usually +// more than the actual usable code. But again, VC7 does not compile down as small as VC6. +// +// The argument can be made that doing this is a waste of time, since the "zero bytes" +// will be compressed out in a zip file or install archive. Not really - it doesn't matter +// if the data is a string of zeroes or ones or 85858585 - it will still take room (20 bytes +// in a zip file, 29 bytes if only *4* of them 4k bytes are not the same) and time to +// compress that data and decompress it. Also, 20k of zeros is NOT 20k on disk - it's the +// size of the cluster slop- for Fat32 systems, 20k can be 32k, NTFS could make it 24k if you're +// just 1 byte over (round up). Most end users do not have the dual P4 Xeon systems with +// two gigs of RDram and a Raid 0+1 of Western Digital 120meg Special Editions that all +// worthy developers have (all six of us), so they will need any space and LOADING TIME +// savings they will need; taking an extra 32k or more out of your end user's 64megs of +// ram on Windows 98 is Not a Good Thing. +// +// Now, as a ADDED BONUS at NO EXTRA COST TO YOU! Under VC6, using the /merge:.text=.data +// pragma will cause the output file to be un-disassembleable! (is that a word?) At least, +// with the normal tools - WinDisam, DumpBin, and the like will not work. Try it - use the +// header, compile release, and then use DUMPBIN /DISASM filename.exe - no code! +// Thanks to Gëzim Pani for discovering this gem - for a full writeup on +// this issue and the ramifactions of it, visit www.nopcode.com for the Aggressive Optimize +// article. + +#ifndef _AGGRESSIVEOPTIMIZE_H_ +#define _AGGRESSIVEOPTIMIZE_H_ + +#pragma warning(disable:4711) + +#ifdef NDEBUG +// /Og (global optimizations), /Os (favor small code), /Oy (no frame pointers) +#pragma optimize("gsy",on) + +#if (_MSC_VER<1300) + #pragma comment(linker,"/RELEASE") +#endif + +// Note that merging the .rdata section will result in LARGER exe's if you using +// MFC (esp. static link). If this is desirable, define _MERGE_RDATA_ in your project. +//#ifdef _MERGE_RDATA_ +//#pragma comment(linker,"/merge:.rdata=.data") +//#endif // _MERGE_RDATA_ + +//#pragma comment(linker,"/merge:.text=.data") +//#if (_MSC_VER<1300) + // In VC7, this causes problems with the relocation and data tables, so best to not merge them +// #pragma comment(linker,"/merge:.reloc=.data") +//#endif + +// Merging sections with different attributes causes a linker warning, so +// turn off the warning. From Michael Geary. Undocumented, as usual! +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/ignore:4078") +#endif + +// With Visual C++ 5, you already get the 512-byte alignment, so you will only need +// it for VC6, and maybe later. +#if _MSC_VER >= 1000 + +// Option #1: use /filealign +// Totally undocumented! And if you set it lower than 512 bytes, the program crashes. +// Either leave at 0x200 or 0x1000 +//#pragma comment(linker,"/FILEALIGN:0x200") + +// Option #2: use /opt:nowin98 +// See KB:Q235956 or the READMEVC.htm in your VC directory for info on this one. +// This is our currently preferred option, since it is fully documented and unlikely +// to break in service packs and updates. +#if (_MSC_VER<1300) + // In VC7, you will need to put this in your project settings + #pragma comment(linker,"/opt:nowin98") +#else + +// Option #3: use /align:4096 +// A side effect of using the default align value is that it turns on the above switch. +// Does nothing under Vc7 that /opt:nowin98 doesn't already give you +// #pragma comment(linker,"/ALIGN:512") +#endif + +#endif // _MSC_VER >= 1000 + +#endif // NDEBUG + +#endif // _AGGRESSIVEOPTIMIZE_H_ diff --git a/plugins/KeyboardNotify/src/EnumProc.cpp b/plugins/KeyboardNotify/src/EnumProc.cpp new file mode 100644 index 0000000000..7a5a23f0e3 --- /dev/null +++ b/plugins/KeyboardNotify/src/EnumProc.cpp @@ -0,0 +1,260 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include "EnumProc.h" + + +BOOL findFilename(TCHAR *); +TCHAR *filename(TCHAR *); +BOOL WINAPI Enum16(DWORD, WORD, WORD, TCHAR *, TCHAR *, LPARAM); + + +// Globals +extern double dWinVer; +extern BOOL bWindowsNT; +extern PROCESS_LIST ProcessList; + +HINSTANCE hInstLib, hInstLib2; +HANDLE (WINAPI *lpfCreateToolhelp32Snapshot)(DWORD, DWORD); +BOOL (WINAPI *lpfProcess32First)(HANDLE, LPPROCESSENTRY32); +BOOL (WINAPI *lpfProcess32Next)(HANDLE, LPPROCESSENTRY32); +BOOL (WINAPI *lpfEnumProcesses)(DWORD *, DWORD, DWORD *); +BOOL (WINAPI *lpfEnumProcessModules)(HANDLE, HMODULE *, DWORD, LPDWORD); +DWORD (WINAPI *lpfGetModuleBaseName)(HANDLE, HMODULE, LPTSTR, DWORD); +INT (WINAPI *lpfVDMEnumTaskWOWEx)(DWORD, TASKENUMPROCEX, LPARAM); + + +void LoadProcsLibrary(void) +{ + if (bWindowsNT && dWinVer < 5) { + + if (!(hInstLib = LoadLibraryA("PSAPI.DLL"))) + return; + + if (!(hInstLib2 = LoadLibraryA("VDMDBG.DLL"))) + return; + + lpfEnumProcesses = (BOOL (WINAPI *)(DWORD *, DWORD, DWORD*)) GetProcAddress(hInstLib, "EnumProcesses"); + lpfEnumProcessModules = (BOOL (WINAPI *)(HANDLE, HMODULE *, DWORD, LPDWORD)) GetProcAddress(hInstLib, "EnumProcessModules"); + lpfGetModuleBaseName = (DWORD (WINAPI *)(HANDLE, HMODULE, LPTSTR, DWORD)) GetProcAddress(hInstLib, "GetModuleBaseNameA"); + + lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX, LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx"); + } else { + + if (!(hInstLib = LoadLibraryA("Kernel32.DLL"))) + return; + + if (bWindowsNT && !(hInstLib2 = LoadLibraryA("VDMDBG.DLL"))) + return; + + lpfCreateToolhelp32Snapshot = (HANDLE (WINAPI *)(DWORD,DWORD)) GetProcAddress(hInstLib, "CreateToolhelp32Snapshot"); + lpfProcess32First = (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress(hInstLib, "Process32First"); + lpfProcess32Next = (BOOL (WINAPI *)(HANDLE,LPPROCESSENTRY32)) GetProcAddress(hInstLib, "Process32Next"); + + if (bWindowsNT) + lpfVDMEnumTaskWOWEx = (INT (WINAPI *)(DWORD, TASKENUMPROCEX, LPARAM)) GetProcAddress(hInstLib2, "VDMEnumTaskWOWEx"); + } +} + + +void UnloadProcsLibrary(void) +{ + if (hInstLib) + FreeLibrary(hInstLib); + if (hInstLib2) + FreeLibrary(hInstLib2); + + hInstLib = hInstLib = NULL; + lpfCreateToolhelp32Snapshot = NULL; + lpfProcess32First = NULL; + lpfProcess32Next = NULL; + lpfEnumProcesses = NULL; + lpfEnumProcessModules = NULL; + lpfGetModuleBaseName = NULL; + lpfVDMEnumTaskWOWEx = NULL; +} + + +BOOL areThereProcessesRunning(void) +{ + HANDLE hSnapShot = NULL; + LPDWORD lpdwPIDs = NULL; + PROCESSENTRY32 procentry; + BOOL bFlag; + DWORD dwSize; + DWORD dwSize2; + DWORD dwIndex; + HMODULE hMod; + HANDLE hProcess; + TCHAR szFileName[MAX_PATH+1]; + + + if (!ProcessList.count) // Process list is empty + return FALSE; + + // If Windows NT 4.0 + if (bWindowsNT && dWinVer < 5) { + + if (!lpfEnumProcesses || !lpfEnumProcessModules || !lpfGetModuleBaseName || !lpfVDMEnumTaskWOWEx) + return FALSE; + + // + // Call the PSAPI function EnumProcesses to get all of the ProcID's currently in the system. + // + // NOTE: In the documentation, the third parameter of EnumProcesses is named cbNeeded, which implies that you + // can call the function once to find out how much space to allocate for a buffer and again to fill the buffer. + // This is not the case. The cbNeeded parameter returns the number of PIDs returned, so if your buffer size is + // zero cbNeeded returns zero. + // + // NOTE: The "HeapAlloc" loop here ensures that we actually allocate a buffer large enough for all the + // PIDs in the system. + // + dwSize2 = 256 * sizeof(DWORD); + do { + if (lpdwPIDs) { + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + dwSize2 *= 2; + } + if (!(lpdwPIDs = (LPDWORD)HeapAlloc(GetProcessHeap(), 0, dwSize2))) + return FALSE; + if (!lpfEnumProcesses(lpdwPIDs, dwSize2, &dwSize)) { + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + return FALSE; + } + } while (dwSize == dwSize2); + + // How many ProcID's did we get? + dwSize /= sizeof(DWORD); + + // Loop through each ProcID. + for (dwIndex = 0; dwIndex < dwSize; dwIndex++) { + TCHAR *szFileNameAux; + szFileName[0] = '\0'; + + // Open the process (if we can... security does not permit every process in the system to be opened). + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, FALSE, lpdwPIDs[dwIndex]); + if (hProcess) { + // Here we call EnumProcessModules to get only the first module in the process. This will be the + // EXE module for which we will retrieve the name. + if (lpfEnumProcessModules(hProcess, &hMod, sizeof(hMod), &dwSize2)) { + // Get the module name + if (!lpfGetModuleBaseName(hProcess, hMod, szFileName, sizeof(szFileName))) + szFileName[0] = '\0'; + } + CloseHandle(hProcess); + } + szFileNameAux = filename(szFileName); + + // Search szFileName in user-defined list + if (findFilename(szFileNameAux)) { + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + return TRUE; + } + + // Did we just bump into an NTVDM? + if (!_wcsicmp(szFileNameAux, L"NTVDM.EXE")) { + BOOL bFound = FALSE; + + // Enum the 16-bit stuff. + lpfVDMEnumTaskWOWEx(lpdwPIDs[dwIndex], (TASKENUMPROCEX) Enum16, (LPARAM)&bFound); + + // Did we find any user-defined process? + if (bFound) { + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + return TRUE; + } + } + } + HeapFree(GetProcessHeap(), 0, lpdwPIDs); + + // If any OS other than Windows NT 4.0. + } else { + + if (!lpfProcess32Next || !lpfProcess32First || !lpfCreateToolhelp32Snapshot) + return FALSE; + + // Get a handle to a Toolhelp snapshot of all processes. + if ((hSnapShot = lpfCreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) == INVALID_HANDLE_VALUE) + return FALSE; + + // While there are processes, keep looping. + for (procentry.dwSize=sizeof(PROCESSENTRY32), bFlag=lpfProcess32First(hSnapShot, &procentry); bFlag; procentry.dwSize=sizeof(PROCESSENTRY32), bFlag=lpfProcess32Next(hSnapShot, &procentry)) { + TCHAR *szFileNameAux = filename(procentry.szExeFile); + + // Search szFileName in user-defined list + if (findFilename(szFileNameAux)) + return TRUE; + + // Did we just bump into an NTVDM? + if (lpfVDMEnumTaskWOWEx && !_wcsicmp(szFileNameAux, L"NTVDM.EXE")) { + BOOL bFound = FALSE; + + // Enum the 16-bit stuff. + lpfVDMEnumTaskWOWEx(procentry.th32ProcessID, (TASKENUMPROCEX)Enum16, (LPARAM)&bFound); + + // Did we find any user-defined process? + if (bFound) + return TRUE; + } + } + } + + return FALSE; +} + + +BOOL WINAPI Enum16(DWORD dwThreadId, WORD hMod16, WORD hTask16, TCHAR *szModName, TCHAR *szFileName, LPARAM lpUserDefined) +{ + BOOL bRet; + BOOL *pbFound = (BOOL *)lpUserDefined; + + if ((bRet = findFilename(filename(szFileName)))) + *pbFound = TRUE; + + return bRet; +} + + +BOOL findFilename(TCHAR *fileName) +{ + unsigned int i; + + for (i=0; i < ProcessList.count; i++) + if (ProcessList.szFileName[i] && !_wcsicmp(ProcessList.szFileName[i], fileName)) + return TRUE; + + return FALSE; +} + + +TCHAR *filename(TCHAR *fullFileName) +{ + TCHAR *str; + + str = wcsrchr(fullFileName, '\\'); + if (!str) + return fullFileName; + + return ++str; +} \ No newline at end of file diff --git a/plugins/KeyboardNotify/src/EnumProc.h b/plugins/KeyboardNotify/src/EnumProc.h new file mode 100644 index 0000000000..09b3cba8d6 --- /dev/null +++ b/plugins/KeyboardNotify/src/EnumProc.h @@ -0,0 +1,27 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +typedef struct { + unsigned int count; + TCHAR **szFileName; +} PROCESS_LIST; + + +void LoadProcsLibrary(void); +void UnloadProcsLibrary(void); +BOOL areThereProcessesRunning(void); diff --git a/plugins/KeyboardNotify/src/constants.h b/plugins/KeyboardNotify/src/constants.h new file mode 100644 index 0000000000..d50ded6d23 --- /dev/null +++ b/plugins/KeyboardNotify/src/constants.h @@ -0,0 +1,85 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +// Settings values +#define KEYBDMODULE "keybdnotify" +#define FLASH_SAMETIME 0 +#define FLASH_INTURN 1 +#define FLASH_INSEQUENCE 2 +#define FLASH_CUSTOM 3 +#define FLASH_TRILLIAN 4 +#define SEQ_LEFT2RIGHT 0 +#define SEQ_RIGHT2LEFT 1 +#define SEQ_LIKEKIT 2 +#define ACTIVE_MIRANDA 0 +#define ACTIVE_WINDOWS 1 +// Until settings map +#define UNTIL_NBLINKS 1 +#define UNTIL_REATTENDED 2 +#define UNTIL_EVENTSOPEN 4 +#define UNTIL_CONDITIONS 8 + +// Status map +#define MAP_ONLINE 1 +#define MAP_AWAY 2 +#define MAP_NA 4 +#define MAP_OCCUPIED 8 +#define MAP_DND 16 +#define MAP_FREECHAT 32 +#define MAP_INVISIBLE 64 +#define MAP_ONTHEPHONE 128 +#define MAP_OUTTOLUNCH 256 +#define MAP_OFFLINE 512 + +// Default settings +#define DEF_SETTING_ONMSG 1 // 1: Yes, 0: No +#define DEF_SETTING_ONURL 1 // 1: Yes, 0: No +#define DEF_SETTING_ONFILE 1 // 1: Yes, 0: No +#define DEF_SETTING_OTHER 1 // 1: Yes, 0: No +#define DEF_SETTING_FSCREEN 1 // 1: Yes, 0: No +#define DEF_SETTING_SSAVER 1 // 1: Yes, 0: No +#define DEF_SETTING_LOCKED 1 // 1: Yes, 0: No +#define DEF_SETTING_PROCS 0 // 1: Yes, 0: No +#define DEF_SETTING_ACTIVE 1 // 1: Yes, 0: No +#define DEF_SETTING_IFMSGOPEN 1 // 1: Yes, 0: No +#define DEF_SETTING_IFMSGNOTTOP 0 // 1: Yes, 0: No +#define DEF_SETTING_IFMSGOLDER 0 // 1: Yes, 0: No +#define DEF_SETTING_SECSOLDER 10 // Seconds +#define DEF_SETTING_FLASHUNTIL 2 // 1 = After x blinks, 2 = Until Miranda/Windows become active, 4 = Events are opened, 8 = Until end of 'notify when' conditions +#define DEF_SETTING_NBLINKS 4 // Seconds +#define DEF_SETTING_MIRORWIN 0 // 0-1, 0 = Miranda becomes active, 1 = Windows becomes active +#define DEF_SETTING_STATUS 1023 // 1023 = All +#define DEF_SETTING_CHECKTIME 0 // Minutes, 0 = don't check +#define DEF_SETTING_FLASHCAPS 1 // 1: Yes, 0: No +#define DEF_SETTING_FLASHNUM 1 // 1: Yes, 0: No +#define DEF_SETTING_FLASHSCROLL 1 // 1: Yes, 0: No +#define DEF_SETTING_FLASHEFFECT 0 // 0-3, 0 = All together, 1 = In turn, 2 = In sequence, 3 = Custom Theme, 4 = Trillian-like sequences +#define DEF_SETTING_SEQORDER 0 // 0-2, 0 = left to right, 1 = right to left, 2 = left <-> right +#define DEF_SETTING_CUSTOMTHEME 0 // Theme number +#define DEF_SETTING_LEDSMSG 2 // 2: Num Lock +#define DEF_SETTING_LEDSFILE 4 // 2: Caps Lock +#define DEF_SETTING_LEDSURL 1 // 2: Scroll Lock +#define DEF_SETTING_LEDSOTHER 7 // 2: Num Lock + Caps Lock + Scroll Lock +#define DEF_SETTING_STARTDELAY 2 // Seconds +#define DEF_SETTING_FLASHSPEED 3 // 0-5, 0 = really slow, 5 = really fast +#define DEF_SETTING_KEYPRESSES 0 // 1: Yes, 0: No +#define DEF_SETTING_OVERRIDE 0 // 1: Yes, 0: No +#define DEF_SETTING_TESTNUM 2 // Number of sequences to test before stopping +#define DEF_SETTING_TESTSECS 2 // Seconds to test before stopping +#define DEF_SETTING_PROTOCOL 1 // 1: Yes, 0: No +#define DEF_SETTING_XSTATUS 1 // 1: Yes, 0: No diff --git a/plugins/KeyboardNotify/src/flash.cpp b/plugins/KeyboardNotify/src/flash.cpp new file mode 100644 index 0000000000..aa0014a329 --- /dev/null +++ b/plugins/KeyboardNotify/src/flash.cpp @@ -0,0 +1,438 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include "flash.h" +#include "keyboard.h" +#include "keypresses.h" +#include "utils.h" +#include "constants.h" +#include +#include + +typedef struct { + unsigned int size; + unsigned int index; + BYTE frame[MAX_PATH]; +} FLASHING_SEQUENCE; + + +// Prototypes +FLASHING_SEQUENCE *getCustomSeq(void); +FLASHING_SEQUENCE *getPredefinedSeq(void); +FLASHING_SEQUENCE *getTrillianSeq(void); +void updateTrillianSeq(void); +static void TestThread(FLASHING_SEQUENCE *); +static void PreviewThread(void *); +FLASHING_SEQUENCE str2FS(TCHAR *); +BYTE KbdChar2Byte(char); +void countUnopenEvents(int *, int *, int *, int *); + +#define Leds2Flash ((BYTE)(bFlashLed[2] + (bFlashLed[0]<<1) + (bFlashLed[1]<<2))) + +// Flashing settings +FLASHING_SEQUENCE *pFS; +BOOL bTemporarilyUseExtern; +extern BYTE bFlashLed[3]; +extern BYTE bFlashEffect; extern BYTE bSequenceOrder; +extern WORD wCustomTheme; +extern BYTE bTrillianLedsMsg; extern BYTE bTrillianLedsURL; extern BYTE bTrillianLedsFile; extern BYTE bTrillianLedsOther; +extern BYTE bEmulateKeypresses; + + +// TestThread/PreviewThread globals +extern int nWaitDelay; extern WORD wStartDelay; +BOOL bTestSemaphore, bPreviewSemaphore, bPreview; + + +void RestoreLEDState(void) +{ + if (bEmulateKeypresses) + keypresses_RestoreLEDState(); + else + ToggleKeyboardLights((BYTE)(LedState(VK_SCROLL) + (LedState(VK_NUMLOCK)<<1) + (LedState(VK_CAPITAL)<<2))); +} + + +BYTE getBlinkingLeds(void) +{ + if (!pFS->size) + return (BYTE)(LedState(VK_SCROLL) + (LedState(VK_NUMLOCK)<<1) + (LedState(VK_CAPITAL)<<2)); + + pFS->index %= pFS->size; + if (bFlashEffect == FLASH_TRILLIAN && !bTemporarilyUseExtern && !pFS->index) + updateTrillianSeq(); + return pFS->frame[pFS->index++]; +} + + +void setFlashingSequence(void) +{ + switch (bFlashEffect) { + case FLASH_CUSTOM: + pFS = getCustomSeq(); + break; + case FLASH_TRILLIAN: + pFS = getTrillianSeq(); + break; + default: + pFS = getPredefinedSeq(); + } + bTemporarilyUseExtern = FALSE; +} + + +FLASHING_SEQUENCE *getCustomSeq(void) +{ + static FLASHING_SEQUENCE Custom = {0}; + + DBVARIANT dbv; + TCHAR customStr[MAX_PATH+1]; + + + customStr[0] = _T('\0'); + if (!DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", wCustomTheme), &dbv)) { + wcscpy(customStr, dbv.pwszVal); + DBFreeVariant(&dbv); + } + + Custom = str2FS(customStr); + + return &Custom; +} + + +FLASHING_SEQUENCE *getPredefinedSeq(void) +{ + static FLASHING_SEQUENCE Predefined = {0}; + + FLASHING_SEQUENCE *pAux; + FLASHING_SEQUENCE SameTime = {2, 0, {7, 0}}; + FLASHING_SEQUENCE InTurn = {2, 0, {3, 4}}; + FLASHING_SEQUENCE InSeq = {3, 0, {2, 4, 1}}; + FLASHING_SEQUENCE InSeqRev = {3, 0, {1, 4, 2}}; + FLASHING_SEQUENCE InSeqKIT = {4, 0, {2, 4, 1, 4}}; + + + if (Leds2Flash < 3 || Leds2Flash == 4) + pAux = &SameTime; + else + switch (bFlashEffect) { + default: + case FLASH_SAMETIME: + pAux = &SameTime; + break; + case FLASH_INTURN: + if (Leds2Flash == 3) // 3 = Num+Scroll + pAux = &InSeq; + else + pAux = &InTurn; + break; + case FLASH_INSEQUENCE: + switch (bSequenceOrder) { + default: + case SEQ_LEFT2RIGHT: + pAux = &InSeq; + break; + case SEQ_RIGHT2LEFT: + pAux = &InSeqRev; + break; + case SEQ_LIKEKIT: + if (Leds2Flash != 7) // 7 = Num+Caps+Scroll + pAux = &InSeq; + else + pAux = &InSeqKIT; + break; + } + break; + } + + Predefined.size = Predefined.index = 0; + for (pAux->index=0; pAux->index < pAux->size; pAux->index++) + if (!pAux->frame[pAux->index] || (pAux->frame[pAux->index] & Leds2Flash)) { + Predefined.size++; + Predefined.frame[Predefined.size - 1] = pAux->frame[pAux->index] & Leds2Flash; + } + + return &Predefined; +} + + +FLASHING_SEQUENCE *getTrillianSeq(void) +{ + static FLASHING_SEQUENCE Trillian = {2, 0, {0, 0}}; + + Trillian.size = 2; + Trillian.index = 0; + + return &Trillian; +} + + +void updateTrillianSeq(void) +{ + int i, msgCount=0, fileCount=0, urlCount=0, otherCount=0; + + pFS->size = 2; + countUnopenEvents(&msgCount, &fileCount, &urlCount, &otherCount); + + if ((bTrillianLedsMsg & Leds2Flash) && (pFS->size + 2 * msgCount) <= MAX_PATH) + for (i=0; i < msgCount; i++) { + pFS->frame[pFS->size++] = bTrillianLedsMsg & Leds2Flash; + pFS->frame[pFS->size++] = 0; + } + + if ((bTrillianLedsFile & Leds2Flash) && (pFS->size + 2 * fileCount) <= MAX_PATH) + for (i=0; i < fileCount; i++) { + pFS->frame[pFS->size++] = bTrillianLedsFile & Leds2Flash; + pFS->frame[pFS->size++] = 0; + } + + if ((bTrillianLedsURL & Leds2Flash) && (pFS->size + 2 * urlCount) <= MAX_PATH) + for (i=0; i < urlCount; i++) { + pFS->frame[pFS->size++] = bTrillianLedsURL & Leds2Flash; + pFS->frame[pFS->size++] = 0; + } + + if ((bTrillianLedsOther & Leds2Flash) && (pFS->size + 2 * otherCount) <= MAX_PATH) + for (i=0; i < otherCount; i++) { + pFS->frame[pFS->size++] = bTrillianLedsOther & Leds2Flash; + pFS->frame[pFS->size++] = 0; + } + +} + + +void useExternSequence(TCHAR *extStr) +{ + static FLASHING_SEQUENCE Extern = {0}; + + TCHAR externStr[MAX_PATH+1]; + + + wcscpy(externStr, extStr); + + Extern = str2FS(normalizeCustomString(externStr)); + + pFS = &Extern; + bTemporarilyUseExtern = TRUE; +} + + +TCHAR *normalizeCustomString(TCHAR *customStr) +{ + int len=0, status=0; + BOOL used[4]; + TCHAR strAux[MAX_PATH+1], *str; + + for (wcscpy(str=strAux, customStr); *str; str++) + switch (*str) { + case _T('['): + if (status == 0) { + status = 1; + customStr[len++] = *str; + used[0] = used [1] = used[2] = used[3] = FALSE; + } + break; + case _T(']'): + if (status == 1) { + status = 0; + customStr[len++] = *str; + } + break; + case _T('0'): + case _T('1'): + case _T('2'): + case _T('3'): + if (status == 0) + customStr[len++] = *str; + else + if (!used[*str - _T('0')]) { + customStr[len++] = *str; + used[*str - _T('0')] = TRUE; + } + break; + } + if (status == 1) + customStr[len++] = _T(']'); + customStr[len] = _T('\0'); + + return customStr; +} + + +TCHAR *getCurrentSequenceString(void) +{ + static TCHAR CurrentSeqString[MAX_PATH+1]; + + unsigned int i; + TCHAR *str; + + + for (i=0, str=CurrentSeqString; i < pFS->size; i++) + switch (pFS->frame[i]) { + case 0: + *(str++) = _T('0'); + break; + case 1: + *(str++) = _T('3'); + break; + case 2: + *(str++) = _T('1'); + break; + case 3: + *(str++) = _T('['); + *(str++) = _T('1'); + *(str++) = _T('3'); + *(str++) = _T(']'); + break; + case 4: + *(str++) = _T('2'); + break; + case 5: + *(str++) = _T('['); + *(str++) = _T('2'); + *(str++) = _T('3'); + *(str++) = _T(']'); + break; + case 6: + *(str++) = _T('['); + *(str++) = _T('1'); + *(str++) = _T('2'); + *(str++) = _T(']'); + break; + case 7: + *(str++) = _T('['); + *(str++) = _T('1'); + *(str++) = _T('2'); + *(str++) = _T('3'); + *(str++) = _T(']'); + } + *str = _T('\0'); + + + return CurrentSeqString; +} + + +void testSequence(TCHAR *testStr) +{ + static FLASHING_SEQUENCE Test = {0}; + + DWORD threadID = 0; + + + if (bTestSemaphore) // we try to avoid concurrent test threads + return; + bTestSemaphore = TRUE; + + Test = str2FS(testStr); + + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)TestThread, &Test, 0, &threadID); +} + + +static void TestThread(FLASHING_SEQUENCE *pTest) +{ + unsigned int i; + DWORD dwEndTest; + + unsigned int testNum = (unsigned int)DBGetContactSettingByte(NULL, KEYBDMODULE, "testnum", DEF_SETTING_TESTNUM); + unsigned int testSecs = (unsigned int)DBGetContactSettingByte(NULL, KEYBDMODULE, "testsecs", DEF_SETTING_TESTSECS); + + for (i=0, dwEndTest=GetTickCount()+testSecs*1000; i < testNum || GetTickCount() < dwEndTest; i++) + for (pTest->index=0; pTest->index < pTest->size; pTest->index++) { + ToggleKeyboardLights(pTest->frame[pTest->index]); + Sleep(nWaitDelay); + } + + RestoreLEDState(); + + bTestSemaphore = FALSE; +} + + +void previewFlashing(BOOL buttonState) +{ + DWORD threadID = 0; + + bPreview = buttonState; + + if (!bPreview || bPreviewSemaphore) // turn off flashing or already running + return; + + bPreviewSemaphore = TRUE; + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreviewThread, NULL, 0, &threadID); +} + + +static void PreviewThread(void *dummy) +{ + unsigned int i; + BYTE unchangedLeds; + + if (wStartDelay > 0) + Sleep(wStartDelay * 1000); + + unchangedLeds = (BYTE)(LedState(VK_SCROLL) * !bFlashLed[2] + ((LedState(VK_NUMLOCK) * !bFlashLed[0])<<1) + ((LedState(VK_CAPITAL) * !bFlashLed[1])<<2)); + + while (bPreview) + for (i=0; bPreview && i < pFS->size; i++) { + ToggleKeyboardLights((BYTE)(pFS->frame[i%pFS->size]|unchangedLeds)); + Sleep(nWaitDelay); + } + + RestoreLEDState(); + + bPreviewSemaphore = FALSE; +} + + +FLASHING_SEQUENCE str2FS(TCHAR *str) +{ + FLASHING_SEQUENCE Temp = {0}; + + for (Temp.size=Temp.index=0; *str; str++) { + Temp.size++; + if (*str == _T('[')) { + Temp.frame[Temp.size - 1] = 0; + for (str++; *str && *str != _T(']'); str++) + Temp.frame[Temp.size - 1] += KbdChar2Byte(*str) & Leds2Flash; + if (!*str) break; + } else + Temp.frame[Temp.size - 1] = KbdChar2Byte(*str) & Leds2Flash; + } + + return Temp; +} + + +BYTE KbdChar2Byte(char kbdChar) +{ + switch (kbdChar) { + case '1': //NumLock + return 2; + case '2': //CapsLock + return 4; + case '3': //ScrollLock + return 1; + } + return 0; +} diff --git a/plugins/KeyboardNotify/src/flash.h b/plugins/KeyboardNotify/src/flash.h new file mode 100644 index 0000000000..f60706fc76 --- /dev/null +++ b/plugins/KeyboardNotify/src/flash.h @@ -0,0 +1,28 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +void RestoreLEDState(void); +BYTE getBlinkingLeds(void); +void setFlashingSequence(void); +void useExternSequence(TCHAR *); +TCHAR *normalizeCustomString(TCHAR *); +TCHAR *getCurrentSequenceString(void); +void testSequence(TCHAR *); +void previewFlashing(BOOL); + +#define LedState(a) (((BYTE)(GetKeyState(a) & 0xffff))!=0) diff --git a/plugins/KeyboardNotify/src/ignore.cpp b/plugins/KeyboardNotify/src/ignore.cpp new file mode 100644 index 0000000000..57fcceb8a6 --- /dev/null +++ b/plugins/KeyboardNotify/src/ignore.cpp @@ -0,0 +1,389 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include "ignore.h" +#include "resource.h" +#include "constants.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define IGNOREEVENT_MAX 4 +#define IDI_SMALLDOT 211 +#define IDI_FILLEDBLOB 212 +#define IDI_EMPTYBLOB 213 + +#define SIZEOF(a) (sizeof(a) / sizeof(a[0])) + +static const DWORD ignoreIdToPf1[IGNOREEVENT_MAX] = {PF1_IMRECV, PF1_URLRECV, PF1_FILERECV, 0xFFFFFFFF}; + +extern double dWinVer; +extern BOOL bWindowsNT; + + +static DWORD GetMask(HANDLE hContact) +{ + DWORD mask = DBGetContactSettingDword(hContact, KEYBDMODULE, "Mask1", (DWORD)(-1)); + if(mask == (DWORD)(-1)) { + if(hContact == NULL) + mask=0; + else { + if(DBGetContactSettingByte(hContact, "CList", "Hidden", 0) || DBGetContactSettingByte(hContact, "CList", "NotOnList", 0)) + mask = DBGetContactSettingDword(NULL, KEYBDMODULE, "Mask1", 0); + else + mask = DBGetContactSettingDword(NULL, KEYBDMODULE, "Default1", 0); + } + } + return mask; +} + +static void SetListGroupIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem, int *groupChildCount) +{ + int typeOfFirst; + int iconOn[IGNOREEVENT_MAX]={1,1,1,1}; + int childCount[IGNOREEVENT_MAX]={0,0,0,0}, i; + int iImage; + HANDLE hItem, hChildItem; + + typeOfFirst = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hFirstItem, 0); + //check groups + if(typeOfFirst == CLCIT_GROUP) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem); + while(hItem) { + hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if(hChildItem) + SetListGroupIcons(hwndList, hChildItem, hItem, childCount); + for(i=0; i < SIZEOF(iconOn); i++) + if(iconOn[i] && SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, i) == 0) + iconOn[i] = 0; + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem); + } + //check contacts + if(typeOfFirst == CLCIT_CONTACT) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem); + while(hItem) { + for(i=0; i < SIZEOF(iconOn); i++) { + iImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, i); + if(iconOn[i] && iImage == 0) + iconOn[i] = 0; + if(iImage != 0xFF) + childCount[i]++; + } + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem); + } + //set icons + for(i=0; i < SIZEOF(iconOn); i++) { + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(i, childCount[i]?(iconOn[i]?i+3:0):0xFF)); + if(groupChildCount) + groupChildCount[i] += childCount[i]; + } + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(IGNOREEVENT_MAX, 1)); + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(IGNOREEVENT_MAX+1, 2)); +} + +static void SetAllChildIcons(HWND hwndList, HANDLE hFirstItem, int iColumn, int iImage) +{ + int typeOfFirst, iOldIcon; + HANDLE hItem, hChildItem; + + typeOfFirst = SendMessage(hwndList,CLM_GETITEMTYPE,(WPARAM)hFirstItem, 0); + //check groups + if(typeOfFirst == CLCIT_GROUP) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hFirstItem); + while(hItem) { + hChildItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if(hChildItem) + SetAllChildIcons(hwndList, hChildItem, iColumn, iImage); + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTGROUP, (LPARAM)hItem); + } + //check contacts + if(typeOfFirst == CLCIT_CONTACT) + hItem = hFirstItem; + else + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hFirstItem); + while(hItem) { + iOldIcon = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn); + if(iOldIcon != 0xFF && iOldIcon != iImage) + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem); + } +} + +static void ResetListOptions(HWND hwndList) +{ + int i; + + SendMessage(hwndList, CLM_SETBKBITMAP, 0, (LPARAM)NULL); + SendMessage(hwndList, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(hwndList, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(hwndList, CLM_SETLEFTMARGIN, 4, 0); + SendMessage(hwndList, CLM_SETINDENT, 10, 0); + SendMessage(hwndList, CLM_SETHIDEEMPTYGROUPS, 1, 0); + for(i=0; i <= FONTID_MAX; i++) + SendMessage(hwndList, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); +} + +static void SetIconsForColumn(HWND hwndList, HANDLE hItem, HANDLE hItemAll, int iColumn, int iImage) +{ + int itemType; + + itemType = SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hItem, 0); + if(itemType == CLCIT_CONTACT) { + int oldiImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn); + if (oldiImage != 0xFF && oldiImage != iImage) + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); + } + else if(itemType == CLCIT_INFO) { + if(hItem == hItemAll) + SetAllChildIcons(hwndList, hItem, iColumn, iImage); + else + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); //hItemUnknown + } + else if(itemType == CLCIT_GROUP) { + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if(hItem) + SetAllChildIcons(hwndList, hItem, iColumn, iImage); + } +} + +static void InitialiseItem(HWND hwndList, HANDLE hContact, HANDLE hItem, DWORD protoCaps) +{ + DWORD mask; + int i; + + mask = GetMask(hContact); + for(i=0; i < IGNOREEVENT_MAX; i++) + if(ignoreIdToPf1[i] == 0xFFFFFFFF || protoCaps & ignoreIdToPf1[i]) + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(i, mask&(1<= 5.01)?ILC_COLOR32:ILC_COLOR16)|ILC_MASK, 3+IGNOREEVENT_MAX, 3+IGNOREEVENT_MAX); + ImageList_AddIcon(hIml, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_SMALLDOT))); + ImageList_AddIcon(hIml, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_FILLEDBLOB))); + ImageList_AddIcon(hIml, LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_EMPTYBLOB))); + ImageList_AddIcon(hIml, LoadSkinnedIcon(SKINICON_EVENT_MESSAGE)); + ImageList_AddIcon(hIml, LoadSkinnedIcon(SKINICON_EVENT_URL)); + ImageList_AddIcon(hIml, LoadSkinnedIcon(SKINICON_EVENT_FILE)); + ImageList_AddIcon(hIml, LoadSkinnedIcon(SKINICON_OTHER_MIRANDA)); + SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml); + for(i=0; i < SIZEOF(hIcons); i++) + hIcons[i] = ImageList_GetIcon(hIml, 1+i, ILD_NORMAL); + } + SendDlgItemMessage(hwndDlg, IDC_ALLICON, STM_SETICON, (WPARAM)hIcons[0], 0); + SendDlgItemMessage(hwndDlg, IDC_NONEICON, STM_SETICON, (WPARAM)hIcons[1], 0); + SendDlgItemMessage(hwndDlg, IDC_MSGICON, STM_SETICON, (WPARAM)hIcons[2], 0); + SendDlgItemMessage(hwndDlg, IDC_URLICON, STM_SETICON, (WPARAM)hIcons[3], 0); + SendDlgItemMessage(hwndDlg, IDC_FILEICON, STM_SETICON, (WPARAM)hIcons[4], 0); + SendDlgItemMessage(hwndDlg, IDC_OTHERICON, STM_SETICON, (WPARAM)hIcons[5], 0); + + SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_LIST), GWL_STYLE) &~ (CLS_CHECKBOXES|CLS_GROUPCHECKBOXES)); + SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_AUTOREBUILD, 0, 0); + + ResetListOptions(GetDlgItem(hwndDlg, IDC_LIST)); + SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_SETEXTRACOLUMNS, IGNOREEVENT_MAX+2, 0); + + { CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT; + cii.pszText = TranslateT("** All contacts **"); + hItemAll=(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_ADDINFOITEM, 0, (LPARAM)&cii); + + cii.pszText = TranslateT("** Unknown contacts **"); + hItemUnknown=(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST,CLM_ADDINFOITEM, 0, (LPARAM)&cii); + InitialiseItem(GetDlgItem(hwndDlg, IDC_LIST), NULL, hItemUnknown, 0xFFFFFFFF); + } + + SetAllContactIcons(GetDlgItem(hwndDlg, IDC_LIST)); + SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + return TRUE; + case WM_SETFOCUS: + SetFocus(GetDlgItem(hwndDlg, IDC_LIST)); + break; + case WM_NOTIFY: + switch(((LPNMHDR)lParam)->idFrom) { + case IDC_LIST: + switch (((LPNMHDR)lParam)->code) + { + case CLN_NEWCONTACT: + case CLN_LISTREBUILT: + SetAllContactIcons(GetDlgItem(hwndDlg, IDC_LIST)); + //fall through + case CLN_CONTACTMOVED: + SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + break; + case CLN_OPTIONSCHANGED: + ResetListOptions(GetDlgItem(hwndDlg, IDC_LIST)); + break; + case CLN_CHECKCHANGED: + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + break; + case NM_CLICK: + { int iImage; + HANDLE hItem; + DWORD hitFlags; + NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam; + + if(nm->iColumn == -1) + break; + hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)); + if(hItem == NULL) + break; + if (!(hitFlags & CLCHT_ONITEMEXTRA)) + break; + if(nm->iColumn == IGNOREEVENT_MAX) { //ignore all + for(iImage=0; iImage < IGNOREEVENT_MAX; iImage++) + SetIconsForColumn(GetDlgItem(hwndDlg, IDC_LIST), hItem, hItemAll, iImage, iImage+3); + } + else if(nm->iColumn == IGNOREEVENT_MAX+1) { //ignore none + for(iImage=0; iImage < IGNOREEVENT_MAX; iImage++) + SetIconsForColumn(GetDlgItem(hwndDlg, IDC_LIST), hItem, hItemAll, iImage, 0); + } + else { + iImage = SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0)); + if(iImage == 0) + iImage = nm->iColumn + 3; + else if(iImage != 0xFF) + iImage = 0; + SetIconsForColumn(GetDlgItem(hwndDlg, IDC_LIST), hItem, hItemAll, nm->iColumn, iImage); + } + SetListGroupIcons(GetDlgItem(hwndDlg, IDC_LIST),(HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + break; + } + } + break; + case 0: + switch (((LPNMHDR)lParam)->code) + { + case PSN_APPLY: + { HANDLE hContact, hItem; + + hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + do { + hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if(hItem) + SaveItemMask(GetDlgItem(hwndDlg, IDC_LIST), hContact, hItem, "Mask1"); + } while(hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0)); + SaveItemMask(GetDlgItem(hwndDlg, IDC_LIST), NULL, hItemAll, "Default1"); + SaveItemMask(GetDlgItem(hwndDlg, IDC_LIST), NULL, hItemUnknown, "Mask1"); + return TRUE; + } + } + break; + } + break; + case WM_DESTROY: + { int i; + HIMAGELIST hIml; + for(i=0; i < SIZEOF(hIcons); i++) + DestroyIcon(hIcons[i]); + hIml = (HIMAGELIST)SendDlgItemMessage(hwndDlg, IDC_LIST, CLM_GETEXTRAIMAGELIST, 0, 0); + ImageList_Destroy(hIml); + break; + } + } + return FALSE; +} + +BOOL IsIgnored(HANDLE hContact, WORD eventType) +{ + WORD ignoreID = 0; + DWORD mask = GetMask(hContact); + + switch(eventType) { + case EVENTTYPE_MESSAGE: + ignoreID = 0; + break; + case EVENTTYPE_URL: + ignoreID = 1; + break; + case EVENTTYPE_FILE: + ignoreID = 2; + break; + default: + ignoreID = 3; + } + + return (mask>>ignoreID)&1; +} diff --git a/plugins/KeyboardNotify/src/ignore.h b/plugins/KeyboardNotify/src/ignore.h new file mode 100644 index 0000000000..a72df7b6f6 --- /dev/null +++ b/plugins/KeyboardNotify/src/ignore.h @@ -0,0 +1,20 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +BOOL IsIgnored(HANDLE, WORD); +INT_PTR CALLBACK DlgProcIgnoreOptions(HWND, UINT, WPARAM, LPARAM); diff --git a/plugins/KeyboardNotify/src/keyboard.cpp b/plugins/KeyboardNotify/src/keyboard.cpp new file mode 100644 index 0000000000..df1033fce7 --- /dev/null +++ b/plugins/KeyboardNotify/src/keyboard.cpp @@ -0,0 +1,120 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include "keypresses.h" +#include +#include + + +// Globals +extern BOOL bWindowsNT; +extern BYTE bEmulateKeypresses; +HANDLE hKbdDev[10] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE}; + +// Defines +#define MAX_KBDHANDLES 10 +#define IOCTL_KEYBOARD_SET_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0002, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_KEYBOARD_QUERY_TYPEMATIC CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_KEYBOARD_QUERY_INDICATORS CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS) + +typedef struct _KEYBOARD_INDICATOR_PARAMETERS { + USHORT UnitId; // Unit identifier. + USHORT LedFlags; // LED indicator state. + +} KEYBOARD_INDICATOR_PARAMETERS, *PKEYBOARD_INDICATOR_PARAMETERS; + + +void outportb(UINT portid, BYTE value) +{ + #if !defined( _WIN64 ) + __asm mov edx,portid + __asm mov al,value + __asm out dx,al + #endif +} + + +BOOL OpenKeyboardDevice() +{ + int i = 0; + TCHAR aux1[MAX_PATH+1], aux2[MAX_PATH+1]; + + if (!bWindowsNT) + return TRUE; + + do { + _snwprintf(aux1, sizeof(aux1), _T("Kbd%d"), i); + _snwprintf(aux2, sizeof(aux2), _T("\\Device\\KeyboardClass%d"), i); + DefineDosDevice(DDD_RAW_TARGET_PATH, aux1, aux2); + + _snwprintf(aux1, sizeof(aux1), _T("\\\\.\\Kbd%d"), i); + hKbdDev[i] = CreateFile(aux1, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + + } while (hKbdDev[i] != INVALID_HANDLE_VALUE && ++i < MAX_KBDHANDLES); + + return hKbdDev[0] != INVALID_HANDLE_VALUE; +} + +BOOL ToggleKeyboardLights(BYTE byte) +{ + int i; BOOL result = FALSE; + KEYBOARD_INDICATOR_PARAMETERS InputBuffer; // Input buffer for DeviceIoControl + ULONG DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS); + ULONG ReturnedLength; // Number of bytes returned in output buffer + + if (bEmulateKeypresses) + return keypresses_ToggleKeyboardLights(byte); + + if (!bWindowsNT) { + outportb(0x60, 0xED); + Sleep(10); + outportb(0x60, byte); + return TRUE; + } + + InputBuffer.UnitId = 0; + InputBuffer.LedFlags = byte; + + for (i=0; i < MAX_KBDHANDLES && hKbdDev[i] != INVALID_HANDLE_VALUE; i++) + result |= DeviceIoControl(hKbdDev[i], IOCTL_KEYBOARD_SET_INDICATORS, &InputBuffer, DataLength, NULL, 0, &ReturnedLength, NULL); + + return result; +} + +void CloseKeyboardDevice() +{ + int i = 0; + TCHAR aux[MAX_PATH+1]; + + if (!bWindowsNT) + return; + + do { + if (hKbdDev[i] != INVALID_HANDLE_VALUE) + CloseHandle(hKbdDev[i]); + + _snwprintf(aux, sizeof(aux), _T("Kbd%d"), i); + DefineDosDevice(DDD_REMOVE_DEFINITION, aux, NULL); + + } while (hKbdDev[i] != INVALID_HANDLE_VALUE && ++i < MAX_KBDHANDLES); +} diff --git a/plugins/KeyboardNotify/src/keyboard.h b/plugins/KeyboardNotify/src/keyboard.h new file mode 100644 index 0000000000..8fe6b52fe9 --- /dev/null +++ b/plugins/KeyboardNotify/src/keyboard.h @@ -0,0 +1,21 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +BOOL OpenKeyboardDevice(void); +BOOL ToggleKeyboardLights(BYTE); +void CloseKeyboardDevice(void); diff --git a/plugins/KeyboardNotify/src/keypresses.cpp b/plugins/KeyboardNotify/src/keypresses.cpp new file mode 100644 index 0000000000..6d1cef58e6 --- /dev/null +++ b/plugins/KeyboardNotify/src/keypresses.cpp @@ -0,0 +1,77 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0500 + +#include +#include "flash.h" +#include "keypresses.h" + + +// Prototypes +void SetLock(WORD, BYTE, unsigned int *, INPUT *); + +// Globals +BOOL LEDstateSaved = FALSE; +BYTE LEDstate; + + +void keypresses_RestoreLEDState(void) +{ + if (LEDstateSaved) + keypresses_ToggleKeyboardLights(LEDstate); + LEDstateSaved = FALSE; +} + +BOOL keypresses_ToggleKeyboardLights(BYTE byte) +{ + unsigned int n = 0; + INPUT keystrokes[6] = {0}; + + if (!LEDstateSaved) { + LEDstate = (BYTE)(LedState(VK_SCROLL) + (LedState(VK_NUMLOCK)<<1) + (LedState(VK_CAPITAL)<<2)); + LEDstateSaved = TRUE; + } + + SetLock(VK_NUMLOCK, (BYTE)(byte&2), &n, keystrokes); + SetLock(VK_CAPITAL, (BYTE)(byte&4), &n, keystrokes); + SetLock(VK_SCROLL, (BYTE)(byte&1), &n, keystrokes); + SendInput(n, keystrokes, sizeof(INPUT)); + + return TRUE; +} + +void SetLock(WORD keyCode, BYTE value, unsigned int *n, INPUT *keystrokes) +{ + BYTE status; + + GetAsyncKeyState(keyCode); + status = GetKeyState(keyCode) & 1; + + if ((!value && status) || (value && !status)) { + keystrokes[*n].type = INPUT_KEYBOARD; + keystrokes[*n].ki.wVk = keyCode; + keystrokes[*n].ki.wScan = 0x45; + keystrokes[(*n)++].ki.dwFlags = KEYEVENTF_EXTENDEDKEY | 0; + keystrokes[*n].type = INPUT_KEYBOARD; + keystrokes[*n].ki.wVk = keyCode; + keystrokes[*n].ki.wScan = 0x45; + keystrokes[(*n)++].ki.dwFlags = KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP; + } +} diff --git a/plugins/KeyboardNotify/src/keypresses.h b/plugins/KeyboardNotify/src/keypresses.h new file mode 100644 index 0000000000..57e99aa25c --- /dev/null +++ b/plugins/KeyboardNotify/src/keypresses.h @@ -0,0 +1,20 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +void keypresses_RestoreLEDState(void); +BOOL keypresses_ToggleKeyboardLights(BYTE); diff --git a/plugins/KeyboardNotify/src/main.cpp b/plugins/KeyboardNotify/src/main.cpp new file mode 100644 index 0000000000..e82cc2cfdc --- /dev/null +++ b/plugins/KeyboardNotify/src/main.cpp @@ -0,0 +1,1448 @@ +/* + KeyboardNotify plugin v1.5 for Miranda IM + _________________________________________ + + Copyright (C) 2002,2003 Martin Öberg + Copyright (C) 2004 Std + Copyright (C) 2005,2006 TioDuke (tioduke@yahoo.ca) + + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + + Description + ----------- + This plugin for Miranda-IM notifies user of specified events (as incoming messages, + incoming files, incoming URLs or other events). This plugin is based on the original one + by Martin Öberg (aka strickz) and Std's modifications (mainly the idea of using direct + port handling using a driver). + It has many options allowing: + a) To select on which events to react + b) Under which conditions (eg: fullscreen mode, ScreenSaver running, workstation locked) + c) To act only if the protocol receiving the event is under specified status + d) For message events you can choose to be notified if the message window is open or not + e) A notification feature allowing to be notified of pending events (unopen events) + after specified period of time + f) To select method for stopping the blinking (after x secs, if Miranda is re-attended, + if Windows is re-attended, if all notified events are opened or when the notify conditions + end) + g) And several flashing options: select leds to blink, effects (all at the same time, + in turn, in sequence and like KITT!), preview button + It was designed to be flexible and performing several different tasks. It can be + configured to act like the original one and has several functions from other Miranda's + keyboard notifier plugins. + It also provides a service to allow third party plugins use its notifier abilities. + + Options + ------- + Options page Options->Plugins->Keyboard Flash. Tabbed: Protocols, Rules (when), Flashing (how), Themes and Ignore. + + Thanks + ------ + - Pete for the numerous patches he sent, actively helping to improve the code and + functionality + - UnregistereD for great help in solving problem with Windows activity detection + - Slacktarn, Sir_qwerty and Tweety for giving great help with ideas (most of the new + features included in this plugin were suggested by them) and testing + - The authors of AAA, PopUp+, KeyScrollNotify, original KeyboardNotify, Neweventnotify, + IEView, NGEventNotify for part of their code used in this plugin. + - Vampik fot the InTurn flashing option + - Miranda IM developers for this amazing program + - all other people from Miranda community + + History + ------- + 1.5.7.7: + [!] Added support for Miranda 0.8.x.x. + 1.5.7.6: + [!] Fixed bug in Ignore module. + 1.5.7.5: + [!] Updated TriggerPlugin support for latest version. + 1.5.7.4: + [*] Updated screenshot + [*] Minor code cleaning + 1.5.7.3: + [+] Added xstatus support + 1.5.7.2: + [+] Added per contact Ignore options + 1.5.7.1: + [!] Fix in Options for themes under WinXP+ (really essential feature) + 1.5.7.0: + [+] Added support for Trigger plugin + 1.5.6.3: + [-] Removed device presence validation: it is not needed now that the plugin works on USB (thanks Nick, aka Aestetic) + [+] Added a new service to the API for 'normalizing' a custom flashing sequence string + [-] Simplified the API (the extended version of the start blink service is no longer needed). + 1.5.6.2: + [!] Fixed problem while trying to detect if message window is in foreground. + 1.5.6.1: + [!] Fixed bug with keypress emulation and "until Windows is re-attended" option. + 1.5.6.0: + [+] Option to emulate keypresses (for the USB people) + [*] Changed the emergency key (to make it stop with PAUSE instead of SCROLL LOCK key). + 1.5.5.4: + [*] Improved ListView control handling + [*] Changed the default values (for the sake of new users). + 1.5.5.3: + [*] More code optimization. + 1.5.5.2: + [+] Support for Update plugin. + 1.5.5.1: + [!] Minor source fixes. + 1.5.5.0: + [+] New 'notify when' option: while defined programs are running (just like gamerstatus) + [+] Extended the API to add two new services to disable and re-enable keyboard notifications (for use by bosskey plugin). + 1.5.4.4: + [!] Fixed (hopefully) problems with some system configurations (with PS2 keyboards) where the KeyboardClass0 device was not the apropriate one (thanks pete!) + [+] Extended the plugin API (requested bt tweety). + 1.5.4.3: + [!] Fixed some compatibility issues with nconvers++ (thank you donatas for your help). + 1.5.4.2: + [!] Fixed problem with Windows' activity detection under Win9X when using other plugins that do the same. + [!] Fixed crash caused by incoming authorisation requests when metacontacts was enabled. + 1.5.4.1: + [!] Some corrections on third party plugins events handling (now they are more assimilated to the 'other events') + [*] Some code cleaning + [!] Fixed problem with first message in Metacontacts recognition while checking for pending events (thank you again NirG) + 1.5.4.0: + [+] New plugin API (thank you CriS for your ideas and great help) + [!] Added Offline status to status check list (thank you Slaktarn for finding it). + 1.5.3.4: + [!] Fixed Metacontacts recognition in checking and counting of pending events (thank you NirG for finding the problem) + [!] Fixed problems with multiple instances of the plugin running (thank you tweety for reporting and testing). + 1.5.3.3: + [!] Changed behaviour of Preview button to make it independent of the rules' options. + 1.5.3.2: + [+] New dialog to asign leds to specific events for the trillian-like sequences. + 1.5.3.1: + [!] Fixed bug of loosing any other until setting when selecting 'Events are opened'. + 1.5.3.0: + [+] Applied pete's patches (thank you very much for your great work) + - Use of GetLastInputInfo when possible for detecting Windows' activity + - Made Windows' mouse hooks also aware of mouse clicking + - Made Miranda re-attended option react on windows restoring and ignoring mouse hovering an unfocused window + - New option for message events to avoid blinking if message window is focused + - Made the plugin handle metacontact's special issues + [!] Use of the new message API for windows detection when possible + [+] New message event option to check last message timestamp (requested by D46MD) + [+] Possibility of choosing more than one flash until option at the same time + [+] New flashing effect to make the leds blink accordingly to number of events + [+] Possibility of selecting/unselecting protocols (requested by tweety, usuful to avoid flashing on some protocols as rss) + 1.5.2.2: + [!] scriver's message window detection (thanks D46MD for your great help) + [!] corrected 'flash until' checking accordingly to pete's patch (thank you) + 1.5.2.1: + [!] nconvers++'s message window detection + [!] checked window detection for srmm, scriver, sramm and srmm_mod + 1.5.2.0: + [+] Custom theme support + [-] Custom order history + 1.5.1.0: + [+] Custom order effect + [+] Custom order history + 1.5.0.0: + [+] Drivers aren't needed anymore + [+] Status selection option + [+] Miranda/Windows activity detection (thank you Peter Boon) + [+] 'Opened events' stop method + [+] x seconds stop method + [+] Hooking database event for detecting incoming events + [+] Notifier option for pending events + [+] Checkbox for enabling disabling open messages notification + [+] In sequence and KIT flashing effects + [+] Preview button + [+] Tabbed options + [!] Several corrections/improvements in options page + [!] Not selected leds will preserve their original state + 1.4.1.0: (by me and Vampik) + [+] Notify on fullscreen, screensaver, worksation locked + [!] Try to improve Win98 keysimulation routines + [+] Added InTurn effect (thank you Vampik) + [!] Corrected speed of blinking (thank you Vampik) + 1.4.0.0: (by Std, unreleased) + [+] Added direct port handling using PortTalk.sys driver + 1.3.0.0: (by strickz) + This is strickz' final release. It still uses keypress simulation. It was nice (thanks *g*) + + +*/ + +#define WIN32_LEAN_AND_MEAN +#define _WIN32_WINNT 0x0500 + +#include +#include +#include +#include "flash.h" +#include "ignore.h" +#include "keyboard.h" +#include "trigger.h" +#include "constants.h" +#include "protolist.h" +#include "EnumProc.h" +#include "utils.h" +#include "m_kbdnotify.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#pragma comment(lib, "advapi32.lib") + +#define NCONVERS_BLINKID ((HANDLE)123456) //nconvers' random identifier used to flash an icon for "incoming message" on contact list + +#ifndef SPI_GETSCREENSAVERRUNNING +#define SPI_GETSCREENSAVERRUNNING 114 +#endif + +#ifndef WM_XBUTTONDBLCLK +#define WM_XBUTTONDBLCLK 0x020D +#endif +#ifndef WM_NCXBUTTONDBLCLK +#define WM_NCXBUTTONDBLCLK 0x00AD +#endif + + +HINSTANCE hInst; + +int hLangpack; + +DWORD IDThread = 0; +HANDLE hThread = NULL; +HANDLE hFlashEvent; +HANDLE hExitEvent; + +HANDLE hModulesLoaded = NULL; +HANDLE hMsgEventHook = NULL; +HANDLE hOptionsInitialize = NULL; +HANDLE hEnableService = NULL; +HANDLE hDisableService = NULL; +HANDLE hStartBlinkService = NULL; +HANDLE hEventsOpenedService = NULL; +HANDLE hFlashingEventService = NULL; +HANDLE hNormalizeSequenceService = NULL; + +HHOOK hMirandaMouseHook = NULL; +HHOOK hMirandaKeyBoardHook = NULL; +HHOOK hMirandaWndProcHook = NULL; +UINT hReminderTimer = 0; + +#pragma data_seg("Shared") +HHOOK hMouseHook = NULL; +HHOOK hKeyBoardHook = NULL; +BYTE bEmulateKeypresses = 0; +DWORD dwLastInput = 0; +POINT lastGlobalMousePos = {0, 0}; +#pragma data_seg() +#pragma comment(linker, "/section:Shared,rws") + +static BOOL (WINAPI * MyGetLastInputInfo)(PLASTINPUTINFO); + + +BYTE bFlashOnMsg; +BYTE bFlashOnURL; +BYTE bFlashOnFile; +BYTE bFlashOnOther; +BYTE bFullScreenMode; +BYTE bScreenSaverRunning; +BYTE bWorkstationLocked; +BYTE bProcessesAreRunning; +BYTE bWorkstationActive; +BYTE bFlashIfMsgOpen; +BYTE bFlashIfMsgWinNotTop; +BYTE bFlashIfMsgOlder; +WORD wSecondsOlder; +BYTE bFlashUntil; +WORD wBlinksNumber; +BYTE bMirandaOrWindows; +WORD wStatusMap; +WORD wReminderCheck; +BYTE bFlashLed[3]; +BYTE bFlashEffect; +BYTE bSequenceOrder; +WORD wCustomTheme; +WORD wStartDelay; +BYTE bFlashSpeed; +BYTE bOverride; +BYTE bTrillianLedsMsg; +BYTE bTrillianLedsURL; +BYTE bTrillianLedsFile; +BYTE bTrillianLedsOther; + +PROTOCOL_LIST ProtoList = {0, NULL}; +PROCESS_LIST ProcessList = {0, NULL}; + +double dWinVer; +BOOL bWindowsNT; + +int nWaitDelay; +unsigned int nExternCount = 0; +BOOL bFlashingEnabled = TRUE; +BOOL bReminderDisabled = FALSE; + +char *szMetaProto = NULL; +BYTE bMetaProtoEnabled = 0; + +#define MIID_KBDNOTIFY {0x119d7288, 0x2050, 0x448d, { 0x99, 0x00, 0xd8, 0x6a, 0xc7, 0x04, 0x26, 0xbf }} + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + "Keyboard Notify Ext.", + PLUGIN_MAKE_VERSION(1,5,7,7), + "Flashes your keyboard LEDs when a message has arrived", + "TioDuke", + "tioduke@yahoo.ca", + "Š 2002-2003 M.Öberg, 2004 Std, 2005-2008 TioDuke", + "http://addons.miranda-im.org/", + UNICODE_AWARE, //doesn't replace anything built-in + MIID_KBDNOTIFY //{119D7288-2050-448d-9900-D86AC70426BF} +}; + + + +int InitializeOptions(WPARAM,LPARAM); +void LoadSettings(void); +int HookWindowsHooks(void); +int UnhookWindowsHooks(void); +static LRESULT CALLBACK MouseHookFunction(int, WPARAM, LPARAM); +static LRESULT CALLBACK KeyBoardHookFunction(int, WPARAM, LPARAM); +static LRESULT CALLBACK MirandaMouseHookFunction(int, WPARAM, LPARAM); +static LRESULT CALLBACK MirandaKeyBoardHookFunction(int, WPARAM, LPARAM); +static LRESULT CALLBACK MirandaWndProcHookFunction(int, WPARAM, LPARAM); +BOOL CheckMsgWnd(HANDLE, BOOL *); + + +BOOL isMetaContactsSubContact(HANDLE hMetaContact, HANDLE hContact) +{ + char *szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hMetaContact, 0); + if (szProto && !strcmp(szMetaProto, szProto)) { // Safety check + int i = DBGetContactSettingDword(hContact, szMetaProto, "ContactNumber", -1); + if (i >= 0 && hContact == (HANDLE)CallService(MS_MC_GETSUBCONTACT, (WPARAM)hMetaContact, i)) + return TRUE; + } + return FALSE; +} + + +BOOL checkOpenWindow(HANDLE hContact) +{ + BOOL found, focus; + + if (bFlashIfMsgOpen && !bFlashIfMsgWinNotTop) + return TRUE; + + found = CheckMsgWnd(hContact, &focus); + if (!found && szMetaProto && bMetaProtoEnabled) { + HANDLE hMetaContact = (HANDLE)DBGetContactSettingDword(hContact, szMetaProto, "Handle", 0); + if (hMetaContact && isMetaContactsSubContact(hMetaContact, hContact)) + found = CheckMsgWnd(hMetaContact, &focus); + } + if (!found) + return TRUE; + + if (bFlashIfMsgOpen && !focus) + return TRUE; + + return FALSE; +} + + +BOOL IsSaverOnNT4() +{ + HDESK hd = OpenDesktop(L"screen-saver", 0, FALSE, MAXIMUM_ALLOWED); + + if(hd == NULL) + return GetLastError()==ERROR_ACCESS_DENIED; + + CloseDesktop(hd); + return TRUE; +} + + +BOOL isScreenSaverRunning() +{ + BOOL screenSaverIsRunning=FALSE; + + if (bWindowsNT && dWinVer < 5) return IsSaverOnNT4(); + + SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &screenSaverIsRunning, FALSE); + return screenSaverIsRunning; +} + + +/* this function is from the original idle module */ +BOOL isWorkstationLocked() +{ + HDESK hd; + char buf[MAX_PATH]; + + if (!bWindowsNT) return FALSE; + + hd = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED); /* if it fails then the workstation is prolly locked anyway */ + if (hd == NULL) return TRUE; + GetUserObjectInformation(hd, UOI_NAME, buf, sizeof(buf), NULL); /* if we got it (hmm,) get a name */ + CloseDesktop(hd); + return strcmp(buf, "Winlogon")==0; +} + + +BOOL isFullScreen() +{ + int w = GetSystemMetrics(SM_CXSCREEN); + int h = GetSystemMetrics(SM_CYSCREEN); + + HWND hWnd = 0; + while (hWnd = FindWindowEx(NULL, hWnd, NULL, NULL)) { + RECT WindowRect; + + if (!(GetWindowLongPtr(hWnd, GWL_EXSTYLE) & WS_EX_TOPMOST)) + continue; + + GetWindowRect(hWnd, &WindowRect); + if ((w != (WindowRect.right - WindowRect.left)) || (h != (WindowRect.bottom - WindowRect.top))) + continue; + + return TRUE; + } + + return FALSE; +} + + +BOOL checkNotifyOptions() +{ + BOOL fullScreenMode, screenSaverIsRunning, workstationIsLocked, processesRunning; + + screenSaverIsRunning = isScreenSaverRunning(); + if (screenSaverIsRunning && bScreenSaverRunning) + return TRUE; + + workstationIsLocked = isWorkstationLocked(); + if (workstationIsLocked && bWorkstationLocked) + return TRUE; + + fullScreenMode = isFullScreen() && !screenSaverIsRunning; + if (fullScreenMode && bFullScreenMode) + return TRUE; + + processesRunning = areThereProcessesRunning(); + if (processesRunning && bProcessesAreRunning) + return TRUE; + + return (!fullScreenMode && !screenSaverIsRunning && !workstationIsLocked && !processesRunning && bWorkstationActive); +} + + +BOOL isStatusEnabled(int status) +{ + switch (status) { + case ID_STATUS_OFFLINE: return wStatusMap & MAP_OFFLINE; + case ID_STATUS_ONLINE: return wStatusMap & MAP_ONLINE; + case ID_STATUS_AWAY: return wStatusMap & MAP_AWAY; + case ID_STATUS_NA: return wStatusMap & MAP_NA; + case ID_STATUS_OCCUPIED: return wStatusMap & MAP_OCCUPIED; + case ID_STATUS_DND: return wStatusMap & MAP_DND; + case ID_STATUS_FREECHAT: return wStatusMap & MAP_FREECHAT; + case ID_STATUS_INVISIBLE: return wStatusMap & MAP_INVISIBLE; + case ID_STATUS_ONTHEPHONE: return wStatusMap & MAP_ONTHEPHONE; + case ID_STATUS_OUTTOLUNCH: return wStatusMap & MAP_OUTTOLUNCH; + default: return FALSE; + } +} + + +BOOL checkGlobalStatus() +{ + return isStatusEnabled(CallService(MS_CLIST_GETSTATUSMODE, 0, 0)); +} + + +BOOL checkGlobalXstatus() +{ + ICQ_CUSTOM_STATUS xstatus={0}; + unsigned int i, protosSupporting; int status=0; + + for(i=0, protosSupporting=0; i < ProtoList.protoCount; i++) { + if (!ProtoList.protoInfo[i].enabled || !ProtoList.protoInfo[i].xstatus.count) continue; + + protosSupporting++; + // Retrieve xstatus for protocol + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_MASK_STATUS; + xstatus.status = &status; + CallProtoService(ProtoList.protoInfo[i].szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus); + + if (ProtoList.protoInfo[i].xstatus.enabled[status]) return TRUE; + } + + if (!protosSupporting) + return TRUE; + else + return FALSE; +} + + +DBEVENTINFO createMsgEventInfo(HANDLE hContact) +{ + DBEVENTINFO einfo = {0}; + + einfo.cbSize = sizeof(einfo); + einfo.eventType = EVENTTYPE_MESSAGE; + einfo.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + + return einfo; +} + + +DBEVENTINFO readEventInfo(HANDLE hDbEvent, HANDLE hContact) +{ + DBEVENTINFO einfo = {0}; + + if (hDbEvent == NCONVERS_BLINKID) // we need to handle nconvers' blink event + return createMsgEventInfo(hContact); + + einfo.cbSize = sizeof(einfo); + einfo.cbBlob = 0; + einfo.pBlob = NULL; + CallService(MS_DB_EVENT_GET, (WPARAM)hDbEvent, (LPARAM)&einfo); + + return einfo; +} + + +BOOL checkIgnore(HANDLE hContact, WORD eventType) +{ + return !IsIgnored(hContact, eventType); +} + + +BOOL checkProtocol(char *szProto) +{ + unsigned int i; + + if (!szProto) + return FALSE; + + for(i=0; i < ProtoList.protoCount; i++) + if (ProtoList.protoInfo[i].szProto && !strcmp(ProtoList.protoInfo[i].szProto, szProto)) + return ProtoList.protoInfo[i].enabled; + + return FALSE; +} + + +BOOL metaCheckProtocol(char *szProto, HANDLE hContact, WORD eventType) +{ + HANDLE hSubContact=NULL; + + if (szMetaProto && bMetaProtoEnabled && szProto && !strcmp(szMetaProto, szProto)) + if (hSubContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0)) + szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hSubContact, 0); + + return checkProtocol(szProto) && checkIgnore(hSubContact?hSubContact:hContact, eventType); +} + + +BOOL checkUnopenEvents() +{ + int nIndex; + CLISTEVENT *pCLEvent; + + if (nExternCount && bFlashOnOther) + return TRUE; + + for (nIndex = 0; pCLEvent = (CLISTEVENT*)CallService(MS_CLIST_GETEVENT, -1, nIndex); nIndex++) { + DBEVENTINFO einfo = readEventInfo(pCLEvent->hDbEvent, pCLEvent->hContact); + + if ((einfo.eventType == EVENTTYPE_MESSAGE && bFlashOnMsg) || + (einfo.eventType == EVENTTYPE_URL && bFlashOnURL) || + (einfo.eventType == EVENTTYPE_FILE && bFlashOnFile) || + (einfo.eventType != EVENTTYPE_MESSAGE && einfo.eventType != EVENTTYPE_URL && einfo.eventType != EVENTTYPE_FILE && bFlashOnOther)) + + if (metaCheckProtocol(einfo.szModule, pCLEvent->hContact, einfo.eventType)) + return TRUE; + } + + return FALSE; +} + + +static void FlashThreadFunction() +{ + BOOL bEvent = FALSE; + DWORD dwEventStarted, dwFlashStarted; + BYTE data, unchangedLeds; + + while (TRUE) { + unchangedLeds = (BYTE)(LedState(VK_PAUSE) * !bFlashLed[2] + ((LedState(VK_NUMLOCK) * !bFlashLed[0])<<1) + ((LedState(VK_CAPITAL) * !bFlashLed[1])<<2)); + GetAsyncKeyState(VK_PAUSE); // empty Pause/Break's keystroke buffer + + // Start flashing + while(bEvent && bFlashingEnabled) + { + // Let's give the user the opportunity of finishing flashing manually :) + if (GetAsyncKeyState(VK_PAUSE) & 1) + break; + + if ((bFlashUntil & UNTIL_NBLINKS) && GetTickCount() > (dwFlashStarted + wBlinksNumber * 1000)) + break; + if (bFlashUntil & UNTIL_REATTENDED) { + if (bMirandaOrWindows == ACTIVE_WINDOWS && MyGetLastInputInfo && !bEmulateKeypresses) { + LASTINPUTINFO lii; + ZeroMemory(&lii, sizeof(lii)); + lii.cbSize = sizeof(lii); + MyGetLastInputInfo(&lii); + dwLastInput = lii.dwTime; + } + if (dwLastInput > dwEventStarted) + break; + } + if ((bFlashUntil & UNTIL_EVENTSOPEN) && !checkUnopenEvents()) + break; + if ((bFlashUntil & UNTIL_CONDITIONS) && (!checkNotifyOptions() || !checkGlobalStatus() || !checkGlobalXstatus())) + break; + + data = getBlinkingLeds(); + ToggleKeyboardLights((BYTE)(data|unchangedLeds)); + + // Wait for exit event + if (WaitForSingleObject(hExitEvent, nWaitDelay) == WAIT_OBJECT_0) + return; + } + RestoreLEDState(); + + setFlashingSequence(); + bReminderDisabled = FALSE; + + // Wait for new event + { + DWORD dwEvent; + HANDLE Objects[2]; + Objects[0] = hFlashEvent; + Objects[1] = hExitEvent; + dwEvent = WaitForMultipleObjects(2, Objects, FALSE, INFINITE); + if ((dwEvent - WAIT_OBJECT_0) == 1) + return; + } + + bEvent = TRUE; + bReminderDisabled = TRUE; + dwEventStarted = GetTickCount(); + // Wait StartDelay seconds + if (wStartDelay > 0) + Sleep(wStartDelay * 1000); + dwFlashStarted = GetTickCount(); + + } + +} + + +BOOL checkMsgTimestamp(HANDLE hEventCurrent, DWORD timestampCurrent) +{ + HANDLE hEvent; + + if (!bFlashIfMsgOlder) + return TRUE; + + for (hEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hEventCurrent, 0); hEvent; hEvent=(HANDLE)CallService(MS_DB_EVENT_FINDPREV, (WPARAM)hEvent, 0)) { + DBEVENTINFO einfo = {0}; + + einfo.cbSize = sizeof(einfo); + einfo.cbBlob = 0; + einfo.pBlob = NULL; + CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&einfo); + if ((einfo.timestamp + wSecondsOlder) <= timestampCurrent) + return TRUE; + if (einfo.eventType == EVENTTYPE_MESSAGE) + return FALSE; + } + + return TRUE; +} + + +BOOL contactCheckProtocol(char *szProto, HANDLE hContact, WORD eventType) +{ + if (szMetaProto && bMetaProtoEnabled && hContact) { + HANDLE hMetaContact = (HANDLE)DBGetContactSettingDword(hContact, szMetaProto, "Handle", 0); + if (hMetaContact && isMetaContactsSubContact(hMetaContact, hContact)) + return FALSE; + } + + return (metaCheckProtocol(szProto, hContact, eventType)); +} + + +BOOL checkStatus(char *szProto) +{ + if (!szProto) + return checkGlobalStatus(); + + return isStatusEnabled(CallProtoService(szProto, PS_GETSTATUS, 0, 0)); +} + + +BOOL checkXstatus(char *szProto) +{ + unsigned int i; int status=0; + ICQ_CUSTOM_STATUS xstatus={0}; + + if (!szProto) + return checkGlobalXstatus(); + + for(i=0; i < ProtoList.protoCount; i++) + if (ProtoList.protoInfo[i].szProto && !strcmp(ProtoList.protoInfo[i].szProto, szProto)) { + if (!ProtoList.protoInfo[i].xstatus.count) return TRUE; + + // Retrieve xstatus for protocol + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_MASK_STATUS; + xstatus.status = &status; + CallProtoService(ProtoList.protoInfo[i].szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus); + + return ProtoList.protoInfo[i].xstatus.enabled[status]; + } + + return TRUE; +} + + +// 'Pings' the FlashThread to keep the LEDs flashing. +static int PluginMessageEventHook(WPARAM wParam, LPARAM lParam) +{ + DBEVENTINFO einfo = {0}; + HANDLE hContact = (HANDLE)wParam; + HANDLE hEvent = (HANDLE)lParam; + + //get DBEVENTINFO without pBlob + einfo.cbSize = sizeof(einfo); + einfo.cbBlob = 0; + einfo.pBlob = NULL; + CallService(MS_DB_EVENT_GET, (WPARAM)hEvent, (LPARAM)&einfo); + + if (!(einfo.flags & DBEF_SENT)) + if ((einfo.eventType == EVENTTYPE_MESSAGE && bFlashOnMsg && checkOpenWindow(hContact) && checkMsgTimestamp(hEvent, einfo.timestamp)) || + (einfo.eventType == EVENTTYPE_URL && bFlashOnURL) || + (einfo.eventType == EVENTTYPE_FILE && bFlashOnFile) || + (einfo.eventType != EVENTTYPE_MESSAGE && einfo.eventType != EVENTTYPE_URL && einfo.eventType != EVENTTYPE_FILE && bFlashOnOther)) { + + if (contactCheckProtocol(einfo.szModule, hContact, einfo.eventType) && checkNotifyOptions() && checkStatus(einfo.szModule) && checkXstatus(einfo.szModule)) + + SetEvent(hFlashEvent); + } + + return 0; +} + + +// ** +// ** Checks for pending events. If it finds any, it pings the FlashThread to keep the LEDs flashing. +// ** + +static VOID CALLBACK ReminderTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime) +{ + int nIndex; + CLISTEVENT *pCLEvent; + + if (!bReminderDisabled && nExternCount && bFlashOnOther) { + SetEvent(hFlashEvent); + return; + } + + for (nIndex = 0; !bReminderDisabled && (pCLEvent = (CLISTEVENT*)CallService(MS_CLIST_GETEVENT, -1, nIndex)); nIndex++) { + DBEVENTINFO einfo = readEventInfo(pCLEvent->hDbEvent, pCLEvent->hContact); + + if ((einfo.eventType == EVENTTYPE_MESSAGE && bFlashOnMsg) || + (einfo.eventType == EVENTTYPE_URL && bFlashOnURL) || + (einfo.eventType == EVENTTYPE_FILE && bFlashOnFile) || + (einfo.eventType != EVENTTYPE_MESSAGE && einfo.eventType != EVENTTYPE_URL && einfo.eventType != EVENTTYPE_FILE && bFlashOnOther)) + + if (metaCheckProtocol(einfo.szModule, pCLEvent->hContact, einfo.eventType) && checkNotifyOptions() && checkStatus(einfo.szModule) && checkXstatus(einfo.szModule)) { + + SetEvent(hFlashEvent); + return; + } + } + +} + + +// Support for third-party plugins and mBot's scripts +static INT_PTR EnableService(WPARAM wParam, LPARAM lParam) +{ + bFlashingEnabled = TRUE; + return 0; +} + +static INT_PTR DisableService(WPARAM wParam, LPARAM lParam) +{ + bFlashingEnabled = FALSE; + return 0; +} + +static INT_PTR StartBlinkService(WPARAM wParam, LPARAM lParam) +{ + nExternCount += (unsigned int)wParam; + if (bFlashOnOther && checkNotifyOptions() && checkGlobalStatus() && checkGlobalXstatus()) { + if (lParam) + useExternSequence((TCHAR *)lParam); + SetEvent(hFlashEvent); + } + + return 0; +} + +static INT_PTR EventsWereOpenedService(WPARAM wParam, LPARAM lParam) +{ + if ((unsigned int)wParam > nExternCount) + nExternCount = 0; + else + nExternCount -= (unsigned int)wParam; + + return 0; +} + + +static INT_PTR IsFlashingActiveService(WPARAM wParam, LPARAM lParam) +{ + if (!bReminderDisabled) + return 0; + + return (int)getCurrentSequenceString(); +} + + +INT_PTR NormalizeSequenceService(WPARAM wParam, LPARAM lParam) +{ + TCHAR strAux[MAX_PATH+1], *strIn = (TCHAR *)lParam; + + _snwprintf(strAux, MAX_PATH, _T("%s"), strIn); + _snwprintf(strIn, MAX_PATH, _T("%s"), normalizeCustomString(strAux)); + + return (int)strIn; +} + + +// Support for Trigger plugin +static void ForceEventsWereOpenedThread(void *eventMaxSeconds) +{ + Sleep(((WORD)eventMaxSeconds) * 1000); + CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, 0); +} + + +void StartBlinkAction(char *flashSequence, WORD eventMaxSeconds) +{ + DWORD threadID = 0; + + if (eventMaxSeconds) + CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ForceEventsWereOpenedThread, (void *)eventMaxSeconds, 0, &threadID); + + CallService(MS_KBDNOTIFY_STARTBLINK, 1, (LPARAM)flashSequence); +} + + +void createProcessList(void) +{ + DBVARIANT dbv; + unsigned int i, count; + + count = (unsigned int)DBGetContactSettingWord(NULL, KEYBDMODULE, "processcount", 0); + + ProcessList.count = 0; + ProcessList.szFileName = (TCHAR **)malloc(count * sizeof(TCHAR *)); + if (ProcessList.szFileName) { + for(i=0; i < count; i++) + if (DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("process%d", i), &dbv)) + ProcessList.szFileName[i] = NULL; + else { + ProcessList.szFileName[i] = (TCHAR *)malloc(wcslen(dbv.ptszVal) + 1); + if (ProcessList.szFileName[i]) + wcscpy(ProcessList.szFileName[i], dbv.ptszVal); + DBFreeVariant(&dbv); + } + ProcessList.count = count; + } + +} + + +void destroyProcessList(void) +{ + unsigned int i, count; + + count = ProcessList.count; + + ProcessList.count = 0; + for(i=0; i < count; i++) + if (ProcessList.szFileName[i]) + free(ProcessList.szFileName[i]); + + if (ProcessList.szFileName) + free(ProcessList.szFileName); + ProcessList.szFileName = NULL; +} + + +void LoadSettings(void) +{ + unsigned int i; + + bFlashOnMsg = DBGetContactSettingByte(NULL, KEYBDMODULE, "onmsg", DEF_SETTING_ONMSG); + bFlashOnURL = DBGetContactSettingByte(NULL, KEYBDMODULE, "onurl", DEF_SETTING_ONURL); + bFlashOnFile = DBGetContactSettingByte(NULL, KEYBDMODULE, "onfile", DEF_SETTING_ONFILE); + bFlashOnOther = DBGetContactSettingByte(NULL, KEYBDMODULE, "onother", DEF_SETTING_OTHER); + bFullScreenMode = DBGetContactSettingByte(NULL, KEYBDMODULE, "fscreenmode", DEF_SETTING_FSCREEN); + bScreenSaverRunning = DBGetContactSettingByte(NULL, KEYBDMODULE, "ssaverrunning", DEF_SETTING_SSAVER); + bWorkstationLocked = (bWindowsNT ? DBGetContactSettingByte(NULL, KEYBDMODULE, "wstationlocked", DEF_SETTING_LOCKED):0); + bProcessesAreRunning = DBGetContactSettingByte(NULL, KEYBDMODULE, "procsrunning", DEF_SETTING_PROCS); + bWorkstationActive = DBGetContactSettingByte(NULL, KEYBDMODULE, "wstationactive", DEF_SETTING_ACTIVE); + bFlashIfMsgOpen = DBGetContactSettingByte(NULL, KEYBDMODULE, "ifmsgopen", DEF_SETTING_IFMSGOPEN); + bFlashIfMsgWinNotTop = DBGetContactSettingByte(NULL, KEYBDMODULE, "ifmsgnottop", DEF_SETTING_IFMSGNOTTOP); + bFlashIfMsgOlder = DBGetContactSettingByte(NULL, KEYBDMODULE, "ifmsgolder", DEF_SETTING_IFMSGOLDER); + wSecondsOlder = DBGetContactSettingWord(NULL, KEYBDMODULE, "secsolder", DEF_SETTING_SECSOLDER); + bFlashUntil = DBGetContactSettingByte(NULL, KEYBDMODULE, "funtil", DEF_SETTING_FLASHUNTIL); + wBlinksNumber = DBGetContactSettingWord(NULL, KEYBDMODULE, "nblinks", DEF_SETTING_NBLINKS); + bMirandaOrWindows = DBGetContactSettingByte(NULL, KEYBDMODULE, "mirorwin", DEF_SETTING_MIRORWIN); + wStatusMap = DBGetContactSettingWord(NULL, KEYBDMODULE, "status", DEF_SETTING_STATUS); + wReminderCheck = DBGetContactSettingWord(NULL, KEYBDMODULE, "remcheck", DEF_SETTING_CHECKTIME); + bFlashLed[0] = !!DBGetContactSettingByte(NULL, KEYBDMODULE, "fnum", DEF_SETTING_FLASHNUM); + bFlashLed[1] = !!DBGetContactSettingByte(NULL, KEYBDMODULE, "fcaps", DEF_SETTING_FLASHCAPS); + bFlashLed[2] = !!DBGetContactSettingByte(NULL, KEYBDMODULE, "fscroll", DEF_SETTING_FLASHSCROLL); + bFlashEffect = DBGetContactSettingByte(NULL, KEYBDMODULE, "feffect", DEF_SETTING_FLASHEFFECT); + bSequenceOrder = DBGetContactSettingByte(NULL, KEYBDMODULE, "order", DEF_SETTING_SEQORDER); + wCustomTheme = DBGetContactSettingWord(NULL, KEYBDMODULE, "custom", DEF_SETTING_CUSTOMTHEME); + bTrillianLedsMsg = DBGetContactSettingByte(NULL, KEYBDMODULE, "ledsmsg", DEF_SETTING_LEDSMSG); + bTrillianLedsURL = DBGetContactSettingByte(NULL, KEYBDMODULE, "ledsurl", DEF_SETTING_LEDSURL); + bTrillianLedsFile = DBGetContactSettingByte(NULL, KEYBDMODULE, "ledsfile", DEF_SETTING_LEDSFILE); + bTrillianLedsOther = DBGetContactSettingByte(NULL, KEYBDMODULE, "ledsother", DEF_SETTING_LEDSOTHER); + wStartDelay = DBGetContactSettingWord(NULL, KEYBDMODULE, "sdelay", DEF_SETTING_STARTDELAY); + bFlashSpeed = DBGetContactSettingByte(NULL, KEYBDMODULE, "speed", DEF_SETTING_FLASHSPEED); + switch (bFlashSpeed) { + case 0: nWaitDelay = 1500; break; + case 1: nWaitDelay = 0750; break; + case 2: nWaitDelay = 0250; break; + case 3: nWaitDelay = 0150; break; + case 4: nWaitDelay = 0100; break; + default: nWaitDelay = 0050; break; + } + setFlashingSequence(); + bEmulateKeypresses = DBGetContactSettingByte(NULL, KEYBDMODULE, "keypresses", DEF_SETTING_KEYPRESSES); + bOverride = DBGetContactSettingByte(NULL, KEYBDMODULE, "override", DEF_SETTING_OVERRIDE); + // Create hidden settings (for test button) if needed + if (DBGetContactSettingByte(NULL, KEYBDMODULE, "testnum", -1) == -1) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "testnum", DEF_SETTING_TESTNUM); + if (DBGetContactSettingByte(NULL, KEYBDMODULE, "testsecs", -1) == -1) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "testsecs", DEF_SETTING_TESTSECS); + for(i=0; i < ProtoList.protoCount; i++) + if (ProtoList.protoInfo[i].visible) { + unsigned int j; + ProtoList.protoInfo[i].enabled = DBGetContactSettingByte(NULL, KEYBDMODULE, ProtoList.protoInfo[i].szProto, DEF_SETTING_PROTOCOL); + for(j=0; j < ProtoList.protoInfo[i].xstatus.count; j++) + ProtoList.protoInfo[i].xstatus.enabled[j] = DBGetContactSettingByte(NULL, KEYBDMODULE, fmtDBSettingName("%sxstatus%d", ProtoList.protoInfo[i].szProto, j), DEF_SETTING_XSTATUS); + } + + if (szMetaProto) + bMetaProtoEnabled = DBGetContactSettingByte(NULL, szMetaProto, "Enabled", 1); + + destroyProcessList(); + createProcessList(); + UnhookWindowsHooks(); + HookWindowsHooks(); +} + + +void GetWindowsVersion(void) +{ + OSVERSIONINFOEX osvi; + BOOL bOsVersionInfoEx; + + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) &osvi))) { + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (!GetVersionEx((OSVERSIONINFO *)&osvi)) + osvi.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS; + } + bWindowsNT = osvi.dwPlatformId==VER_PLATFORM_WIN32_NT; + dWinVer = osvi.dwMajorVersion + osvi.dwMinorVersion / 10.0; +} + + +void updateXstatusProto(PROTOCOL_INFO *protoInfo) +{ + unsigned int i; + char szServiceName[MAXMODULELABELLENGTH]; + ICQ_CUSTOM_STATUS xstatus={0}; + + mir_snprintf(szServiceName, sizeof(szServiceName), "%s%s", protoInfo->szProto, PS_ICQ_GETCUSTOMSTATUSEX); + if (!ServiceExists(szServiceName)) return; + + // Retrieve xstatus.count + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_STATUSES_COUNT; + xstatus.wParam = &(protoInfo->xstatus.count); + CallProtoService(protoInfo->szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus); + (protoInfo->xstatus.count)++; // Don't forget about xstatus=0 (None) + + // Alloc and initiailize xstatus.enabled array + protoInfo->xstatus.enabled = (BOOL *)malloc(protoInfo->xstatus.count * sizeof(BOOL)); + if (!protoInfo->xstatus.enabled) + protoInfo->xstatus.count = 0; + else + for(i=0; i < protoInfo->xstatus.count; i++) + protoInfo->xstatus.enabled[i] = FALSE; + +} + + +void createProtocolList(void) +{ + unsigned int i; + PROTOCOLDESCRIPTOR **proto; + + if (ServiceExists(MS_MC_GETPROTOCOLNAME)) + szMetaProto = (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0); + + CallService(MS_PROTO_ENUMPROTOCOLS, (WPARAM)&ProtoList.protoCount, (LPARAM)&proto); + ProtoList.protoInfo = (PROTOCOL_INFO *)malloc(ProtoList.protoCount * sizeof(PROTOCOL_INFO)); + if (!ProtoList.protoInfo) + ProtoList.protoCount = 0; + else + for(i=0; i < ProtoList.protoCount; i++) { + ProtoList.protoInfo[i].xstatus.count = 0; + ProtoList.protoInfo[i].xstatus.enabled = NULL; + ProtoList.protoInfo[i].szProto = (char *)malloc(strlen(proto[i]->szName) + 1); + if (!ProtoList.protoInfo[i].szProto) { + ProtoList.protoInfo[i].enabled = FALSE; + ProtoList.protoInfo[i].visible = FALSE; + } else { + strcpy(ProtoList.protoInfo[i].szProto, proto[i]->szName); + ProtoList.protoInfo[i].enabled = FALSE; + if (proto[i]->type != PROTOTYPE_PROTOCOL) + ProtoList.protoInfo[i].visible = FALSE; + else + if (szMetaProto && !strcmp(proto[i]->szName, szMetaProto)) + ProtoList.protoInfo[i].visible = FALSE; + else { + ProtoList.protoInfo[i].visible = TRUE; + updateXstatusProto(&(ProtoList.protoInfo[i])); + } + } + } + +} + + +// We use the profile name to create the first part of each event name +// We do so to avoid problems between different instances of the plugin concurrently running +void createEventPrefix(TCHAR *prefixName, size_t maxLen) +{ + size_t len; + TCHAR profileName[MAX_PATH+1], *str; + + getAbsoluteProfileName(profileName, MAX_PATH); + + while (str = wcschr(profileName, _T('\\'))) + *str = _T('/'); + if ((len = wcslen(profileName)) <= maxLen) + wcscpy(prefixName, profileName); + else { + str = profileName + len - maxLen / 2; + _snwprintf(prefixName, maxLen / 2, L"%s", profileName); + wcscat(prefixName, str); + } +} + + +// ** +// ** Everything below is just Miranda init/uninit stuff +// ** + + +static int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + TCHAR eventPrefix[MAX_PATH+1], eventName[MAX_PATH+1]; + + LoadProcsLibrary(); + if (bWindowsNT && dWinVer >= 5) + MyGetLastInputInfo = (BOOL (WINAPI *)(PLASTINPUTINFO)) GetProcAddress(GetModuleHandle(L"user32"), "GetLastInputInfo"); + else + MyGetLastInputInfo = NULL; + + createProtocolList(); + LoadSettings(); + + // Create some synchronisation objects + createEventPrefix(eventPrefix, MAX_PATH - 11); + _snwprintf(eventName, sizeof(eventName), _T("%s/FlashEvent"), eventPrefix); + hFlashEvent = CreateEvent(NULL, FALSE, FALSE, eventName); + _snwprintf(eventName, sizeof(eventName), _T("%s/ExitEvent"), eventPrefix); + hExitEvent = CreateEvent(NULL, FALSE, FALSE, eventName); + + hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FlashThreadFunction, NULL, 0, &IDThread); + + hMsgEventHook = HookEvent(ME_DB_EVENT_ADDED, PluginMessageEventHook); + hOptionsInitialize = HookEvent(ME_OPT_INITIALISE, InitializeOptions); + hEnableService = CreateServiceFunction(MS_KBDNOTIFY_ENABLE, EnableService); + hDisableService = CreateServiceFunction(MS_KBDNOTIFY_DISABLE, DisableService); + hStartBlinkService = CreateServiceFunction(MS_KBDNOTIFY_STARTBLINK, StartBlinkService); + hEventsOpenedService = CreateServiceFunction(MS_KBDNOTIFY_EVENTSOPENED, EventsWereOpenedService); + hFlashingEventService = CreateServiceFunction(MS_KBDNOTIFY_FLASHINGACTIVE, IsFlashingActiveService); + hNormalizeSequenceService = CreateServiceFunction(MS_KBDNOTIFY_NORMALSEQUENCE, NormalizeSequenceService); + + RegisterAction(); + if (ServiceExists("DBEditorpp/RegisterSingleModule")) + CallService("DBEditorpp/RegisterSingleModule", (WPARAM)KEYBDMODULE, 0); + + return 0; +} + + + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + + hInst = hinstDLL; + + return TRUE; + +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +extern "C" __declspec(dllexport) int Load(void) +{ + + mir_getLP(&pluginInfo); + + GetWindowsVersion(); + OpenKeyboardDevice(); + hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + + return 0; +} + + + +void destroyProtocolList(void) +{ + unsigned int i; + + for(i=0; i < ProtoList.protoCount; i++) { + if (ProtoList.protoInfo[i].szProto) + free(ProtoList.protoInfo[i].szProto); + if (ProtoList.protoInfo[i].xstatus.enabled) + free(ProtoList.protoInfo[i].xstatus.enabled); + } + + ProtoList.protoCount = 0; + if (ProtoList.protoInfo) + free(ProtoList.protoInfo); +} + + +extern "C" __declspec(dllexport) int Unload(void) +{ + + UnhookWindowsHooks(); + DeInitAction(); + if (hModulesLoaded) + UnhookEvent(hModulesLoaded); + if (hMsgEventHook) + UnhookEvent(hMsgEventHook); + if (hOptionsInitialize) + UnhookEvent(hOptionsInitialize); + if (hEnableService) + DestroyServiceFunction(hEnableService); + if (hDisableService) + DestroyServiceFunction(hDisableService); + if (hStartBlinkService) + DestroyServiceFunction(hStartBlinkService); + if (hEventsOpenedService) + DestroyServiceFunction(hEventsOpenedService); + if (hFlashingEventService) + DestroyServiceFunction(hFlashingEventService); + if (hNormalizeSequenceService) + DestroyServiceFunction(hNormalizeSequenceService); + + // Wait for thread to exit + SetEvent(hExitEvent); + WaitForSingleObject(hThread, INFINITE); + + RestoreLEDState(); + CloseKeyboardDevice(); + + UnloadProcsLibrary(); + destroyProcessList(); + destroyProtocolList(); + + return 0; +} + + +// ========================== Windows hooks ========================== +int HookWindowsHooks() +{ + if (wReminderCheck) + hReminderTimer = SetTimer(NULL,0, wReminderCheck * 60000, ReminderTimer); + + if (bFlashUntil & UNTIL_REATTENDED) + switch (bMirandaOrWindows) { + case ACTIVE_WINDOWS: + if (!MyGetLastInputInfo || bEmulateKeypresses) { + if (hMouseHook == NULL) + hMouseHook = SetWindowsHookEx(WH_MOUSE, MouseHookFunction, hInst, 0); + if (hKeyBoardHook == NULL) + hKeyBoardHook = SetWindowsHookEx(WH_KEYBOARD, KeyBoardHookFunction, hInst, 0); + } + break; + case ACTIVE_MIRANDA: + if (hMirandaMouseHook == NULL) + hMirandaMouseHook = SetWindowsHookEx(WH_MOUSE, MirandaMouseHookFunction, NULL, GetCurrentThreadId()); + if (hMirandaKeyBoardHook == NULL) + hMirandaKeyBoardHook = SetWindowsHookEx(WH_KEYBOARD, MirandaKeyBoardHookFunction, NULL, GetCurrentThreadId()); + if (hMirandaWndProcHook == NULL) + hMirandaWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, MirandaWndProcHookFunction, NULL, GetCurrentThreadId()); + } + + return 0; +} + +int UnhookWindowsHooks() +{ + if (hReminderTimer) + KillTimer(NULL, hReminderTimer); + if (hMouseHook) + UnhookWindowsHookEx(hMouseHook); + if (hKeyBoardHook) + UnhookWindowsHookEx(hKeyBoardHook); + if (hMirandaMouseHook) + UnhookWindowsHookEx(hMirandaMouseHook); + if (hMirandaKeyBoardHook) + UnhookWindowsHookEx(hMirandaKeyBoardHook); + if (hMirandaWndProcHook) + UnhookWindowsHookEx(hMirandaWndProcHook); + + hReminderTimer = 0; + hMouseHook = hKeyBoardHook = hMirandaMouseHook = hMirandaKeyBoardHook = hMirandaWndProcHook = NULL; + + return 0; +} + +static LRESULT CALLBACK MouseHookFunction(int code, WPARAM wParam, LPARAM lParam) +{ + if (code >= 0) { + /* This should handle all mouse buttons ... */ + if ((wParam >= WM_NCLBUTTONDOWN && wParam <= WM_NCXBUTTONDBLCLK && wParam != 0x00AA) || (wParam >= WM_LBUTTONDOWN && wParam <= WM_XBUTTONDBLCLK)) + dwLastInput = GetTickCount(); + /* ... and here it is either mouse move, hover, leave or something unexpected */ + else { + PMOUSEHOOKSTRUCT mouseInfo = (PMOUSEHOOKSTRUCT)lParam; + POINT pt = mouseInfo->pt; + if (pt.x!=lastGlobalMousePos.x || pt.y!=lastGlobalMousePos.y) { + lastGlobalMousePos = pt; + dwLastInput = GetTickCount(); + } + } + } + + return CallNextHookEx(hMouseHook, code, wParam, lParam); +} + +static LRESULT CALLBACK KeyBoardHookFunction(int code, WPARAM wParam, LPARAM lParam) +{ + if (code >= 0 && (!bEmulateKeypresses || (bEmulateKeypresses && wParam != VK_NUMLOCK && wParam != VK_CAPITAL && wParam != VK_SCROLL))) + dwLastInput = GetTickCount(); + + return CallNextHookEx(hKeyBoardHook, code, wParam, lParam); +} + +static LRESULT CALLBACK MirandaMouseHookFunction(int code, WPARAM wParam, LPARAM lParam) +{ + static POINT lastMousePos = {0, 0}; + + if (code >= 0) { + /* Movement mouse messages are for some reason incoming in inactive/background window too, that is not input */ + DWORD pid; + GetWindowThreadProcessId(GetForegroundWindow(), &pid); + if(pid == GetCurrentProcessId()) { + /* This should handle all mouse buttons ... */ + if ((wParam >= WM_NCLBUTTONDOWN && wParam <= WM_NCXBUTTONDBLCLK && wParam != 0x00AA) || (wParam >= WM_LBUTTONDOWN && wParam <= WM_XBUTTONDBLCLK)) + dwLastInput = GetTickCount(); + /* ... and here it is either mouse move, hover, leave or something unexpected */ + else { + PMOUSEHOOKSTRUCT mouseInfo = (PMOUSEHOOKSTRUCT)lParam; + POINT pt = mouseInfo->pt; + if (pt.x!=lastMousePos.x || pt.y!=lastMousePos.y) { + lastMousePos = pt; + dwLastInput = GetTickCount(); + } + } + } + } + + return CallNextHookEx(hMirandaMouseHook, code, wParam, lParam); +} + +static LRESULT CALLBACK MirandaKeyBoardHookFunction(int code, WPARAM wParam, LPARAM lParam) { + + if (code >= 0 && (!bEmulateKeypresses || (bEmulateKeypresses && wParam != VK_NUMLOCK && wParam != VK_CAPITAL && wParam != VK_SCROLL))) + dwLastInput = GetTickCount(); + + return CallNextHookEx(hMirandaKeyBoardHook, code, wParam, lParam); +} + +static LRESULT CALLBACK MirandaWndProcHookFunction(int code, WPARAM wParam, LPARAM lParam) { + + if (code >= 0) { + /* WM_ACTIVATEAPP with nonzero wParam means someone brought miranda to foreground, that equals to input */ + PCWPSTRUCT cwpInfo = (PCWPSTRUCT)lParam; + if(cwpInfo->message == WM_ACTIVATEAPP && cwpInfo->wParam) + dwLastInput = GetTickCount(); + } + + return CallNextHookEx(hMirandaWndProcHook, code, wParam, lParam); +} + + +//===================== Check Window Message function ===================== + +// Took this snippet of code from "EventNotify" by micron-x, thx *g* +// and updated with NGEventNotify and pete's patch +// checks if the message-dialog window is already opened and returns: +// TRUE - Windows found +// FALSE - No window found + +HWND findMessageWindow(HANDLE hContact) +{ + HWND hwnd; + TCHAR newtitle[256]; + char *szProto, *contactName, *szStatus; + CONTACTINFO ci = {0}; + + szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + contactName = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0); + szStatus = (char *)CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, szProto==NULL?ID_STATUS_OFFLINE:DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), 0); + + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%s): %s"), contactName, szStatus, TranslateT("Message Received")); + if(hwnd = FindWindow(NULL, newtitle)) + return hwnd; + + _snwprintf(newtitle, sizeof(newtitle), _T("%s %s"), contactName, szStatus); + if(hwnd = FindWindow(NULL, newtitle)) + return hwnd; + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%s): %s"), contactName, szStatus, TranslateT("Message Session")); + if(hwnd = FindWindow(NULL, newtitle)) + return hwnd; + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%s): %s"), contactName, szStatus, TranslateT("Message Session is typing...")); + if(hwnd = FindWindow(NULL, newtitle)) + return hwnd; + // search for the nconvers++ message window that uses the UIN + ci.cbSize = sizeof(CONTACTINFO); + ci.dwFlag = CNF_UNIQUEID; + ci.hContact = hContact; + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM)&ci)) { + switch(ci.type) { + case CNFT_BYTE: + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%d) %s"), contactName, ci.bVal, szStatus); + break; + case CNFT_WORD: + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%d) %s"), contactName, ci.wVal, szStatus); + break; + case CNFT_DWORD: + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%d) %s"), contactName, ci.dVal, szStatus); + break; + case CNFT_ASCIIZ: + _snwprintf(newtitle, sizeof(newtitle), _T("%s (%s) %s"), contactName, ci.pszVal, szStatus); + break; + } + if(hwnd = FindWindow(NULL, newtitle)) + return hwnd; + } + + return NULL; +} + +BOOL CheckMsgWnd(HANDLE hContact, BOOL *focus) +{ + if (ServiceExists(MS_MSG_GETWINDOWDATA)) { // use the new message API + MessageWindowData mwd; + MessageWindowInputData mwid; + mwid.cbSize = sizeof(MessageWindowInputData); + mwid.hContact = hContact; + mwid.uFlags = MSG_WINDOW_UFLAG_MSG_BOTH; + mwd.cbSize = sizeof(MessageWindowData); + mwd.hContact = hContact; + if (!CallService(MS_MSG_GETWINDOWDATA, (WPARAM)&mwid, (LPARAM)&mwd) && mwd.hwndWindow) { + *focus = mwd.uState & MSG_WINDOW_STATE_FOCUS; + return TRUE; + } + } else { // old way: find it by using the window class & title + HWND hwnd; + + if(hwnd = findMessageWindow(hContact)) { + *focus = hwnd==GetForegroundWindow(); + return TRUE; + } + } + + *focus = FALSE; + return FALSE; +} + + +void countUnopenEvents(int *msgCount, int *fileCount, int *urlCount, int *otherCount) +{ + int nIndex; + CLISTEVENT *pCLEvent; + + for (nIndex = 0; pCLEvent = (CLISTEVENT*)CallService(MS_CLIST_GETEVENT, -1, nIndex); nIndex++) { + DBEVENTINFO einfo = readEventInfo(pCLEvent->hDbEvent, pCLEvent->hContact); + + if (metaCheckProtocol(einfo.szModule, pCLEvent->hContact, einfo.eventType)) + switch (einfo.eventType) { + case EVENTTYPE_MESSAGE: + if (bFlashOnMsg) + (*msgCount)++; + break; + case EVENTTYPE_URL: + if (bFlashOnURL) + (*urlCount)++; + break; + case EVENTTYPE_FILE: + if (bFlashOnFile) + (*fileCount)++; + break; + default: + if (bFlashOnOther) + (*otherCount)++; + } + } + if (bFlashOnOther) + (*otherCount) += nExternCount; +} diff --git a/plugins/KeyboardNotify/src/options.cpp b/plugins/KeyboardNotify/src/options.cpp new file mode 100644 index 0000000000..d74902aec8 --- /dev/null +++ b/plugins/KeyboardNotify/src/options.cpp @@ -0,0 +1,1565 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include "flash.h" +#include "ignore.h" +#include "resource.h" +#include "constants.h" +#include "protolist.h" +#include "EnumProc.h" +#include "utils.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IDI_BLANK 200 + +#ifndef ETDT_ENABLE +#define ETDT_ENABLE 0x00000002 +#endif +#ifndef ETDT_USETABTEXTURE +#define ETDT_USETABTEXTURE 0x00000004 +#endif +#ifndef ETDT_ENABLETAB +#define ETDT_ENABLETAB (ETDT_ENABLE|ETDT_USETABTEXTURE) +#endif + +#ifndef ListView_SetCheckState +#define ListView_SetCheckState(hLv, iItem, bCheck) \ + ListView_SetItemState(hLv, iItem, bCheck ? INDEXTOSTATEIMAGEMASK(2) : INDEXTOSTATEIMAGEMASK(1), LVIS_STATEIMAGEMASK) +#endif + +#ifndef TVS_NOHSCROLL +#define TVS_NOHSCROLL 0x8000 +#endif + +#ifndef TVM_GETITEMSTATE +#define TVM_GETITEMSTATE (TV_FIRST+39) +#endif + +#ifndef TreeView_SetItemState +#define TreeView_SetItemState(hwndTv, hti, data, _mask) \ + { TVITEM _TVI; \ + _TVI.mask = TVIF_STATE; \ + _TVI.hItem = hti; \ + _TVI.stateMask = _mask; \ + _TVI.state = data; \ + SendMessageA((hwndTv), TVM_SETITEM, 0, (LPARAM)&_TVI); } +#endif + +#ifndef TreeView_GetItemState +#define TreeView_GetItemState(hwndTv, hti, mask) \ + (UINT)SendMessageA((hwndTv), TVM_GETITEMSTATE, (WPARAM)(hti), (LPARAM)(mask)) +#endif + +void LoadSettings(void); +int InitializeOptions(WPARAM,LPARAM); +INT_PTR CALLBACK DlgProcOptions(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcProtoOptions(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcBasicOptions(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcEffectOptions(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcThemeOptions(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcProcesses(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcEventLeds(HWND, UINT, WPARAM, LPARAM); +INT_PTR CALLBACK DlgProcXstatusList(HWND, UINT, WPARAM, LPARAM); +void exportThemes(const TCHAR *); +void importThemes(const TCHAR *, BOOL); +void writeThemeToCombo(const TCHAR *, const TCHAR *, BOOL); +void createProcessListAux(void); +void destroyProcessListAux(void); +void createXstatusListAux(void); +void destroyXstatusListAux(void); + + +extern HINSTANCE hInst; +extern double dWinVer; +extern BOOL bWindowsNT; + +extern BYTE bFlashOnMsg; +extern BYTE bFlashOnURL; +extern BYTE bFlashOnFile; +extern BYTE bFlashOnOther; +extern BYTE bFullScreenMode; +extern BYTE bScreenSaverRunning; +extern BYTE bWorkstationLocked; +extern BYTE bProcessesAreRunning; +extern BYTE bWorkstationActive; +extern BYTE bFlashIfMsgOpen; +extern BYTE bFlashIfMsgOlder; +extern WORD wSecondsOlder; +extern BYTE bFlashUntil; +extern WORD wBlinksNumber; +extern BYTE bMirandaOrWindows; +extern WORD wStatusMap; +extern WORD wReminderCheck; +extern BYTE bFlashLed[3]; +extern BYTE bFlashEffect; +extern BYTE bSequenceOrder; +extern WORD wCustomTheme; +extern WORD wStartDelay; +extern BYTE bFlashSpeed; +extern BYTE bEmulateKeypresses; +extern BYTE bOverride; +extern BYTE bFlashIfMsgWinNotTop; +extern BYTE bTrillianLedsMsg; +extern BYTE bTrillianLedsURL; +extern BYTE bTrillianLedsFile; +extern BYTE bTrillianLedsOther; + +extern PROTOCOL_LIST ProtoList; +extern PROCESS_LIST ProcessList; + +HWND hwndProto, hwndBasic, hwndEffect, hwndTheme, hwndIgnore, hwndCurrentTab; + +TCHAR *AttendedName[]={_T("Miranda"), _T("Windows")}; +TCHAR *OrderName[]={_T("left->right"), _T("right->left"), _T("left<->right")}; + +PROCESS_LIST ProcessListAux; +XSTATUS_INFO *XstatusListAux; +BYTE trillianLedsMsg, trillianLedsURL, trillianLedsFile, trillianLedsOther; + +static BOOL (WINAPI *pfnEnableThemeDialogTexture)(HANDLE, DWORD) = 0; + + +// ** +// ** Initialize the Miranda options page +// ** +int InitializeOptions(WPARAM wParam,LPARAM lParam) +{ + if (bWindowsNT && dWinVer >= 5.01) { + HMODULE hUxTheme = GetModuleHandle(L"uxtheme.dll"); + if(hUxTheme) + pfnEnableThemeDialogTexture = (BOOL (WINAPI *)(HANDLE, DWORD))GetProcAddress(hUxTheme, "EnableThemeDialogTexture"); + } + + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.position = 0; + odp.hInstance = hInst; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPTIONS); + odp.pszTitle = LPGEN("Keyboard Flash"); + odp.pszGroup = LPGEN("Plugins"); + odp.groupPosition = 910000000; + odp.flags = ODPF_BOLDGROUPS; + odp.pfnDlgProc = DlgProcOptions; + odp.nIDBottomSimpleControl = 0; + Options_AddPage(wParam, &odp); + + return 0; +} + +INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_INITDIALOG: + { + HWND tc; + TCITEM tci; + tc = GetDlgItem(hwndDlg, IDC_TABS); + tci.mask = TCIF_TEXT; + tci.pszText = TranslateT("Protocols"); + TabCtrl_InsertItem(tc, 0, &tci); + tci.pszText = TranslateT("Rules"); + TabCtrl_InsertItem(tc, 1, &tci); + tci.pszText = TranslateT("Flashing"); + TabCtrl_InsertItem(tc, 2, &tci); + tci.pszText = TranslateT("Themes"); + TabCtrl_InsertItem(tc, 3, &tci); + tci.pszText = TranslateT("Ignore"); + TabCtrl_InsertItem(tc, 4, &tci); + + hwndProto = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_PROTO_OPTIONS), hwndDlg, DlgProcProtoOptions, (LPARAM) NULL); + if(hwndProto && pfnEnableThemeDialogTexture) + pfnEnableThemeDialogTexture(hwndProto, ETDT_ENABLETAB); + SetWindowPos(hwndProto, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + ShowWindow(hwndProto, SW_SHOW); + hwndBasic = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_BASIC_OPTIONS), hwndDlg, DlgProcBasicOptions, (LPARAM) NULL); + if(hwndBasic && pfnEnableThemeDialogTexture) + pfnEnableThemeDialogTexture(hwndBasic, ETDT_ENABLETAB); + SetWindowPos(hwndBasic, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + hwndEffect = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_EFFECT_OPTIONS), hwndDlg, DlgProcEffectOptions, (LPARAM) NULL); + if(hwndEffect && pfnEnableThemeDialogTexture) + pfnEnableThemeDialogTexture(hwndEffect, ETDT_ENABLETAB); + SetWindowPos(hwndEffect, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + hwndTheme = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_THEME_OPTIONS), hwndDlg, DlgProcThemeOptions, (LPARAM) NULL); + if(hwndTheme && pfnEnableThemeDialogTexture) + pfnEnableThemeDialogTexture(hwndTheme, ETDT_ENABLETAB); + SetWindowPos(hwndTheme, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + hwndIgnore = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_IGNORE_OPTIONS), hwndDlg, DlgProcIgnoreOptions, (LPARAM) NULL); + if(hwndIgnore && pfnEnableThemeDialogTexture) + pfnEnableThemeDialogTexture(hwndIgnore, ETDT_ENABLETAB); + SetWindowPos(hwndIgnore, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + hwndCurrentTab = hwndProto; + return TRUE; + + } + case WM_COMMAND: + break; + case WM_NOTIFY: + { + switch (((LPNMHDR) lParam)->code) { + case TCN_SELCHANGE: + switch (wParam) { + case IDC_TABS: + { + HWND hwnd; + switch (TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TABS))) { + default: + case 0: + hwnd = hwndProto; + break; + case 1: + hwnd = hwndBasic; + break; + case 2: + hwnd = hwndEffect; + break; + case 3: + hwnd = hwndTheme; + break; + case 4: + hwnd = hwndIgnore; + break; + } + if (hwnd!=hwndCurrentTab) { + ShowWindow(hwnd, SW_SHOW); + ShowWindow(hwndCurrentTab, SW_HIDE); + hwndCurrentTab = hwnd; + } + } + break; + } + break; + case PSN_APPLY: + SendMessage(hwndProto, WM_NOTIFY, wParam, lParam); + SendMessage(hwndBasic, WM_NOTIFY, wParam, lParam); + SendMessage(hwndEffect, WM_NOTIFY, wParam, lParam); + SendMessage(hwndTheme, WM_NOTIFY, wParam, lParam); + SendMessage(hwndIgnore, WM_NOTIFY, wParam, lParam); + return TRUE; + } + } + break; + case WM_DESTROY: + break; + } + return FALSE; +} + + +INT_PTR CALLBACK DlgProcProtoOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static BOOL initDlg=FALSE; + + switch (msg) { + + case WM_INITDIALOG: + initDlg=TRUE; + TranslateDialogDefault(hwndDlg); + + // proto list + { + unsigned int i; + LVCOLUMN lvCol; + LVITEM lvItem; + HWND hList = GetDlgItem(hwndDlg, IDC_PROTOCOLLIST); + + // create columns + ListView_SetExtendedListViewStyleEx(hList, LVS_EX_CHECKBOXES, LVS_EX_CHECKBOXES); + memset(&lvCol, 0, sizeof(lvCol)); + lvCol.mask = LVCF_WIDTH|LVCF_TEXT; + lvCol.pszText = TranslateT("Protocol"); + lvCol.cx = 118; + ListView_InsertColumn(hList, 0, &lvCol); + // fill + memset(&lvItem, 0, sizeof(lvItem)); + lvItem.mask = LVIF_TEXT|LVIF_PARAM; + lvItem.cchTextMax = 256; + lvItem.iItem = 0; + lvItem.iSubItem = 0; + for(i=0; i < ProtoList.protoCount; i++) { + int count; PROTOACCOUNT** protos; + ProtoEnumAccounts( &count, &protos ); + if(ProtoList.protoInfo[i].visible) { + lvItem.lParam = (LPARAM)ProtoList.protoInfo[i].szProto; + lvItem.pszText = protos[i] -> tszAccountName; + ListView_InsertItem(hList, &lvItem); + ListView_SetCheckState(hList, lvItem.iItem, ProtoList.protoInfo[i].enabled); + lvItem.iItem++; + } + } + } + + initDlg=FALSE; + return TRUE; + + case WM_NOTIFY: + { + //Here we have pressed either the OK or the APPLY button. + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + // enabled protos + { + int i; + LVITEM lvItem; + HWND hList = GetDlgItem(hwndDlg, IDC_PROTOCOLLIST); + + memset(&lvItem, 0, sizeof(lvItem)); + lvItem.mask = LVIF_PARAM; + lvItem.iSubItem = 0; + for (i=0; i < ListView_GetItemCount(hList); i++) { + lvItem.iItem = i; + ListView_GetItem(hList, &lvItem); + DBWriteContactSettingByte(NULL, KEYBDMODULE, (char *)lvItem.lParam, (BYTE)!!ListView_GetCheckState(hList, lvItem.iItem)); + } + } + + LoadSettings(); + + return TRUE; + } // switch code - 0 + break; + case IDC_PROTOCOLLIST: + switch(((NMHDR*)lParam)->code) { + case LVN_ITEMCHANGED: + { + NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam; + + if (!initDlg && ((nmlv->uNewState ^ nmlv->uOldState) & LVIS_STATEIMAGEMASK)) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + } + break; + } // switch code - IDC_PROTOCOLLIST + break; + } //switch idFrom + } + break; //End WM_NOTIFY + + default: + break; + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcBasicOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + unsigned int i; + static BOOL initDlg=FALSE; + + switch (msg) { + + case WM_INITDIALOG: + initDlg=TRUE; + TranslateDialogDefault(hwndDlg); + + createProcessListAux(); + createXstatusListAux(); + + CheckDlgButton(hwndDlg, IDC_ONMESSAGE, bFlashOnMsg ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ONURL, bFlashOnURL ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ONFILE, bFlashOnFile ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ONOTHER, bFlashOnOther ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_FSCREEN, bFullScreenMode ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_SSAVER, bScreenSaverRunning ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_LOCKED, bWorkstationLocked ? BST_CHECKED:BST_UNCHECKED); + if (!bWindowsNT) + EnableWindow(GetDlgItem(hwndDlg, IDC_LOCKED), FALSE); + CheckDlgButton(hwndDlg, IDC_PGMS, bProcessesAreRunning ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ACTIVE, bWorkstationActive ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_IFOPEN, bFlashIfMsgOpen ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_IFNOTTOP, bFlashIfMsgWinNotTop ? BST_CHECKED:BST_UNCHECKED); + if (!bFlashIfMsgOpen) + EnableWindow(GetDlgItem(hwndDlg, IDC_IFNOTTOP), FALSE); + CheckDlgButton(hwndDlg, IDC_IFOLDER, bFlashIfMsgOlder ? BST_CHECKED:BST_UNCHECKED); + SendDlgItemMessage(hwndDlg, IDC_OLDERSPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_SOLDER), 0); + SendDlgItemMessage(hwndDlg, IDC_OLDERSPIN, UDM_SETRANGE32, 1, MAKELONG(UD_MAXVAL, 0)); + SendDlgItemMessage(hwndDlg, IDC_OLDERSPIN, UDM_SETPOS, 0, MAKELONG(wSecondsOlder, 0)); + if (!bFlashIfMsgOlder) { + EnableWindow(GetDlgItem(hwndDlg, IDC_SOLDER), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_OLDERSPIN), FALSE); + } + + CheckDlgButton(hwndDlg, IDC_UNTILBLK, bFlashUntil&UNTIL_NBLINKS ? BST_CHECKED:BST_UNCHECKED); + SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_SBLINK), 0); + SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETRANGE32, 1, MAKELONG(UD_MAXVAL, 0)); + SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETPOS, 0, MAKELONG(wBlinksNumber, 0)); + if (!(bFlashUntil & UNTIL_NBLINKS)) { + EnableWindow(GetDlgItem(hwndDlg, IDC_SBLINK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKSPIN), FALSE); + } + CheckDlgButton(hwndDlg, IDC_UNTILATTENDED, bFlashUntil&UNTIL_REATTENDED ? BST_CHECKED:BST_UNCHECKED); + for (i=0; i < 2; i++) { + int index = SendDlgItemMessage(hwndDlg, IDC_MIRORWIN, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)AttendedName[i]); + if (index != CB_ERR && index != CB_ERRSPACE) + SendDlgItemMessage(hwndDlg, IDC_MIRORWIN, CB_SETITEMDATA, (WPARAM)index, (LPARAM)i); + } + SendDlgItemMessage(hwndDlg, IDC_MIRORWIN, CB_SETCURSEL, (WPARAM)bMirandaOrWindows, 0); + if (!(bFlashUntil & UNTIL_REATTENDED)) + EnableWindow(GetDlgItem(hwndDlg, IDC_MIRORWIN), FALSE); + CheckDlgButton(hwndDlg, IDC_UNTILOPEN, bFlashUntil&UNTIL_EVENTSOPEN ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_UNTILCOND, bFlashUntil&UNTIL_CONDITIONS ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_ONLINE, wStatusMap&MAP_ONLINE ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_AWAY, wStatusMap&MAP_AWAY ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_NA, wStatusMap&MAP_NA ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OCCUPIED, wStatusMap&MAP_OCCUPIED ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_DND, wStatusMap&MAP_DND ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_FREECHAT, wStatusMap&MAP_FREECHAT ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_INVISIBLE, wStatusMap&MAP_INVISIBLE ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_ONTHEPHONE, wStatusMap&MAP_ONTHEPHONE ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OUTTOLUNCH, wStatusMap&MAP_OUTTOLUNCH ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OFFLINE, wStatusMap&MAP_OFFLINE ? BST_CHECKED:BST_UNCHECKED); + + SendDlgItemMessage(hwndDlg, IDC_REMCHECK, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_SREMCHECK), 0); + SendDlgItemMessage(hwndDlg, IDC_REMCHECK, UDM_SETRANGE32, 0, MAKELONG(UD_MAXVAL, 0)); + SendDlgItemMessage(hwndDlg, IDC_REMCHECK, UDM_SETPOS, 0, MAKELONG(wReminderCheck, 0)); + + initDlg=FALSE; + return TRUE; + + case WM_VSCROLL: + case WM_HSCROLL: + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + break; + + case WM_DESTROY: + destroyProcessListAux(); + destroyXstatusListAux(); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_ONMESSAGE: + case IDC_ONURL: + case IDC_ONFILE: + case IDC_ONOTHER: + case IDC_IFOPEN: + case IDC_IFNOTTOP: + case IDC_IFOLDER: + case IDC_UNTILBLK: + case IDC_UNTILATTENDED: + case IDC_MIRORWIN: + case IDC_UNTILOPEN: + case IDC_UNTILCOND: + case IDC_FSCREEN: + case IDC_SSAVER: + case IDC_LOCKED: + case IDC_PGMS: + case IDC_ACTIVE: + case IDC_ONLINE: + case IDC_AWAY: + case IDC_NA: + case IDC_OCCUPIED: + case IDC_DND: + case IDC_FREECHAT: + case IDC_INVISIBLE: + case IDC_ONTHEPHONE: + case IDC_OUTTOLUNCH: + case IDC_OFFLINE: + EnableWindow(GetDlgItem(hwndDlg, IDC_IFNOTTOP), IsDlgButtonChecked(hwndDlg, IDC_IFOPEN) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_SOLDER), IsDlgButtonChecked(hwndDlg, IDC_IFOLDER) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_OLDERSPIN), IsDlgButtonChecked(hwndDlg, IDC_IFOLDER) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_SBLINK), IsDlgButtonChecked(hwndDlg, IDC_UNTILBLK) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_BLINKSPIN), IsDlgButtonChecked(hwndDlg, IDC_UNTILBLK) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_MIRORWIN), IsDlgButtonChecked(hwndDlg, IDC_UNTILATTENDED) == BST_CHECKED); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_SOLDER: + if(HIWORD(wParam) == EN_CHANGE && !initDlg) { + BOOL translated; + int val = GetDlgItemInt(hwndDlg, IDC_SOLDER, &translated, FALSE); + if (translated && val < 1) + SendDlgItemMessage(hwndDlg, IDC_OLDERSPIN, UDM_SETPOS, 0, MAKELONG(val, 0)); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + } + return TRUE; + case IDC_SBLINK: + if(HIWORD(wParam) == EN_CHANGE && !initDlg) { + BOOL translated; + int val = GetDlgItemInt(hwndDlg, IDC_SBLINK, &translated, FALSE); + if (translated && val < 1) + SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_SETPOS, 0, MAKELONG(val, 0)); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + } + return TRUE; + case IDC_ASSIGNPGMS: + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_PROCESSES), hwndDlg, DlgProcProcesses, 0) == IDC_OKPGM) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_SELECTXSTATUS: + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_XSTATUSES), hwndDlg, DlgProcXstatusList, 0) == IDC_OKXST) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_SREMCHECK: + if(HIWORD(wParam) == EN_CHANGE && !initDlg) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + } + break; + + case WM_NOTIFY: + { + unsigned int j; + BYTE untilMap = 0; + WORD statusMap = 0; + //Here we have pressed either the OK or the APPLY button. + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + DBWriteContactSettingByte(NULL, KEYBDMODULE, "onmsg", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ONMESSAGE) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "onurl", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ONURL) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "onfile", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ONFILE) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "onother", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ONOTHER) == BST_CHECKED ? 1:0)); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "fscreenmode", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_FSCREEN) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ssaverrunning", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SSAVER) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "wstationlocked", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_LOCKED) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "procsrunning", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_PGMS) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "wstationactive", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_ACTIVE) == BST_CHECKED ? 1:0)); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ifmsgopen", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IFOPEN) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ifmsgnottop", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IFNOTTOP) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ifmsgolder", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_IFOLDER) == BST_CHECKED ? 1:0)); + DBWriteContactSettingWord(NULL, KEYBDMODULE, "secsolder", (WORD)SendDlgItemMessage(hwndDlg, IDC_OLDERSPIN, UDM_GETPOS, 0, 0)); + + if(IsDlgButtonChecked(hwndDlg, IDC_UNTILBLK) == BST_CHECKED) + untilMap |= UNTIL_NBLINKS; + if (IsDlgButtonChecked(hwndDlg, IDC_UNTILATTENDED) == BST_CHECKED) + untilMap |= UNTIL_REATTENDED; + if (IsDlgButtonChecked(hwndDlg, IDC_UNTILOPEN) == BST_CHECKED) + untilMap |= UNTIL_EVENTSOPEN; + if (IsDlgButtonChecked(hwndDlg, IDC_UNTILCOND) == BST_CHECKED) + untilMap |= UNTIL_CONDITIONS; + DBWriteContactSettingByte(NULL, KEYBDMODULE, "funtil", untilMap); + DBWriteContactSettingWord(NULL, KEYBDMODULE, "nblinks", (WORD)SendDlgItemMessage(hwndDlg, IDC_BLINKSPIN, UDM_GETPOS, 0, 0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "mirorwin", (BYTE)SendDlgItemMessage(hwndDlg, IDC_MIRORWIN, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hwndDlg, IDC_MIRORWIN, CB_GETCURSEL, 0, 0), 0)); + + if(IsDlgButtonChecked(hwndDlg, IDC_ONLINE) == BST_CHECKED) + statusMap |= MAP_ONLINE; + if(IsDlgButtonChecked(hwndDlg, IDC_AWAY) == BST_CHECKED) + statusMap |= MAP_AWAY; + if(IsDlgButtonChecked(hwndDlg, IDC_NA) == BST_CHECKED) + statusMap |= MAP_NA; + if(IsDlgButtonChecked(hwndDlg, IDC_OCCUPIED) == BST_CHECKED) + statusMap |= MAP_OCCUPIED; + if(IsDlgButtonChecked(hwndDlg, IDC_DND) == BST_CHECKED) + statusMap |= MAP_DND; + if(IsDlgButtonChecked(hwndDlg, IDC_FREECHAT) == BST_CHECKED) + statusMap |= MAP_FREECHAT; + if(IsDlgButtonChecked(hwndDlg, IDC_INVISIBLE) == BST_CHECKED) + statusMap |= MAP_INVISIBLE; + if(IsDlgButtonChecked(hwndDlg, IDC_ONTHEPHONE) == BST_CHECKED) + statusMap |= MAP_ONTHEPHONE; + if(IsDlgButtonChecked(hwndDlg, IDC_OUTTOLUNCH) == BST_CHECKED) + statusMap |= MAP_OUTTOLUNCH; + if(IsDlgButtonChecked(hwndDlg, IDC_OFFLINE) == BST_CHECKED) + statusMap |= MAP_OFFLINE; + DBWriteContactSettingWord(NULL, KEYBDMODULE, "status", statusMap); + + DBWriteContactSettingWord(NULL, KEYBDMODULE, "remcheck", (WORD)SendDlgItemMessage(hwndDlg, IDC_REMCHECK, UDM_GETPOS, 0, 0)); + + for (i=0, j=0; j < ProcessListAux.count; j++) + if (ProcessListAux.szFileName[j]) + DBWriteContactSettingWString(NULL, KEYBDMODULE, fmtDBSettingName("process%d", i++), ProcessListAux.szFileName[j]); + DBWriteContactSettingWord(NULL, KEYBDMODULE, "processcount", (WORD)i); + while (!DBDeleteContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("process%d", i++))); + + if (XstatusListAux) + for (i=0; i < ProtoList.protoCount; i++) + for(j=0; j < XstatusListAux[i].count; j++) + DBWriteContactSettingByte(NULL, KEYBDMODULE, fmtDBSettingName("%sxstatus%d", ProtoList.protoInfo[i].szProto, j), (BYTE)XstatusListAux[i].enabled[j]); + + LoadSettings(); + + return TRUE; + } // switch code + break; + } //switch idFrom + } + break; //End WM_NOTIFY + + default: + break; + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcEffectOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + int i; + DBVARIANT dbv; + static BOOL initDlg=FALSE; + + switch (msg) { + + case WM_INITDIALOG: + initDlg=TRUE; + TranslateDialogDefault(hwndDlg); + + trillianLedsMsg = bTrillianLedsMsg; + trillianLedsURL = bTrillianLedsURL; + trillianLedsFile = bTrillianLedsFile; + trillianLedsOther = bTrillianLedsOther; + + CheckDlgButton(hwndDlg, IDC_NUM, bFlashLed[0] ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_CAPS, bFlashLed[1] ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_SCROLL, bFlashLed[2] ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_SAMETIME, bFlashEffect == FLASH_SAMETIME ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_INTURN, bFlashEffect == FLASH_INTURN ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_INSEQUENCE, bFlashEffect == FLASH_INSEQUENCE ? BST_CHECKED:BST_UNCHECKED); + for (i=0; i < 3; i++) { + int index = SendDlgItemMessage(hwndDlg, IDC_SEQORDER, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)(OrderName[i])); + if (index != CB_ERR && index != CB_ERRSPACE) + SendDlgItemMessage(hwndDlg, IDC_SEQORDER, CB_SETITEMDATA, (WPARAM)index, (LPARAM)i); + } + SendDlgItemMessage(hwndDlg, IDC_SEQORDER, CB_SETCURSEL, (WPARAM)bSequenceOrder, 0); + if (bFlashEffect != FLASH_INSEQUENCE) + EnableWindow(GetDlgItem(hwndDlg, IDC_SEQORDER), FALSE); + CheckDlgButton(hwndDlg, IDC_CUSTOM, bFlashEffect == FLASH_CUSTOM ? BST_CHECKED:BST_UNCHECKED); + for (i=0; !DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), &dbv); i++) { + int index = SendDlgItemMessage(hwndDlg, IDC_SCUSTOM, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)dbv.ptszVal); + DBFreeVariant(&dbv); + if (index != CB_ERR && index != CB_ERRSPACE) + SendDlgItemMessage(hwndDlg, IDC_SCUSTOM, CB_SETITEMDATA, (WPARAM)index, (LPARAM)i); + } + SendDlgItemMessage(hwndDlg, IDC_SCUSTOM, CB_SETCURSEL, (WPARAM)wCustomTheme, 0); + if (bFlashEffect != FLASH_CUSTOM) + EnableWindow(GetDlgItem(hwndDlg, IDC_SCUSTOM), FALSE); + CheckDlgButton(hwndDlg, IDC_TRILLIAN, bFlashEffect == FLASH_TRILLIAN ? BST_CHECKED:BST_UNCHECKED); + if (bFlashEffect != FLASH_TRILLIAN) + EnableWindow(GetDlgItem(hwndDlg, IDC_ASSIGNLEDS), FALSE); + + SendDlgItemMessage(hwndDlg, IDC_DELAYSPIN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_SDELAY), 0); + SendDlgItemMessage(hwndDlg, IDC_DELAYSPIN, UDM_SETRANGE32, 0, MAKELONG(UD_MAXVAL, 0)); + SendDlgItemMessage(hwndDlg, IDC_DELAYSPIN, UDM_SETPOS, 0, MAKELONG(wStartDelay, 0)); + + SendDlgItemMessage(hwndDlg, IDC_SPEED, TBM_SETRANGE, FALSE, MAKELONG(0, 5)); + SendDlgItemMessage(hwndDlg, IDC_SPEED, TBM_SETPOS, TRUE, bFlashSpeed); + + CheckDlgButton(hwndDlg, IDC_KEYPRESSES, bEmulateKeypresses ? BST_CHECKED:BST_UNCHECKED); + + initDlg=FALSE; + return TRUE; + + case WM_VSCROLL: + case WM_HSCROLL: + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + break; + + case WM_DESTROY: + previewFlashing(FALSE); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_NUM: + case IDC_CAPS: + case IDC_SCROLL: + case IDC_SAMETIME: + case IDC_INTURN: + case IDC_INSEQUENCE: + case IDC_SEQORDER: + case IDC_CUSTOM: + case IDC_TRILLIAN: + case IDC_SCUSTOM: + case IDC_SPEED: + case IDC_KEYPRESSES: + EnableWindow(GetDlgItem(hwndDlg, IDC_SEQORDER), IsDlgButtonChecked(hwndDlg, IDC_INSEQUENCE) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_SCUSTOM), IsDlgButtonChecked(hwndDlg, IDC_CUSTOM) == BST_CHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_ASSIGNLEDS), IsDlgButtonChecked(hwndDlg, IDC_TRILLIAN) == BST_CHECKED); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_ASSIGNLEDS: + if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_EVENTLEDS), hwndDlg, DlgProcEventLeds, 0) == IDC_OK) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_SDELAY: + if(HIWORD(wParam) == EN_CHANGE && !initDlg) + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_PREVIEW: + previewFlashing(IsDlgButtonChecked(hwndDlg, IDC_PREVIEW) == BST_CHECKED); + return TRUE; + } + break; + + case WM_NOTIFY: + { + //Here we have pressed either the OK or the APPLY button. + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + DBWriteContactSettingByte(NULL, KEYBDMODULE, "fnum", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_NUM) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "fcaps", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_CAPS) == BST_CHECKED ? 1:0)); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "fscroll", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_SCROLL) == BST_CHECKED ? 1:0)); + + if(IsDlgButtonChecked(hwndDlg, IDC_INTURN) == BST_CHECKED) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "feffect", FLASH_INTURN); + else + if (IsDlgButtonChecked(hwndDlg, IDC_INSEQUENCE) == BST_CHECKED) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "feffect", FLASH_INSEQUENCE); + else + if (IsDlgButtonChecked(hwndDlg, IDC_CUSTOM) == BST_CHECKED) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "feffect", FLASH_CUSTOM); + else + if (IsDlgButtonChecked(hwndDlg, IDC_TRILLIAN) == BST_CHECKED) + DBWriteContactSettingByte(NULL, KEYBDMODULE, "feffect", FLASH_TRILLIAN); + else + DBWriteContactSettingByte(NULL, KEYBDMODULE, "feffect", FLASH_SAMETIME); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "order", (BYTE)SendDlgItemMessage(hwndDlg, IDC_SEQORDER, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hwndDlg, IDC_SEQORDER, CB_GETCURSEL, 0, 0), 0)); + DBWriteContactSettingWord(NULL, KEYBDMODULE, "custom", (WORD)SendDlgItemMessage(hwndDlg, IDC_SCUSTOM, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hwndDlg, IDC_SCUSTOM, CB_GETCURSEL, 0, 0), 0)); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ledsmsg", trillianLedsMsg); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ledsfile", trillianLedsFile); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ledsurl", trillianLedsURL); + DBWriteContactSettingByte(NULL, KEYBDMODULE, "ledsother", trillianLedsOther); + + DBWriteContactSettingWord(NULL, KEYBDMODULE, "sdelay", (WORD)SendDlgItemMessage(hwndDlg, IDC_DELAYSPIN, UDM_GETPOS, 0, 0)); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "speed", (BYTE)SendDlgItemMessage(hwndDlg, IDC_SPEED, TBM_GETPOS, 0, 0)); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "keypresses", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_KEYPRESSES) == BST_CHECKED ? 1:0)); + + LoadSettings(); + + return TRUE; + } // switch code + break; + } //switch idFrom + } + break; //End WM_NOTIFY + + default: + break; + } + + return FALSE; +} + +INT_PTR CALLBACK DlgProcThemeOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + int i; + TCHAR *str; + DBVARIANT dbv; + static BOOL initDlg=FALSE; + + switch (msg) { + + case WM_INITDIALOG: + initDlg=TRUE; + TranslateDialogDefault(hwndDlg); + + SendDlgItemMessage(hwndDlg, IDC_THEME, EM_LIMITTEXT, MAX_PATH, 0); + SendDlgItemMessage(hwndDlg, IDC_CUSTOMSTRING, EM_LIMITTEXT, MAX_PATH, 0); + + for (i=0; !DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), &dbv); i++) { + int index = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + if (index != CB_ERR && index != CB_ERRSPACE) { + str = (TCHAR *)malloc(MAX_PATH+1); + if (str) + if (DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i), &dbv)) + str[0] = _T('\0'); + else { + wcscpy(str, dbv.ptszVal); + DBFreeVariant(&dbv); + } + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_SETITEMDATA, (WPARAM)index, (LPARAM)str); + } + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + if (SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETCOUNT, 0, 0) == 0) + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + else { + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_SETCURSEL, (WPARAM)wCustomTheme, 0); + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)wCustomTheme, 0); + if (str) + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str); + } + + CheckDlgButton(hwndDlg, IDC_OVERRIDE, bOverride ? BST_CHECKED:BST_UNCHECKED); + + initDlg=FALSE; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_THEME: + switch (HIWORD(wParam)) { + int item; + TCHAR theme[MAX_PATH+1]; + + case CBN_SELENDOK: + case CBN_SELCHANGE: + str = (TCHAR *)SendMessage((HWND)lParam, CB_GETITEMDATA, (WPARAM)SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0), 0); + if (str) + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str); + else + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, _T("")); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE); + break; + case CBN_EDITCHANGE: + GetDlgItemText(hwndDlg, IDC_THEME, theme, sizeof(theme)); + if ((item = SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, -1, (LPARAM)theme)) == CB_ERR) { //new theme + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, _T("")); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + } else { + str = (TCHAR *)SendMessage((HWND)lParam, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str); + else + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, _T("")); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + break; + } + return TRUE; + case IDC_CUSTOMSTRING: + if(HIWORD(wParam) == EN_CHANGE) { + int item; + TCHAR theme[MAX_PATH+1], customAux[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_THEME, theme, sizeof(theme)); + if ((item = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_FINDSTRINGEXACT, -1, (LPARAM)theme)) == CB_ERR) + return TRUE; + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) { + GetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, customAux, MAX_PATH); + if (wcscmp(str, customAux)) + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), TRUE); + else + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + } + } + return TRUE; + case IDC_TEST: + { + TCHAR custom[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, custom, MAX_PATH); + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, normalizeCustomString(custom)); + testSequence(custom); + } + return TRUE; + case IDC_ADD: + { + int item; + TCHAR theme[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_THEME, theme, sizeof(theme)); + if (!theme[0]) + return TRUE; + item = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_ADDSTRING, 0, (LPARAM)theme); + str = (TCHAR *)malloc(MAX_PATH+1); + if (str) { + GetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str, MAX_PATH); + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, normalizeCustomString(str)); + } + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_SETITEMDATA, (WPARAM)item, (LPARAM)str); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), TRUE); + } + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_UPDATE: + { + int item; + TCHAR theme[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_THEME, theme, sizeof(theme)); + item = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_FINDSTRINGEXACT, -1, (LPARAM)theme); + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) { + GetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str, MAX_PATH); + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, normalizeCustomString(str)); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + } + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_DELETE: + { + int item; + TCHAR theme[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_THEME, theme, sizeof(theme)); + item = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_FINDSTRINGEXACT, -1, (LPARAM)theme); + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) + free(str); + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_DELETESTRING, (WPARAM)item, 0); + if (SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETCOUNT, 0, 0) == 0) { + SetDlgItemText(hwndDlg, IDC_THEME, _T("")); + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, _T("")); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE), FALSE); + } else { + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_SETCURSEL, 0, 0); + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, 0, 0); + if (str) + SetDlgItemText(hwndDlg, IDC_CUSTOMSTRING, str); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_UPDATE), FALSE); + } + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + case IDC_EXPORT: + { + TCHAR path[MAX_PATH+1], filter[MAX_PATH+1], *pfilter; + OPENFILENAME ofn={0}; + + path[0] = _T('\0'); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + wcscpy(filter,_T("Keyboard Notify Theme")); + wcscat(filter, _T(" (*.knt)")); + pfilter = filter + wcslen(filter) + 1; + wcscpy(pfilter, _T("*.knt")); + pfilter = pfilter + wcslen(pfilter) + 1; + wcscpy(pfilter, _T("All Files")); + pfilter = pfilter + wcslen(pfilter) + 1; + wcscpy(pfilter, _T("*.*")); + pfilter = pfilter + wcslen(pfilter) + 1; + *pfilter = _T('\0'); + ofn.lpstrFilter = filter; + ofn.lpstrFile = path; + ofn.Flags = OFN_HIDEREADONLY|OFN_NOCHANGEDIR|OFN_NOREADONLYRETURN|OFN_PATHMUSTEXIST; + ofn.nMaxFile = sizeof(path); + ofn.lpstrDefExt = _T("knt"); + if(GetSaveFileName(&ofn)) + exportThemes(path); + } + return TRUE; + case IDC_IMPORT: + { + TCHAR path[MAX_PATH+1], filter[MAX_PATH+1], *pfilter; + OPENFILENAME ofn={0}; + + path[0] = _T('\0'); + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = hwndDlg; + ofn.hInstance = NULL; + wcscpy(filter, _T("Keyboard Notify Theme")); + wcscat(filter, _T(" (*.knt)")); + pfilter = filter + wcslen(filter) + 1; + wcscpy(pfilter, _T("*.knt")); + pfilter = pfilter + wcslen(pfilter) + 1; + wcscpy(pfilter, _T("All Files")); + pfilter = pfilter + wcslen(pfilter) + 1; + wcscpy(pfilter, _T("*.*")); + pfilter = pfilter + wcslen(pfilter) + 1; + *pfilter = _T('\0'); + ofn.lpstrFilter = filter; + ofn.lpstrFile = path; + ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR; + ofn.nMaxFile = sizeof(path); + ofn.lpstrDefExt = _T("knt"); + if(GetOpenFileName(&ofn)) { + importThemes(path, IsDlgButtonChecked(hwndDlg, IDC_OVERRIDE) == BST_CHECKED); + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + } + } + return TRUE; + case IDC_OVERRIDE: + SendMessage(GetParent(GetParent(hwndDlg)), PSM_CHANGED, 0, 0); + return TRUE; + } + break; + + case WM_NOTIFY: + { + int count; + TCHAR theme[MAX_PATH+1], themeAux[MAX_PATH+1], *str; + //Here we have pressed either the OK or the APPLY button. + switch(((LPNMHDR)lParam)->idFrom) { + case 0: + switch (((LPNMHDR)lParam)->code) { + case PSN_APPLY: + if (!DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", wCustomTheme), &dbv)) + wcscpy(theme, dbv.ptszVal); + else + theme[0] = _T('\0'); + + // Here we will delete all the items in the theme combo on the Flashing tab: we will load them again later + for (i=0; SendDlgItemMessage(hwndEffect, IDC_SCUSTOM, CB_DELETESTRING, 0, (LPARAM)i) != CB_ERR; i++); + + count = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETCOUNT, 0, 0); + for (i=0, wCustomTheme=0; i < count; i++) { + SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETLBTEXT, (WPARAM)i, (LPARAM)themeAux); + DBWriteContactSettingWString(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), themeAux); + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)i, 0); + if (str) + DBWriteContactSettingWString(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i), str); + else + DBWriteContactSettingWString(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i), _T("")); + + if (!wcscmp(theme, themeAux)) + wCustomTheme = i; + + // Here we will update the theme combo on the Flashing tab: horrible but can't imagine a better way right now + SendDlgItemMessage(hwndEffect, IDC_SCUSTOM, CB_INSERTSTRING, (WPARAM)i, (LPARAM)themeAux); + SendDlgItemMessage(hwndEffect, IDC_SCUSTOM, CB_SETITEMDATA, (WPARAM)i, (LPARAM)i); + } + for (i=count; !DBDeleteContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i)); i++) + DBDeleteContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i)); + + DBWriteContactSettingWord(NULL, KEYBDMODULE, "custom", wCustomTheme); + // Still updating here the the Flashing tab's controls + SendDlgItemMessage(hwndEffect, IDC_SCUSTOM, CB_SETCURSEL, (WPARAM)wCustomTheme, 0); + + DBWriteContactSettingByte(NULL, KEYBDMODULE, "override", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_OVERRIDE) == BST_CHECKED ? 1:0)); + + return TRUE; + } // switch code + break; + } //switch idFrom + } + break; //End WM_NOTIFY + + case WM_DESTROY: + { + int item, count = SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETCOUNT, 0, 0); + + for (item=0; item < count; item++) { + str = (TCHAR *)SendDlgItemMessage(hwndDlg, IDC_THEME, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) + free(str); + } + break; + } + + default: + break; + } + + return FALSE; +} + + +void exportThemes(const TCHAR *filename) +{ + int i; + FILE *fExport; + DBVARIANT dbv; + + if (!(fExport = _wfopen(filename, _T("wt")))) + return; + + fwprintf(fExport, TranslateT("\n; Automatically generated Keyboard Notify Theme file\n\n\n")); + + for (i=0; !DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), &dbv); i++) { + fwprintf(fExport, _T("[%s]\n"), dbv.ptszVal); + DBFreeVariant(&dbv); + if (DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i), &dbv)) + fwprintf(fExport, _T("0\n\n")); + else { + fwprintf(fExport, _T("%s\n\n"), dbv.ptszVal); + DBFreeVariant(&dbv); + } + } + + fwprintf(fExport, TranslateT("\n; End of automatically generated Keyboard Notify Theme file\n")); + + fclose(fExport); +} + + +void importThemes(const TCHAR *filename, BOOL overrideExisting) +{ + int status=0; + size_t i; + FILE *fImport; + TCHAR buffer[MAX_PATH+1], theme[MAX_PATH+1], *str; + + if (!(fImport = _wfopen(filename, _T("rt")))) + return; + + while (fgetws(buffer, MAX_PATH, fImport) != NULL) { + for (str=buffer; *str && isspace(*str); str++); //ltrim + if (!*str || *str == ';') //empty line or comment + continue; + for (i=wcslen(str)-1; isspace(str[i]); str[i--]='\0'); //rtrim + switch (status) { + case 0: + if (i > 1 && str[0] == '[' && str[i] == ']') { + status = 1; + wcscpy(theme, str+1); + theme[i-1] = '\0'; + } + break; + case 1: + status = 0; + writeThemeToCombo(theme, normalizeCustomString(str), overrideExisting); + break; + } + } + + fclose(fImport); +} + + +void writeThemeToCombo(const TCHAR *theme, const TCHAR *custom, BOOL overrideExisting) +{ + int item; + TCHAR *str; + + item = SendDlgItemMessage(hwndTheme, IDC_THEME, CB_FINDSTRINGEXACT, -1, (LPARAM)theme); + if (item == CB_ERR) { + item = SendDlgItemMessage(hwndTheme, IDC_THEME, CB_ADDSTRING, 0, (LPARAM)theme); + str = (TCHAR *)malloc(MAX_PATH+1); + if (str) + wcscpy(str, custom); + SendDlgItemMessage(hwndTheme, IDC_THEME, CB_SETITEMDATA, (WPARAM)item, (LPARAM)str); + } else + if (overrideExisting) { + str = (TCHAR *)SendDlgItemMessage(hwndTheme, IDC_THEME, CB_GETITEMDATA, (WPARAM)item, 0); + if (str) + wcscpy(str, custom); + } +} + + +INT_PTR CALLBACK DlgProcProcesses(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + unsigned int i; + + switch (msg) { + + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, EM_LIMITTEXT, MAX_PATH, 0); + + for (i=0; i < ProcessListAux.count; i++) + if (ProcessListAux.szFileName[i]) { + int index = SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)ProcessListAux.szFileName[i]); + if (index != CB_ERR && index != CB_ERRSPACE) + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_SETITEMDATA, (WPARAM)index, (LPARAM)i); + } + + EnableWindow(GetDlgItem(hwndDlg, IDC_ADDPGM), FALSE); + if (SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_GETCOUNT, 0, 0) == 0) + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), FALSE); + else + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_SETCURSEL, 0, 0); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_PROGRAMS: + switch (HIWORD(wParam)) { + int item; + TCHAR szFileName[MAX_PATH+1]; + + case CBN_SELENDOK: + case CBN_SELCHANGE: + EnableWindow(GetDlgItem(hwndDlg, IDC_ADDPGM), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), TRUE); + break; + case CBN_EDITCHANGE: + GetDlgItemText(hwndDlg, IDC_PROGRAMS, szFileName, sizeof(szFileName)); + if ((item = SendMessage((HWND)lParam, CB_FINDSTRINGEXACT, -1, (LPARAM)szFileName)) == CB_ERR) { //new program + EnableWindow(GetDlgItem(hwndDlg, IDC_ADDPGM), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), FALSE); + } else { + EnableWindow(GetDlgItem(hwndDlg, IDC_ADDPGM), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), TRUE); + } + break; + } + break; + case IDC_ADDPGM: + { + int item; + TCHAR szFileName[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_PROGRAMS, szFileName, sizeof(szFileName)); + if (!szFileName[0]) + break; + item = SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_ADDSTRING, 0, (LPARAM)szFileName); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADDPGM), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), TRUE); + } + break; + case IDC_DELETEPGM: + { + int item; + TCHAR szFileName[MAX_PATH+1]; + + GetDlgItemText(hwndDlg, IDC_PROGRAMS, szFileName, sizeof(szFileName)); + item = SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_FINDSTRINGEXACT, -1, (LPARAM)szFileName); + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_DELETESTRING, (WPARAM)item, 0); + if (SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_GETCOUNT, 0, 0) == 0) { + SetDlgItemText(hwndDlg, IDC_PROGRAMS, _T("")); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETEPGM), FALSE); + } else + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_SETCURSEL, 0, 0); + } + break; + case IDC_OKPGM: + destroyProcessListAux(); + + ProcessListAux.count = SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_GETCOUNT, 0, 0); + ProcessListAux.szFileName = (TCHAR **)malloc(ProcessListAux.count * sizeof(TCHAR *)); + if (!ProcessListAux.szFileName) + ProcessListAux.count = 0; + else + for (i=0; i < ProcessListAux.count; i++) { + TCHAR szFileNameAux[MAX_PATH+1]; + + SendDlgItemMessage(hwndDlg, IDC_PROGRAMS, CB_GETLBTEXT, (WPARAM)i, (LPARAM)szFileNameAux); + ProcessListAux.szFileName[i] = (TCHAR *)malloc(wcslen(szFileNameAux) + 1); + if (ProcessListAux.szFileName[i]) + wcscpy(ProcessListAux.szFileName[i], szFileNameAux); + } + + case IDC_CANCELPGM: + EndDialog(hwndDlg, LOWORD(wParam)); + break; + } + break; + } + + return FALSE; +} + + +void createProcessListAux(void) +{ + unsigned int i; + + ProcessListAux.count = ProcessList.count; + ProcessListAux.szFileName = (TCHAR **)malloc(ProcessListAux.count * sizeof(char *)); + if (!ProcessListAux.szFileName) + ProcessListAux.count = 0; + else + for (i=0; i < ProcessListAux.count; i++) + if (!ProcessList.szFileName[i]) + ProcessListAux.szFileName[i] = NULL; + else { + ProcessListAux.szFileName[i] = (TCHAR *)malloc(wcslen(ProcessList.szFileName[i]) + 1); + if (ProcessListAux.szFileName[i]) + wcscpy(ProcessListAux.szFileName[i], ProcessList.szFileName[i]); + } + +} + + +void destroyProcessListAux(void) +{ + unsigned int i; + + for(i=0; i < ProcessListAux.count; i++) + if (ProcessListAux.szFileName[i]) + free(ProcessListAux.szFileName[i]); + + if (ProcessListAux.szFileName) + free(ProcessListAux.szFileName); + + ProcessListAux.count = 0; + ProcessListAux.szFileName = NULL; +} + + +INT_PTR CALLBACK DlgProcEventLeds(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + + case WM_INITDIALOG: + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_MSGLEDNUM, trillianLedsMsg&2 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_MSGLEDCAPS, trillianLedsMsg&4 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_MSGLEDSCROLL, trillianLedsMsg&1 ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_FILELEDNUM, trillianLedsFile&2 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_FILELEDCAPS, trillianLedsFile&4 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_FILELEDSCROLL, trillianLedsFile&1 ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_URLLEDNUM, trillianLedsURL&2 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_URLLEDCAPS, trillianLedsURL&4 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_URLLEDSCROLL, trillianLedsURL&1 ? BST_CHECKED:BST_UNCHECKED); + + CheckDlgButton(hwndDlg, IDC_OTHERLEDNUM, trillianLedsOther&2 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OTHERLEDCAPS, trillianLedsOther&4 ? BST_CHECKED:BST_UNCHECKED); + CheckDlgButton(hwndDlg, IDC_OTHERLEDSCROLL, trillianLedsOther&1 ? BST_CHECKED:BST_UNCHECKED); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_OK: + trillianLedsMsg = 0; + if(IsDlgButtonChecked(hwndDlg, IDC_MSGLEDNUM) == BST_CHECKED) + trillianLedsMsg |= 2; + if(IsDlgButtonChecked(hwndDlg, IDC_MSGLEDCAPS) == BST_CHECKED) + trillianLedsMsg |= 4; + if(IsDlgButtonChecked(hwndDlg, IDC_MSGLEDSCROLL) == BST_CHECKED) + trillianLedsMsg |= 1; + + trillianLedsFile = 0; + if(IsDlgButtonChecked(hwndDlg, IDC_FILELEDNUM) == BST_CHECKED) + trillianLedsFile |= 2; + if(IsDlgButtonChecked(hwndDlg, IDC_FILELEDCAPS) == BST_CHECKED) + trillianLedsFile |= 4; + if(IsDlgButtonChecked(hwndDlg, IDC_FILELEDSCROLL) == BST_CHECKED) + trillianLedsFile |= 1; + + trillianLedsURL = 0; + if(IsDlgButtonChecked(hwndDlg, IDC_URLLEDNUM) == BST_CHECKED) + trillianLedsURL |= 2; + if(IsDlgButtonChecked(hwndDlg, IDC_URLLEDCAPS) == BST_CHECKED) + trillianLedsURL |= 4; + if(IsDlgButtonChecked(hwndDlg, IDC_URLLEDSCROLL) == BST_CHECKED) + trillianLedsURL |= 1; + + trillianLedsOther = 0; + if(IsDlgButtonChecked(hwndDlg, IDC_OTHERLEDNUM) == BST_CHECKED) + trillianLedsOther |= 2; + if(IsDlgButtonChecked(hwndDlg, IDC_OTHERLEDCAPS) == BST_CHECKED) + trillianLedsOther |= 4; + if(IsDlgButtonChecked(hwndDlg, IDC_OTHERLEDSCROLL) == BST_CHECKED) + trillianLedsOther |= 1; + + case IDC_CANCEL: + EndDialog(hwndDlg, LOWORD(wParam)); + break; + } + break; + } + + return FALSE; +} + + +void createXstatusListAux(void) +{ + unsigned int i, j; + + XstatusListAux = (XSTATUS_INFO *)malloc(ProtoList.protoCount * sizeof(XSTATUS_INFO)); + if (XstatusListAux) + for (i=0; i < ProtoList.protoCount; i++) { + XstatusListAux[i].count = ProtoList.protoInfo[i].xstatus.count; + if (!XstatusListAux[i].count) + XstatusListAux[i].enabled = NULL; + else { + XstatusListAux[i].enabled = (BOOL *)malloc(XstatusListAux[i].count * sizeof(BOOL)); + if (!XstatusListAux[i].enabled) + XstatusListAux[i].count = 0; + else + for(j=0; j < XstatusListAux[i].count; j++) + XstatusListAux[i].enabled[j] = ProtoList.protoInfo[i].xstatus.enabled[j]; + } + } + +} + + +void destroyXstatusListAux(void) +{ + unsigned int i; + + if (XstatusListAux) { + for(i=0; i < ProtoList.protoCount; i++) + if (XstatusListAux[i].enabled) + free(XstatusListAux[i].enabled); + + free(XstatusListAux); + XstatusListAux = NULL; + } + +} + + +INT_PTR CALLBACK DlgProcXstatusList(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + + case WM_INITDIALOG: + + { + unsigned int i; + WPARAM j; + int imageCount; + HICON hIconAux; + HIMAGELIST hImageList; + TVINSERTSTRUCT tvis={0}; + TVITEM tvi={0}; + HTREEITEM hSectionItem, hItem; + HWND hwndTree = GetDlgItem(hwndDlg, IDC_TREE_XSTATUS); + + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndTree, GWL_STYLE, GetWindowLongPtr(hwndTree, GWL_STYLE)|TVS_NOHSCROLL|TVS_CHECKBOXES); + + if (!XstatusListAux) return TRUE; + + // Calculate hImageList size + for (i=0, imageCount=1; i < ProtoList.protoCount; i++) + if (ProtoList.protoInfo[i].enabled && XstatusListAux[i].count) + imageCount += XstatusListAux[i].count; + + hImageList = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), (bWindowsNT && dWinVer >= 5.01?ILC_COLOR32:ILC_COLOR16)|ILC_MASK, imageCount, imageCount); + TreeView_SetImageList(hwndTree, hImageList, TVSIL_NORMAL); + + ImageList_AddIcon(hImageList, hIconAux=(HICON)LoadImage(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_BLANK), IMAGE_ICON, 0, 0, 0)); + if (hIconAux) DestroyIcon(hIconAux); + + TreeView_SelectItem(hwndTree, NULL); + ShowWindow(hwndTree, SW_HIDE); + TreeView_DeleteAllItems(hwndTree); + + for (i=0; i < ProtoList.protoCount; i++) + if (ProtoList.protoInfo[i].enabled && XstatusListAux[i].count) { + HTREEITEM hParent; + + int count; PROTOACCOUNT** protos; + ProtoEnumAccounts( &count, &protos ); + + tvis.hParent = NULL; + tvis.hInsertAfter = TVI_LAST; + tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_STATE|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + tvis.item.pszText = protos[i] -> tszAccountName; + tvis.item.lParam = (LPARAM)i; + tvis.item.stateMask = TVIS_BOLD|TVIS_EXPANDED; + tvis.item.state = TVIS_BOLD|TVIS_EXPANDED; + tvis.item.iImage = tvis.item.iSelectedImage = ImageList_AddIcon(hImageList, hIconAux=(HICON)CallProtoService(ProtoList.protoInfo[i].szProto, PS_LOADICON, PLI_PROTOCOL, 0)); + if (hIconAux) DestroyIcon(hIconAux); + hParent = TreeView_InsertItem(hwndTree, &tvis); + for(j=0; j < XstatusListAux[i].count; j++) { + TCHAR szDefaultName[1024]; + ICQ_CUSTOM_STATUS xstatus={0}; + + tvis.hParent = hParent; + tvis.item.mask = TVIF_TEXT|TVIF_PARAM|TVIF_IMAGE|TVIF_SELECTEDIMAGE; + if (!j){ + tvis.item.pszText = TranslateT("None"); } + else { + xstatus.cbSize = sizeof(ICQ_CUSTOM_STATUS); + xstatus.flags = CSSF_MASK_NAME|CSSF_DEFAULT_NAME|CSSF_UNICODE; + xstatus.ptszName = szDefaultName; + xstatus.wParam = &j; + CallProtoService(ProtoList.protoInfo[i].szProto, PS_ICQ_GETCUSTOMSTATUSEX, 0, (LPARAM)&xstatus); + tvis.item.pszText = szDefaultName; + } + tvis.item.lParam = (LPARAM)j; + tvis.item.iImage = tvis.item.iSelectedImage = j?ImageList_AddIcon(hImageList, hIconAux=(HICON)CallProtoService(ProtoList.protoInfo[i].szProto, PS_ICQ_GETCUSTOMSTATUSICON, (WPARAM)j, 0)):0; + if (hIconAux) DestroyIcon(hIconAux); + TreeView_InsertItem(hwndTree, &tvis); + } + } + + tvi.mask = TVIF_HANDLE|TVIF_PARAM; + for (hSectionItem=TreeView_GetRoot(hwndTree); hSectionItem; hSectionItem=TreeView_GetNextSibling(hwndTree, hSectionItem)) { + tvi.hItem = hSectionItem; + TreeView_GetItem(hwndTree, &tvi); + i = (unsigned int)tvi.lParam; + TreeView_SetItemState(hwndTree, hSectionItem, INDEXTOSTATEIMAGEMASK(0), TVIS_STATEIMAGEMASK); + for (hItem=TreeView_GetChild(hwndTree, hSectionItem); hItem; hItem=TreeView_GetNextSibling(hwndTree, hItem)) { + tvi.hItem = hItem; + TreeView_GetItem(hwndTree, &tvi); + j = (unsigned int)tvi.lParam; + TreeView_SetItemState(hwndTree, hItem, INDEXTOSTATEIMAGEMASK(XstatusListAux[i].enabled[j]?2:1), TVIS_STATEIMAGEMASK); + } + } + + ShowWindow(hwndTree, SW_SHOW); + TreeView_SetItemState(hwndTree, 0, TVIS_SELECTED, TVIS_SELECTED); + return TRUE; + } + + case WM_DESTROY: + { + HIMAGELIST hImageList; + + // Destroy tree view imagelist since it does not get destroyed automatically (see msdn docs) + hImageList = TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TREE_XSTATUS), TVSIL_STATE); + if (hImageList) { + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_XSTATUS), NULL, TVSIL_STATE); + ImageList_Destroy(hImageList); + } + hImageList = TreeView_GetImageList(GetDlgItem(hwndDlg, IDC_TREE_XSTATUS), TVSIL_NORMAL); + if (hImageList) { + TreeView_SetImageList(GetDlgItem(hwndDlg, IDC_TREE_XSTATUS), NULL, TVSIL_NORMAL); + ImageList_Destroy(hImageList); + } + return TRUE; + } + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_OKXST: + { + unsigned int i, j; + HTREEITEM hSectionItem, hItem; + TVITEM tvi={0}; + HWND hwndTree = GetDlgItem(hwndDlg, IDC_TREE_XSTATUS); + + tvi.mask = TVIF_HANDLE|TVIF_PARAM; + for (hSectionItem=TreeView_GetRoot(hwndTree); hSectionItem; hSectionItem=TreeView_GetNextSibling(hwndTree, hSectionItem)) { + tvi.hItem = hSectionItem; + TreeView_GetItem(hwndTree, &tvi); + i = (unsigned int)tvi.lParam; + for (hItem=TreeView_GetChild(hwndTree, hSectionItem); hItem; hItem=TreeView_GetNextSibling(hwndTree, hItem)) { + tvi.hItem = hItem; + TreeView_GetItem(hwndTree, &tvi); + j = (unsigned int)tvi.lParam; + XstatusListAux[i].enabled[j] = !!(TreeView_GetItemState(hwndTree, hItem, TVIS_STATEIMAGEMASK)&INDEXTOSTATEIMAGEMASK(2)); + } + } + } + + case IDC_CANCELXST: + EndDialog(hwndDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + + return FALSE; +} diff --git a/plugins/KeyboardNotify/src/protolist.h b/plugins/KeyboardNotify/src/protolist.h new file mode 100644 index 0000000000..5a08d929da --- /dev/null +++ b/plugins/KeyboardNotify/src/protolist.h @@ -0,0 +1,34 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +typedef struct { + UINT_PTR count; + BOOL *enabled; +} XSTATUS_INFO; + +typedef struct { + char *szProto; + BOOL enabled; + BOOL visible; + XSTATUS_INFO xstatus; +} PROTOCOL_INFO; + +typedef struct { + unsigned int protoCount; + PROTOCOL_INFO *protoInfo; +} PROTOCOL_LIST; diff --git a/plugins/KeyboardNotify/src/resource.h b/plugins/KeyboardNotify/src/resource.h new file mode 100644 index 0000000000..4ebfb19cd0 --- /dev/null +++ b/plugins/KeyboardNotify/src/resource.h @@ -0,0 +1,120 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by resources.rc +// +#define IDC_OTHERICON 1 +#define IDD_OPT_KN_ACTION 120 +#define IDD_OPTIONS 150 +#define IDD_PROTO_OPTIONS 151 +#define IDD_BASIC_OPTIONS 152 +#define IDD_EFFECT_OPTIONS 153 +#define IDD_THEME_OPTIONS 154 +#define IDD_EVENTLEDS 155 +#define IDD_PROCESSES 156 +#define IDD_IGNORE_OPTIONS 157 +#define IDD_XSTATUSES 158 +#define IDC_ONMESSAGE 1000 +#define IDC_ONFILE 1001 +#define IDC_ONURL 1002 +#define IDC_ONOTHER 1003 +#define IDC_IFOPEN 1004 +#define IDC_IFNOTTOP 1005 +#define IDC_IFOLDER 1006 +#define IDC_SOLDER 1007 +#define IDC_OLDERSPIN 1008 +#define IDC_UNTILBLK 1009 +#define IDC_SBLINK 1010 +#define IDC_BLINKSPIN 1011 +#define IDC_UNTILATTENDED 1012 +#define IDC_MIRORWIN 1013 +#define IDC_UNTILOPEN 1014 +#define IDC_UNTILCOND 1015 +#define IDC_FSCREEN 1016 +#define IDC_SSAVER 1017 +#define IDC_LOCKED 1018 +#define IDC_PGMS 1019 +#define IDC_ASSIGNPGMS 1020 +#define IDC_ACTIVE 1021 +#define IDC_ONLINE 1022 +#define IDC_AWAY 1023 +#define IDC_NA 1024 +#define IDC_OCCUPIED 1025 +#define IDC_DND 1026 +#define IDC_FREECHAT 1027 +#define IDC_INVISIBLE 1028 +#define IDC_ONTHEPHONE 1029 +#define IDC_OUTTOLUNCH 1030 +#define IDC_OFFLINE 1031 +#define IDC_REMCHECK 1032 +#define IDC_SREMCHECK 1033 +#define IDC_NUM 1034 +#define IDC_CAPS 1035 +#define IDC_SCROLL 1036 +#define IDC_SAMETIME 1037 +#define IDC_INTURN 1038 +#define IDC_INSEQUENCE 1039 +#define IDC_SEQORDER 1040 +#define IDC_CUSTOM 1041 +#define IDC_SCUSTOM 1042 +#define IDC_TRILLIAN 1043 +#define IDC_ASSIGNLEDS 1044 +#define IDC_SDELAY 1045 +#define IDC_DELAYSPIN 1046 +#define IDC_PREVIEW 1047 +#define IDC_SPEED 1048 +#define IDC_THEME 1049 +#define IDC_CUSTOMSTRING 1050 +#define IDC_TEST 1051 +#define IDC_ADD 1052 +#define IDC_UPDATE 1053 +#define IDC_DELETE 1054 +#define IDC_EXPORT 1055 +#define IDC_IMPORT 1056 +#define IDC_OVERRIDE 1057 +#define IDC_PROTOCOLLIST 1058 +#define IDC_MSGLEDNUM 1059 +#define IDC_MSGLEDCAPS 1060 +#define IDC_MSGLEDSCROLL 1061 +#define IDC_FILELEDNUM 1062 +#define IDC_FILELEDCAPS 1063 +#define IDC_FILELEDSCROLL 1064 +#define IDC_URLLEDNUM 1065 +#define IDC_URLLEDCAPS 1066 +#define IDC_URLLEDSCROLL 1067 +#define IDC_OTHERLEDNUM 1068 +#define IDC_OTHERLEDCAPS 1069 +#define IDC_OTHERLEDSCROLL 1070 +#define IDC_OK 1071 +#define IDC_CANCEL 1072 +#define IDC_PROGRAMS 1073 +#define IDC_ADDPGM 1074 +#define IDC_DELETEPGM 1075 +#define IDC_OKPGM 1076 +#define IDC_CANCELPGM 1077 +#define IDC_KEYPRESSES 1078 +#define IDC_CUSTOMTHEME 1079 +#define IDC_USECUSTOM 1080 +#define IDC_LIST 1081 +#define IDC_FORCEOPEN 1082 +#define IDC_SFORCEOPEN 1083 +#define IDC_SELECTXSTATUS 1084 +#define IDC_TREE_XSTATUS 1085 +#define IDC_OKXST 1086 +#define IDC_CANCELXST 1087 +#define IDC_FILEICON 1206 +#define IDC_ALLICON 1208 +#define IDC_NONEICON 1209 +#define IDC_MSGICON 1375 +#define IDC_URLICON 1376 +#define IDC_TABS 2000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1088 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/KeyboardNotify/src/trigger.cpp b/plugins/KeyboardNotify/src/trigger.cpp new file mode 100644 index 0000000000..df3d7daaf3 --- /dev/null +++ b/plugins/KeyboardNotify/src/trigger.cpp @@ -0,0 +1,178 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include +#include +#include +#include "constants.h" +#include "utils.h" +#include "resource.h" +#include +#include +#include +#include "m_trigger.h" + +extern HINSTANCE hInst; + +void StartBlinkAction(char *, WORD); + + +int getCustomNro(DWORD actionID, HWND hwndDlg, int nItems) +{ + int i; + DBVARIANT dbv; + char theme[MAX_PATH+1]; + + if (DBGetTriggerSetting(actionID, NULL, KEYBDMODULE, "custom", &dbv)) + return DEF_SETTING_CUSTOMTHEME; + + for (i=0; i < nItems; i++) { + SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_GETLBTEXT, (WPARAM)i, (LPARAM)theme); + if (!strcmp(dbv.pszVal, theme)) { + DBFreeVariant(&dbv); + return i; + } + } + + DBFreeVariant(&dbv); + return DEF_SETTING_CUSTOMTHEME; +} + +static INT_PTR CALLBACK DlgProcOptsActionKbdNotify(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DBVARIANT dbv; + DWORD actionID; + int i, nItems; + char theme[MAX_PATH+1]; + + switch (msg) { + case WM_INITDIALOG: + actionID = (DWORD)lParam; + TranslateDialogDefault(hwndDlg); + + for (i=0; !DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), &dbv); i++) { + int index = SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_INSERTSTRING, (WPARAM)-1, (LPARAM)dbv.pszVal); + DBFreeVariant(&dbv); + if (index != CB_ERR && index != CB_ERRSPACE) + SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_SETITEMDATA, (WPARAM)index, (LPARAM)i); + } + + nItems = SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_GETCOUNT, 0, 0); + + CheckDlgButton(hwndDlg, IDC_USECUSTOM, nItems && DBGetTriggerSettingByte(actionID, NULL, KEYBDMODULE, "usecustom", 0) ? BST_CHECKED:BST_UNCHECKED); + EnableWindow(GetDlgItem(hwndDlg, IDC_USECUSTOM), nItems); + + SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_SETCURSEL, (WPARAM)getCustomNro(actionID, hwndDlg, nItems), 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_CUSTOMTHEME), IsDlgButtonChecked(hwndDlg, IDC_USECUSTOM) == BST_CHECKED); + + SendDlgItemMessage(hwndDlg, IDC_FORCEOPEN, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_SFORCEOPEN), 0); + SendDlgItemMessage(hwndDlg, IDC_FORCEOPEN, UDM_SETRANGE32, 1, MAKELONG(UD_MAXVAL, 0)); + SendDlgItemMessage(hwndDlg, IDC_FORCEOPEN, UDM_SETPOS, 0, MAKELONG(DBGetTriggerSettingWord(actionID, NULL, KEYBDMODULE, "forceopen", DEF_SETTING_NBLINKS), 0)); + + break; + + case TM_ADDACTION: // save the settings + actionID = (DWORD)wParam; + DBWriteTriggerSettingByte(actionID, NULL, KEYBDMODULE, "usecustom", (BYTE)(IsDlgButtonChecked(hwndDlg, IDC_USECUSTOM) == BST_CHECKED ? 1:0)); + SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_GETLBTEXT, (WPARAM)SendDlgItemMessage(hwndDlg, IDC_CUSTOMTHEME, CB_GETCURSEL, 0, 0), (LPARAM)theme); + DBWriteTriggerSettingString(actionID, NULL, KEYBDMODULE, "custom", theme); + DBWriteTriggerSettingWord(actionID, NULL, KEYBDMODULE, "forceopen", (WORD)SendDlgItemMessage(hwndDlg, IDC_FORCEOPEN, UDM_GETPOS, 0, 0)); + break; + + case WM_COMMAND: + if (LOWORD(wParam) == IDC_USECUSTOM) + EnableWindow(GetDlgItem(hwndDlg, IDC_CUSTOMTHEME), IsDlgButtonChecked(hwndDlg, IDC_USECUSTOM) == BST_CHECKED); + break; + + case WM_DESTROY: + break; + } + + return FALSE; +} + +char *getCustomString(DWORD actionID) +{ + int i; + DBVARIANT dbv, dbv2; + static char customString[MAX_PATH+1]; + + if (DBGetTriggerSetting(actionID, NULL, KEYBDMODULE, "custom", &dbv)) + return NULL; + + for (i=0; !DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("theme%d", i), &dbv2); i++) { + if (!strcmp(dbv.pszVal, dbv2.pszVal)) { + DBFreeVariant(&dbv); + DBFreeVariant(&dbv2); + if(DBGetContactSetting(NULL, KEYBDMODULE, fmtDBSettingName("custom%d", i), &dbv2)) + return NULL; + strcpy(customString, dbv2.pszVal); + DBFreeVariant(&dbv2); + return customString; + } + DBFreeVariant(&dbv2); + } + + DBFreeVariant(&dbv); + return NULL; +} + +static int TriggerStartBlinkFunction(DWORD actionID, REPORTINFO *ri) +{ + if (ri->flags&ACT_PERFORM) { + char *customStr; + + if (!DBGetTriggerSettingByte(actionID, NULL, KEYBDMODULE, "usecustom", 0)) + customStr = NULL; + else + customStr = getCustomString(actionID); + StartBlinkAction(customStr, DBGetTriggerSettingWord(actionID, NULL, KEYBDMODULE, "forceopen", DEF_SETTING_NBLINKS)); + } + if (ri->flags&ACT_CLEANUP) { // request to delete all associated settings + RemoveAllActionSettings(actionID, KEYBDMODULE); + } + + return 0; // all ok +} + +int RegisterAction() +{ + ACTIONREGISTER ar; + + if (!ServiceExists(MS_TRIGGER_REGISTERACTION)) + return -1; + + ZeroMemory(&ar, sizeof(ar)); + ar.cbSize = sizeof(ar); + ar.pszName = "Keyboard Flash: Start Blinking"; + ar.actionFunction = TriggerStartBlinkFunction; + ar.hInstance = hInst; + ar.pfnDlgProc = DlgProcOptsActionKbdNotify; + ar.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_KN_ACTION); + ar.flags = ARF_FUNCTION; + return CallService(MS_TRIGGER_REGISTERACTION, 0, (LPARAM)&ar); +} + +int DeInitAction() +{ + return 0; +} diff --git a/plugins/KeyboardNotify/src/trigger.h b/plugins/KeyboardNotify/src/trigger.h new file mode 100644 index 0000000000..41d830938c --- /dev/null +++ b/plugins/KeyboardNotify/src/trigger.h @@ -0,0 +1,20 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +int RegisterAction(); +int DeInitAction(); diff --git a/plugins/KeyboardNotify/src/utils.cpp b/plugins/KeyboardNotify/src/utils.cpp new file mode 100644 index 0000000000..9c710ba217 --- /dev/null +++ b/plugins/KeyboardNotify/src/utils.cpp @@ -0,0 +1,52 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#define WIN32_LEAN_AND_MEAN + +#include +#include +#include "utils.h" +#include +#include +#include + + +char *fmtDBSettingName(const char *fmt, ...) +{ + va_list va; + static char returnString[1024]; + + va_start(va, fmt); + mir_vsnprintf(returnString, sizeof(returnString), fmt, va); + va_end(va); + + return returnString; +} + + +TCHAR *getAbsoluteProfileName(TCHAR *absoluteProfileName, size_t maxLen) +{ + TCHAR profilePath[MAX_PATH+1], profileName[MAX_PATH+1]; + + profilePath[0] = profileName[0] = L'\0'; + CallService(MS_DB_GETPROFILEPATH, MAX_PATH, (LPARAM)profilePath); + CallService(MS_DB_GETPROFILENAME, MAX_PATH, (LPARAM)profileName); + _snwprintf(absoluteProfileName, maxLen, L"%s\\%s", profilePath, profileName); + + return absoluteProfileName; +} diff --git a/plugins/KeyboardNotify/src/utils.h b/plugins/KeyboardNotify/src/utils.h new file mode 100644 index 0000000000..66917754ed --- /dev/null +++ b/plugins/KeyboardNotify/src/utils.h @@ -0,0 +1,20 @@ +/* + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +char *fmtDBSettingName(const char *, ...); +TCHAR *getAbsoluteProfileName(TCHAR *, size_t); -- cgit v1.2.3