summaryrefslogtreecommitdiff
path: root/plugins/KeyboardNotify/src
diff options
context:
space:
mode:
authorVadim Dashevskiy <watcherhd@gmail.com>2012-07-20 10:43:41 +0000
committerVadim Dashevskiy <watcherhd@gmail.com>2012-07-20 10:43:41 +0000
commit6e7980b0ad162bbb526b3d52acbc1639c2b11760 (patch)
tree3affd52d5c43ac3b06507ff56358635767949004 /plugins/KeyboardNotify/src
parentda9f6e8a856fc87172fb0d5997c607b4a930c102 (diff)
Import, KeyboardNotify: changed folder structure
git-svn-id: http://svn.miranda-ng.org/main/trunk@1071 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'plugins/KeyboardNotify/src')
-rw-r--r--plugins/KeyboardNotify/src/AggressiveOptimize.h165
-rw-r--r--plugins/KeyboardNotify/src/EnumProc.cpp260
-rw-r--r--plugins/KeyboardNotify/src/EnumProc.h27
-rw-r--r--plugins/KeyboardNotify/src/constants.h85
-rw-r--r--plugins/KeyboardNotify/src/flash.cpp438
-rw-r--r--plugins/KeyboardNotify/src/flash.h28
-rw-r--r--plugins/KeyboardNotify/src/ignore.cpp389
-rw-r--r--plugins/KeyboardNotify/src/ignore.h20
-rw-r--r--plugins/KeyboardNotify/src/keyboard.cpp120
-rw-r--r--plugins/KeyboardNotify/src/keyboard.h21
-rw-r--r--plugins/KeyboardNotify/src/keypresses.cpp77
-rw-r--r--plugins/KeyboardNotify/src/keypresses.h20
-rw-r--r--plugins/KeyboardNotify/src/main.cpp1448
-rw-r--r--plugins/KeyboardNotify/src/options.cpp1565
-rw-r--r--plugins/KeyboardNotify/src/protolist.h34
-rw-r--r--plugins/KeyboardNotify/src/resource.h120
-rw-r--r--plugins/KeyboardNotify/src/trigger.cpp178
-rw-r--r--plugins/KeyboardNotify/src/trigger.h20
-rw-r--r--plugins/KeyboardNotify/src/utils.cpp52
-rw-r--r--plugins/KeyboardNotify/src/utils.h20
20 files changed, 5087 insertions, 0 deletions
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 <Mike@Geary.com> 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 <gpani@siu.edu> 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 <windows.h>
+#include <stdio.h>
+#include <tlhelp32.h>
+#include <vdmdbg.h>
+#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 <windows.h>
+#include "flash.h"
+#include "keyboard.h"
+#include "keypresses.h"
+#include "utils.h"
+#include "constants.h"
+#include <newpluginapi.h>
+#include <m_database.h>
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include "ignore.h"
+#include "resource.h"
+#include "constants.h"
+#include <newpluginapi.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_protocols.h>
+#include <m_skin.h>
+
+
+#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<<i)?i+3:0));
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNOREEVENT_MAX, 1));
+ SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNOREEVENT_MAX+1, 2));
+}
+
+static void SaveItemMask(HWND hwndList, HANDLE hContact, HANDLE hItem, const char *pszSetting)
+{
+ DWORD mask;
+ int i, iImage;
+
+ for(i=0, mask=0; i < IGNOREEVENT_MAX; i++) {
+ iImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(i, 0));
+ if(iImage && iImage != 0xFF)
+ mask |= 1<<i;
+ }
+ DBWriteContactSettingDword(hContact, KEYBDMODULE, pszSetting, mask);
+}
+
+static void SetAllContactIcons(HWND hwndList)
+{
+ HANDLE hContact,hItem;
+ DWORD protoCaps;
+ char *szProto;
+
+ hContact=(HANDLE)CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
+ do {
+ hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0);
+ if(hItem && SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(IGNOREEVENT_MAX, 0)) == 0xFF) {
+ szProto = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0);
+ if(szProto == NULL)
+ protoCaps = 0;
+ else
+ protoCaps = CallProtoService(szProto, PS_GETCAPS,PFLAGNUM_1, 0);
+ InitialiseItem(hwndList, hContact, hItem, protoCaps);
+ }
+ } while(hContact = (HANDLE)CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0));
+}
+
+INT_PTR CALLBACK DlgProcIgnoreOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HICON hIcons[IGNOREEVENT_MAX+2];
+ static HANDLE hItemAll, hItemUnknown;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ { int i;
+ HIMAGELIST hIml;
+ hIml=ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ((bWindowsNT && dWinVer >= 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 <stdio.h>
+#include <windows.h>
+#include <winioctl.h>
+#include "keypresses.h"
+#include <newpluginapi.h>
+#include <m_utils.h>
+
+
+// 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 <windows.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#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 <newpluginapi.h>
+#include <m_database.h>
+#include <m_options.h>
+#include <m_clist.h>
+#include <m_system.h>
+#include <m_langpack.h>
+#include <m_protocols.h>
+#include <m_protosvc.h>
+#include <m_contacts.h>
+#include <m_message.h>
+#include <m_utils.h>
+#include <m_icq.h>
+#include <m_metacontacts.h>
+#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 <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include "flash.h"
+#include "ignore.h"
+#include "resource.h"
+#include "constants.h"
+#include "protolist.h"
+#include "EnumProc.h"
+#include "utils.h"
+#include <newpluginapi.h>
+#include <m_clc.h>
+#include <m_clist.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#include <m_options.h>
+#include <m_protosvc.h>
+#include <m_protocols.h>
+#include <m_icq.h>
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include "constants.h"
+#include "utils.h"
+#include "resource.h"
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_langpack.h>
+#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 <stdio.h>
+#include <windows.h>
+#include "utils.h"
+#include <newpluginapi.h>
+#include <m_database.h>
+#include <m_utils.h>
+
+
+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);