summaryrefslogtreecommitdiff
path: root/plugins/KeyboardNotify/src/flash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/KeyboardNotify/src/flash.cpp')
-rw-r--r--plugins/KeyboardNotify/src/flash.cpp438
1 files changed, 438 insertions, 0 deletions
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;
+}