From 397e25f2b71347c7c83495fe5b25496ff3b02b75 Mon Sep 17 00:00:00 2001 From: Philip Schell Date: Sat, 19 Oct 2013 13:05:02 +0000 Subject: WinterSpeak: ticket:269 WinterSpeak now rewritten git-svn-id: http://svn.miranda-ng.org/main/trunk@6532 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/WinterSpeak/src/AnnounceDatabase.cpp | 82 ++++++ plugins/WinterSpeak/src/AnnounceDatabase.h | 64 ++++ plugins/WinterSpeak/src/AnnounceDialog.cpp | 149 ++++++++++ plugins/WinterSpeak/src/AnnounceDialog.h | 30 ++ plugins/WinterSpeak/src/Common.h | 41 +++ plugins/WinterSpeak/src/ConfigDatabase.cpp | 146 +++++++++ plugins/WinterSpeak/src/ConfigDatabase.h | 79 +++++ plugins/WinterSpeak/src/DialogConfigActive.cpp | 376 ++++++++++++++++++++++++ plugins/WinterSpeak/src/DialogConfigActive.h | 49 +++ plugins/WinterSpeak/src/DialogConfigEngine.cpp | 229 +++++++++++++++ plugins/WinterSpeak/src/DialogConfigEngine.h | 41 +++ plugins/WinterSpeak/src/EventInformation.cpp | 85 ++++++ plugins/WinterSpeak/src/EventInformation.h | 53 ++++ plugins/WinterSpeak/src/MirandaDialog.cpp | 38 +++ plugins/WinterSpeak/src/MirandaDialog.h | 12 + plugins/WinterSpeak/src/Observer.cpp | 6 + plugins/WinterSpeak/src/Observer.h | 17 ++ plugins/WinterSpeak/src/ProtocolInformation.cpp | 78 +++++ plugins/WinterSpeak/src/ProtocolInformation.h | 25 ++ plugins/WinterSpeak/src/SpeakAnnounce.cpp | 206 +++++++++++++ plugins/WinterSpeak/src/SpeakAnnounce.h | 54 ++++ plugins/WinterSpeak/src/SpeakConfig.cpp | 107 +++++++ plugins/WinterSpeak/src/SpeakConfig.h | 41 +++ plugins/WinterSpeak/src/SpeechApi51.cpp | 253 ++++++++++++++++ plugins/WinterSpeak/src/SpeechApi51.h | 83 ++++++ plugins/WinterSpeak/src/SpeechApi51Lexicon.cpp | 75 +++++ plugins/WinterSpeak/src/SpeechApi51Lexicon.h | 35 +++ plugins/WinterSpeak/src/SpeechInterface.cpp | 68 +++++ plugins/WinterSpeak/src/SpeechInterface.h | 32 ++ plugins/WinterSpeak/src/Subject.cpp | 55 ++++ plugins/WinterSpeak/src/Subject.h | 38 +++ plugins/WinterSpeak/src/TextToSpeech.cpp | 14 + plugins/WinterSpeak/src/TextToSpeech.h | 74 +++++ plugins/WinterSpeak/src/UserInformation.cpp | 78 +++++ plugins/WinterSpeak/src/UserInformation.h | 53 ++++ plugins/WinterSpeak/src/Version.h | 14 + plugins/WinterSpeak/src/m_speak.h | 4 + plugins/WinterSpeak/src/main.cpp | 172 +++++++++++ plugins/WinterSpeak/src/resource.h | 71 +++++ plugins/WinterSpeak/src/stdafx.cpp | 18 ++ plugins/WinterSpeak/src/voice_desc.h | 10 + 41 files changed, 3155 insertions(+) create mode 100644 plugins/WinterSpeak/src/AnnounceDatabase.cpp create mode 100644 plugins/WinterSpeak/src/AnnounceDatabase.h create mode 100644 plugins/WinterSpeak/src/AnnounceDialog.cpp create mode 100644 plugins/WinterSpeak/src/AnnounceDialog.h create mode 100644 plugins/WinterSpeak/src/Common.h create mode 100644 plugins/WinterSpeak/src/ConfigDatabase.cpp create mode 100644 plugins/WinterSpeak/src/ConfigDatabase.h create mode 100644 plugins/WinterSpeak/src/DialogConfigActive.cpp create mode 100644 plugins/WinterSpeak/src/DialogConfigActive.h create mode 100644 plugins/WinterSpeak/src/DialogConfigEngine.cpp create mode 100644 plugins/WinterSpeak/src/DialogConfigEngine.h create mode 100644 plugins/WinterSpeak/src/EventInformation.cpp create mode 100644 plugins/WinterSpeak/src/EventInformation.h create mode 100644 plugins/WinterSpeak/src/MirandaDialog.cpp create mode 100644 plugins/WinterSpeak/src/MirandaDialog.h create mode 100644 plugins/WinterSpeak/src/Observer.cpp create mode 100644 plugins/WinterSpeak/src/Observer.h create mode 100644 plugins/WinterSpeak/src/ProtocolInformation.cpp create mode 100644 plugins/WinterSpeak/src/ProtocolInformation.h create mode 100644 plugins/WinterSpeak/src/SpeakAnnounce.cpp create mode 100644 plugins/WinterSpeak/src/SpeakAnnounce.h create mode 100644 plugins/WinterSpeak/src/SpeakConfig.cpp create mode 100644 plugins/WinterSpeak/src/SpeakConfig.h create mode 100644 plugins/WinterSpeak/src/SpeechApi51.cpp create mode 100644 plugins/WinterSpeak/src/SpeechApi51.h create mode 100644 plugins/WinterSpeak/src/SpeechApi51Lexicon.cpp create mode 100644 plugins/WinterSpeak/src/SpeechApi51Lexicon.h create mode 100644 plugins/WinterSpeak/src/SpeechInterface.cpp create mode 100644 plugins/WinterSpeak/src/SpeechInterface.h create mode 100644 plugins/WinterSpeak/src/Subject.cpp create mode 100644 plugins/WinterSpeak/src/Subject.h create mode 100644 plugins/WinterSpeak/src/TextToSpeech.cpp create mode 100644 plugins/WinterSpeak/src/TextToSpeech.h create mode 100644 plugins/WinterSpeak/src/UserInformation.cpp create mode 100644 plugins/WinterSpeak/src/UserInformation.h create mode 100644 plugins/WinterSpeak/src/Version.h create mode 100644 plugins/WinterSpeak/src/m_speak.h create mode 100644 plugins/WinterSpeak/src/main.cpp create mode 100644 plugins/WinterSpeak/src/resource.h create mode 100644 plugins/WinterSpeak/src/stdafx.cpp create mode 100644 plugins/WinterSpeak/src/voice_desc.h (limited to 'plugins/WinterSpeak/src') diff --git a/plugins/WinterSpeak/src/AnnounceDatabase.cpp b/plugins/WinterSpeak/src/AnnounceDatabase.cpp new file mode 100644 index 0000000000..526d057058 --- /dev/null +++ b/plugins/WinterSpeak/src/AnnounceDatabase.cpp @@ -0,0 +1,82 @@ +#include "Common.h" +#include "AnnounceDatabase.h" + + +//------------------------------------------------------------------------------ +namespace +{ + const char *SPEAK = "speak_announce"; + const char *STATUS_FLAGS = "status_flags"; + const char *EVENT_FLAGS = "event_flags"; + const char *MAX_MSG_SIZE = "max_msg_size"; +} + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +AnnounceDatabase::AnnounceDatabase() : m_status_flags(0), m_event_flags(0), m_max_msg(0) +{ + load(); +} + +//------------------------------------------------------------------------------ +AnnounceDatabase::~AnnounceDatabase() +{ +} + +//------------------------------------------------------------------------------ +bool AnnounceDatabase::getStatusFlag(StatusFlag flag) const +{ + return ((m_status_flags & (1 << flag)) != 0); +} + +//------------------------------------------------------------------------------ +void AnnounceDatabase::setStatusFlag(StatusFlag flag, bool state) +{ + if (state) + { + m_status_flags |= (1 << flag); + } + else + { + m_status_flags &= ~(1 << flag); + } +} + +//------------------------------------------------------------------------------ +bool AnnounceDatabase::getEventFlag(EventFlag flag) const +{ + return ((m_event_flags & (1 << flag)) != 0); +} + +//------------------------------------------------------------------------------ +void AnnounceDatabase::setEventFlag(EventFlag flag, bool state) +{ + if (state) + { + m_event_flags |= (1 << flag); + } + else + { + m_event_flags &= ~(1 << flag); + } +} + +//------------------------------------------------------------------------------ +void AnnounceDatabase::load() +{ + m_status_flags = db_get_dw(NULL, SPEAK, STATUS_FLAGS, 0xffff); + m_event_flags = db_get_dw(NULL, SPEAK, EVENT_FLAGS, 0xffff); + m_max_msg = db_get_dw(NULL, SPEAK, MAX_MSG_SIZE, 50); +} + +//------------------------------------------------------------------------------ +void +AnnounceDatabase::save() +{ + db_set_dw(NULL, SPEAK, STATUS_FLAGS, m_status_flags); + db_set_dw(NULL, SPEAK, EVENT_FLAGS, m_event_flags); + db_set_dw(NULL, SPEAK, MAX_MSG_SIZE, m_max_msg); +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/AnnounceDatabase.h b/plugins/WinterSpeak/src/AnnounceDatabase.h new file mode 100644 index 0000000000..06014843ac --- /dev/null +++ b/plugins/WinterSpeak/src/AnnounceDatabase.h @@ -0,0 +1,64 @@ +#pragma once + +class AnnounceDatabase +{ + public: + AnnounceDatabase(); + ~AnnounceDatabase(); + + enum StatusFlag + { + StatusFlag_Offline = 0, + StatusFlag_Online, + StatusFlag_Away, + StatusFlag_Dnd, + StatusFlag_Na, + StatusFlag_Occupied, + StatusFlag_FreeForChat, + StatusFlag_Invisible, + StatusFlag_SpeakStatusMsg, + StatusFlag_SuppressConnect, + }; + + enum EventFlag + { + EventFlag_Message = 0, + EventFlag_Url, + EventFlag_Added, + EventFlag_AuthRequest, + EventFlag_File, + EventFlag_ReadMsgLength, + EventFlag_DialogOpen, + EventFlag_DialogFocused, + }; + + //-------------------------------------------------------------------------- + // Description : get/set a status flags + //-------------------------------------------------------------------------- + bool getStatusFlag(StatusFlag flag) const; + void setStatusFlag(StatusFlag flag, bool state); + + //-------------------------------------------------------------------------- + // Description : get/set an event flags + //-------------------------------------------------------------------------- + bool getEventFlag(EventFlag flag) const; + void setEventFlag(EventFlag flag, bool state); + + //-------------------------------------------------------------------------- + // Description : get/set an event flags + //-------------------------------------------------------------------------- + unsigned int getMaxMsgSize() const { return m_max_msg; } + void setMaxMsgSize(unsigned int size) { m_max_msg = size; } + + //-------------------------------------------------------------------------- + // Description : load/save the settings from the miranda database + //-------------------------------------------------------------------------- + void load(); + void save(); + + private: + unsigned int m_status_flags; + unsigned int m_event_flags; + + unsigned int m_max_msg; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/AnnounceDialog.cpp b/plugins/WinterSpeak/src/AnnounceDialog.cpp new file mode 100644 index 0000000000..11b917b287 --- /dev/null +++ b/plugins/WinterSpeak/src/AnnounceDialog.cpp @@ -0,0 +1,149 @@ +#include "Common.h" +#include "AnnounceDialog.h" + + +AnnounceDialog *AnnounceDialog::m_instance = 0; + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +AnnounceDialog::AnnounceDialog(AnnounceDatabase &db) : m_db(db) +{ + m_instance = this; +} + +//------------------------------------------------------------------------------ +AnnounceDialog::~AnnounceDialog() +{ + m_instance = 0; +} + +//------------------------------------------------------------------------------ +// private: +//------------------------------------------------------------------------------ +INT_PTR CALLBACK AnnounceDialog::process(HWND window, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (!m_instance) + { + return 1; + } + + switch (message) + { + case WM_INITDIALOG: + m_instance->load(window); + break; + + case WM_COMMAND: + m_instance->command(window, wparam); + break; + + case WM_NOTIFY: + if (PSN_APPLY == LPNMHDR(lparam)->code) + { + m_instance->save(window); + } + break; + } + + return 0; +} + +//------------------------------------------------------------------------------ +void AnnounceDialog::command(HWND window, int control) +{ + switch (LOWORD(control)) + { + case IDC_STATUS_OFFLINE: + case IDC_STATUS_ONLINE: + case IDC_STATUS_AWAY: + case IDC_STATUS_DND: + case IDC_STATUS_NA: + case IDC_STATUS_OCCUPIED: + case IDC_STATUS_FREEFORCHAT: + case IDC_STATUS_INVISIBLE: + case IDC_SPEAK_STATUS_MSG: + case IDC_SUPPRESS_CONNECT: + case IDC_EVENT_MESSAGE: + case IDC_EVENT_URL: + case IDC_EVENT_FILE: + case IDC_EVENT_AUTHREQUEST: + case IDC_EVENT_ADDED: + case IDC_READ_MSG_LENGTH: + case IDC_DIALOG_OPEN: + case IDC_DIALOG_FOCUSED: + + changed(window); + break; + + case IDC_MAX_MSG: + if (EN_CHANGE == HIWORD(control)) + { + changed(window); + } + break; + } +} + +//------------------------------------------------------------------------------ +void +AnnounceDialog::load(HWND window) +{ + TranslateDialogDefault(window); + + // initialise the checkboxes + CheckDlgButton(window, IDC_STATUS_OFFLINE, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Offline)); + CheckDlgButton(window, IDC_STATUS_ONLINE, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Online)); + CheckDlgButton(window, IDC_STATUS_AWAY, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Away)); + CheckDlgButton(window, IDC_STATUS_DND, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Dnd)); + CheckDlgButton(window, IDC_STATUS_NA, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Na)); + CheckDlgButton(window, IDC_STATUS_OCCUPIED, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Occupied)); + CheckDlgButton(window, IDC_STATUS_FREEFORCHAT, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_FreeForChat)); + CheckDlgButton(window, IDC_STATUS_INVISIBLE, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Invisible)); + CheckDlgButton(window, IDC_SPEAK_STATUS_MSG, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_SpeakStatusMsg)); + CheckDlgButton(window, IDC_SUPPRESS_CONNECT, m_db.getStatusFlag(AnnounceDatabase::StatusFlag_SuppressConnect)); + + CheckDlgButton(window, IDC_EVENT_MESSAGE, m_db.getEventFlag(AnnounceDatabase::EventFlag_Message)); + CheckDlgButton(window, IDC_EVENT_URL, m_db.getEventFlag(AnnounceDatabase::EventFlag_Url)); + CheckDlgButton(window, IDC_EVENT_FILE, m_db.getEventFlag(AnnounceDatabase::EventFlag_File)); + CheckDlgButton(window, IDC_EVENT_AUTHREQUEST, m_db.getEventFlag(AnnounceDatabase::EventFlag_AuthRequest)); + CheckDlgButton(window, IDC_EVENT_ADDED, m_db.getEventFlag(AnnounceDatabase::EventFlag_Added)); + CheckDlgButton(window, IDC_READ_MSG_LENGTH, m_db.getEventFlag(AnnounceDatabase::EventFlag_ReadMsgLength)); + CheckDlgButton(window, IDC_DIALOG_OPEN, m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogOpen)); + CheckDlgButton(window, IDC_DIALOG_FOCUSED, m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogFocused)); + + // initialise the welcome message box + SetDlgItemInt(window, IDC_MAX_MSG, m_db.getMaxMsgSize(), 0); +} + +//------------------------------------------------------------------------------ +void +AnnounceDialog::save(HWND window) +{ + // store the checkboxes + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Offline, (IsDlgButtonChecked(window, IDC_STATUS_OFFLINE) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Online, (IsDlgButtonChecked(window, IDC_STATUS_ONLINE) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Away, (IsDlgButtonChecked(window, IDC_STATUS_AWAY) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Dnd, (IsDlgButtonChecked(window, IDC_STATUS_DND) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Na, (IsDlgButtonChecked(window, IDC_STATUS_NA) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Occupied, (IsDlgButtonChecked(window, IDC_STATUS_OCCUPIED) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_FreeForChat, (IsDlgButtonChecked(window, IDC_STATUS_FREEFORCHAT) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_Invisible, (IsDlgButtonChecked(window, IDC_STATUS_INVISIBLE) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_SpeakStatusMsg, (IsDlgButtonChecked(window, IDC_SPEAK_STATUS_MSG) != 0)); + m_db.setStatusFlag(AnnounceDatabase::StatusFlag_SuppressConnect, (IsDlgButtonChecked(window, IDC_SUPPRESS_CONNECT) != 0)); + + m_db.setEventFlag(AnnounceDatabase::EventFlag_Message, (IsDlgButtonChecked(window, IDC_EVENT_MESSAGE) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_Url, (IsDlgButtonChecked(window, IDC_EVENT_URL) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_File, (IsDlgButtonChecked(window, IDC_EVENT_FILE) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_AuthRequest, (IsDlgButtonChecked(window, IDC_EVENT_AUTHREQUEST) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_Added, (IsDlgButtonChecked(window, IDC_EVENT_ADDED) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_ReadMsgLength, (IsDlgButtonChecked(window, IDC_READ_MSG_LENGTH) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_DialogOpen, (IsDlgButtonChecked(window, IDC_DIALOG_OPEN) != 0)); + m_db.setEventFlag(AnnounceDatabase::EventFlag_DialogFocused, (IsDlgButtonChecked(window, IDC_DIALOG_FOCUSED) != 0)); + + m_db.setMaxMsgSize(GetDlgItemInt(window, IDC_MAX_MSG, NULL, 0)); + + m_instance->m_db.save(); +} + +//============================================================================== \ No newline at end of file diff --git a/plugins/WinterSpeak/src/AnnounceDialog.h b/plugins/WinterSpeak/src/AnnounceDialog.h new file mode 100644 index 0000000000..3a3da28f9a --- /dev/null +++ b/plugins/WinterSpeak/src/AnnounceDialog.h @@ -0,0 +1,30 @@ +#pragma once +#include "mirandadialog.h" +#include "AnnounceDatabase.h" + +class AnnounceDialog : public MirandaDialog +{ + public: + AnnounceDialog(AnnounceDatabase &db); + ~AnnounceDialog(); + + //-------------------------------------------------------------------------- + // Description : process a dialog message + // Return : true - update the systems configuration + // false - do nothing + //-------------------------------------------------------------------------- + static INT_PTR CALLBACK process(HWND window, UINT message, WPARAM wparam, LPARAM lparam); + + private: + void command(HWND window, int control); + + //-------------------------------------------------------------------------- + // Description : load/save settings to the miranda database + //-------------------------------------------------------------------------- + void load(HWND window); + void save(HWND window); + + static AnnounceDialog *m_instance; + AnnounceDatabase &m_db; +}; + diff --git a/plugins/WinterSpeak/src/Common.h b/plugins/WinterSpeak/src/Common.h new file mode 100644 index 0000000000..cff8761c21 --- /dev/null +++ b/plugins/WinterSpeak/src/Common.h @@ -0,0 +1,41 @@ +#define _CRT_SECURE_NO_WARNINGS +#define WIN32_LEAN_AND_MEAN + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "resource.h" +#include "Version.h" +#include "m_speak.h" + +#include "DialogConfigEngine.h" +#include "DialogConfigActive.h" + +#include "AnnounceDialog.h" +#include "AnnounceDatabase.h" +#include "SpeakAnnounce.h" + +#include "ConfigDatabase.h" +#include "MirandaDialog.h" +#include "Subject.h" +#include "SpeechInterface.h" +#include "SpeakConfig.h" +#include "UserInformation.h" +#include "EventInformation.h" +#include "ProtocolInformation.h" \ No newline at end of file diff --git a/plugins/WinterSpeak/src/ConfigDatabase.cpp b/plugins/WinterSpeak/src/ConfigDatabase.cpp new file mode 100644 index 0000000000..64af1e35f4 --- /dev/null +++ b/plugins/WinterSpeak/src/ConfigDatabase.cpp @@ -0,0 +1,146 @@ +#include "Common.h" +#include "ConfigDatabase.h" + + +namespace +{ + const char *SPEAK = "speak_config"; + const char *ACTIVE_FLAGS = "active_flags"; + const char *ACTIVE_STATE = "active_state"; + const char *ACTIVE_MSG = "active_msg"; + const char *WELCOME_MSG = "welcome_msg"; + const char *ENGINE = "engine"; + const char *VOICE = "voice"; + const char *VOLUME = "volume"; + const char *RATE = "rate"; + const char *PITCH = "pitch"; +} + +ConfigDatabase::ConfigDatabase() : m_voice_desc(), m_active_flags(0), m_welcome_msg(L""), m_active_users() +{ + // load the database from miranda + load(); +} + + +ConfigDatabase::~ConfigDatabase(void) +{ +} + + +bool ConfigDatabase::getActiveFlag(ActiveFlag flag) const +{ + return ((m_active_flags & (1 << flag)) != 0); +} + +//------------------------------------------------------------------------------ +void ConfigDatabase::setActiveFlag(ActiveFlag flag, bool state) +{ + if (state) + { + m_active_flags |= (1 << flag); + } + else + { + m_active_flags &= ~(1 << flag); + } +} + +//------------------------------------------------------------------------------ +ConfigDatabase::act ConfigDatabase::getActiveUser(HANDLE user) const +{ + ActiveUsersMap::const_iterator iter = m_active_users.find(user); + + if (iter == m_active_users.end()) + { + // get the unknown user status + iter = m_active_users.find(0); + + if (iter == m_active_users.end()) + { + ConfigDatabase::act ret; + ret.message = false; + ret.status = false; + return ret; + } + } + + return iter->second; +} + +//------------------------------------------------------------------------------ +void ConfigDatabase::setActiveUser(HANDLE user, act state) +{ + m_active_users[user].status = state.status; + m_active_users[user].message = state.message; +} + +//------------------------------------------------------------------------------ +void ConfigDatabase::load() +{ + m_voice_desc.engine = DBGetContactSettingString(SPEAK, ENGINE, L""); + m_voice_desc.voice = DBGetContactSettingString(SPEAK, VOICE, L""); + m_voice_desc.volume = db_get_dw(NULL, SPEAK, VOLUME, 50); + m_voice_desc.pitch = db_get_dw(NULL, SPEAK, PITCH, 50); + m_voice_desc.rate = db_get_dw(NULL, SPEAK, RATE, 50); + + m_active_flags = db_get_dw(NULL, SPEAK, ACTIVE_FLAGS, 0xffff); + + m_welcome_msg = DBGetContactSettingString(SPEAK, WELCOME_MSG, L"Welcome to Miranda"); + + // iterate through all the users and add them to the list if active + HANDLE contact = db_find_first(); + + while (NULL != contact) + { + m_active_users[contact].status = (db_get_b(contact, SPEAK, ACTIVE_STATE, true) != 0); + m_active_users[contact].message = (db_get_b(contact, SPEAK, ACTIVE_MSG, true) != 0); + + contact = db_find_next(contact); + } + + // load unknown users setting + m_active_users[0].status = (db_get_b(NULL, SPEAK, ACTIVE_STATE, true) != 0); + m_active_users[0].message = (db_get_b(NULL, SPEAK, ACTIVE_MSG, true) != 0); +} + +//------------------------------------------------------------------------------ +void ConfigDatabase::save() +{ + db_set_ts(NULL, SPEAK, ENGINE, m_voice_desc.engine.c_str()); + db_set_ts(NULL, SPEAK, VOICE, m_voice_desc.voice.c_str()); + db_set_dw(NULL, SPEAK, VOLUME, m_voice_desc.volume); + db_set_dw(NULL, SPEAK, PITCH, m_voice_desc.pitch); + db_set_dw(NULL, SPEAK, RATE, m_voice_desc.rate); + + db_set_dw(NULL, SPEAK, ACTIVE_FLAGS, m_active_flags); + + db_set_ts(NULL, SPEAK, WELCOME_MSG, m_welcome_msg.c_str()); + + for (ActiveUsersMap::iterator i = m_active_users.begin(); i != m_active_users.end(); ++i) + { + db_set_b(i->first, SPEAK, ACTIVE_STATE, i->second.status); + db_set_b(i->first, SPEAK, ACTIVE_MSG, i->second.message); + } + + // notify the subjects that things have changed + notify(); +} + +//------------------------------------------------------------------------------ +// private: +//------------------------------------------------------------------------------ +std::wstring ConfigDatabase::DBGetContactSettingString(const char *szModule, const char *szSetting, const WCHAR *def) +{ + std::wstring ret = def; + DBVARIANT dbv; + + if (!db_get_ts(NULL, szModule, szSetting, &dbv)) + { + ret = dbv.pwszVal; + } + + return ret; +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/ConfigDatabase.h b/plugins/WinterSpeak/src/ConfigDatabase.h new file mode 100644 index 0000000000..5682abf0f0 --- /dev/null +++ b/plugins/WinterSpeak/src/ConfigDatabase.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include "voice_desc.h" +#include "Subject.h" + +class ConfigDatabase : public Subject +{ +public: + ConfigDatabase(void); + ~ConfigDatabase(void); + + enum ActiveFlag + { + ActiveFlag_Online = 1, + ActiveFlag_Away, + ActiveFlag_Dnd, + ActiveFlag_Na, + ActiveFlag_Occupied, + ActiveFlag_FreeForChat, + ActiveFlag_Invisible + }; + + struct act { + bool status; + bool message; + }; + + typedef std::map ActiveUsersMap; + + //-------------------------------------------------------------------------- + // Description : get/set the voice description + //-------------------------------------------------------------------------- + VoiceDesc getVoiceDesc() const { return m_voice_desc; } + void setVoiceDesc(const VoiceDesc &desc) { m_voice_desc = desc; } + + //-------------------------------------------------------------------------- + // Description : get/set the welcome message + //-------------------------------------------------------------------------- + const std::wstring & getWelcomeMessage() const { return m_welcome_msg; } + void setWelcomeMessage(const std::wstring &msg) { m_welcome_msg = msg; } + + //-------------------------------------------------------------------------- + // Description : get/set an status flags + //-------------------------------------------------------------------------- + bool getActiveFlag(ActiveFlag flag) const; + void setActiveFlag(ActiveFlag flag, bool state); + + //-------------------------------------------------------------------------- + // Description : get/set the user active flag + //-------------------------------------------------------------------------- + act getActiveUser(HANDLE user) const; + void setActiveUser(HANDLE user, act state); + ActiveUsersMap getActiveUsers() const { return m_active_users; } + + //-------------------------------------------------------------------------- + // Description : load/save the settings from the miranda database + //-------------------------------------------------------------------------- + void load(); + void save(); + + private: + //-------------------------------------------------------------------------- + // Description : For some reason this isn't implemented in miranda yet + // Just get a string from the db + // Parameters : szModule - the entrys' module + // szSetting - the entrys' setting + // def - default string if entry doesn't exist + //-------------------------------------------------------------------------- + static std::wstring DBGetContactSettingString(const char *szModule, + const char *szSetting, const WCHAR *def); + + VoiceDesc m_voice_desc; + unsigned int m_active_flags; + std::wstring m_welcome_msg; + //std::string m_welcome_msg; + ActiveUsersMap m_active_users; +}; + diff --git a/plugins/WinterSpeak/src/DialogConfigActive.cpp b/plugins/WinterSpeak/src/DialogConfigActive.cpp new file mode 100644 index 0000000000..8caea38e8b --- /dev/null +++ b/plugins/WinterSpeak/src/DialogConfigActive.cpp @@ -0,0 +1,376 @@ +#include "Common.h" +#include "DialogConfigActive.h" + +//------------------------------------------------------------------------------ +DialogConfigActive *DialogConfigActive::m_instance = 0; + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +DialogConfigActive::DialogConfigActive(ConfigDatabase &db) : m_db(db) +{ + m_instance = this; +} + +//------------------------------------------------------------------------------ +DialogConfigActive::~DialogConfigActive() +{ + m_instance = 0; +} + +//------------------------------------------------------------------------------ +int CALLBACK DialogConfigActive::process(HWND window, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (!m_instance) + { + return 1; + } + + switch (message) + { + case WM_INITDIALOG: + m_instance->load(window); + break; + + case WM_NOTIFY: + switch(((LPNMHDR)lparam)->idFrom) { + case IDC_ACTIVE_USERS: { + m_instance->notify(window, lparam); + + } break; + case 0: { + switch (reinterpret_cast(lparam)->code) + { + case PSN_APPLY: + m_instance->save(window); + break; + + case LVN_ITEMCHANGED: + m_instance->changed(window); + break; + } break; + } break; + } break; + case WM_COMMAND: + switch (LOWORD(wparam)) + { + case IDC_ACTIVE_OFFLINE: + case IDC_ACTIVE_ONLINE: + case IDC_ACTIVE_AWAY: + case IDC_ACTIVE_DND: + case IDC_ACTIVE_NA: + case IDC_ACTIVE_OCCUPIED: + case IDC_ACTIVE_FREEFORCHAT: + case IDC_ACTIVE_INVISIBLE: + m_instance->changed(window); + break; + + /*case IDC_ACTIVE_ALL: + m_instance->selectAllUsers(window, true); + break;*/ + + /*case IDC_ACTIVE_NONE: + m_instance->selectAllUsers(window, false); + break;*/ + + case IDC_ACTIVE_USERS: + m_instance->changed(window); + break; + } + break; + } + + return 0; +} + + + + + + + +//------------------------------------------------------------------------------ +// private: +//------------------------------------------------------------------------------ +void DialogConfigActive::notify(HWND hwndDlg, LPARAM lParam) { + switch (((LPNMHDR)lParam)->code) { + case CLN_NEWCONTACT: + case CLN_LISTREBUILT: + SetAllContactIcons( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), hwndDlg); + //fall through + case CLN_CONTACTMOVED: + SetListGroupIcons( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_ACTIVE_USERS, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + break; + case CLN_OPTIONSCHANGED: + + ResetListOptions( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS)); + break; + case CLN_CHECKCHANGED: + m_instance->changed(hwndDlg); + break; + case NM_CLICK: + { + NMCLISTCONTROL *nm = (NMCLISTCONTROL*)lParam; + if (nm->iColumn == -1) + break; + + DWORD hitFlags; + HANDLE hItem = (HANDLE)SendDlgItemMessage(hwndDlg, IDC_ACTIVE_USERS, CLM_HITTEST, (WPARAM)&hitFlags, MAKELPARAM(nm->pt.x, nm->pt.y)); + if (hItem == NULL || !(hitFlags & CLCHT_ONITEMEXTRA)) + break; + + if (nm->iColumn == 2) { // ignore all + for (int iImage = 0;iImage<2;iImage++) + SetIconsForColumn( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), hItem, hItemAll, iImage, iImage+3); + } + else if (nm->iColumn == 3) { // ignore none + for (int iImage = 0;iImage<2;iImage++) + SetIconsForColumn( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), hItem, hItemAll, iImage, 0); + } + else { + int iImage = SendDlgItemMessage(hwndDlg, IDC_ACTIVE_USERS, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(nm->iColumn, 0)); + if (iImage == 0) + iImage = nm->iColumn+3; + else if (iImage != EMPTY_EXTRA_ICON) + iImage = 0; + SetIconsForColumn( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), hItem, hItemAll, nm->iColumn, iImage); + } + SetListGroupIcons( GetDlgItem(hwndDlg, IDC_ACTIVE_USERS), (HANDLE)SendDlgItemMessage(hwndDlg, IDC_ACTIVE_USERS, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + m_instance->changed(hwndDlg); + } + break; + } +} + +void DialogConfigActive::load(HWND window) +{ + TranslateDialogDefault(window); + + // initialise the checkboxes + CheckDlgButton(window, IDC_ACTIVE_ONLINE, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Online)); + CheckDlgButton(window, IDC_ACTIVE_AWAY, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Away)); + CheckDlgButton(window, IDC_ACTIVE_DND, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Dnd)); + CheckDlgButton(window, IDC_ACTIVE_NA, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Na)); + CheckDlgButton(window, IDC_ACTIVE_OCCUPIED, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Occupied)); + CheckDlgButton(window, IDC_ACTIVE_FREEFORCHAT, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_FreeForChat)); + CheckDlgButton(window, IDC_ACTIVE_INVISIBLE, m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Invisible)); + + HWND listview = GetDlgItem(window, IDC_ACTIVE_USERS); + + HIMAGELIST hIml = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_COLOR32 | ILC_MASK, 3, 3); + ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_SMALLDOT); + ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_FILLEDBLOB); + ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_EMPTYBLOB); + ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_EVENT_MESSAGE); + ImageList_AddIcon_IconLibLoaded(hIml, SKINICON_OTHER_USERONLINE); + + SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_SETEXTRAIMAGELIST, 0, (LPARAM)hIml); + for (int i=0; i < SIZEOF(hIcons); i++) + hIcons[i] = ImageList_GetIcon(hIml, 1+i, ILD_NORMAL); + + SendDlgItemMessage(window, IDC_ALLICON, STM_SETICON, (WPARAM)hIcons[0], 0); + SendDlgItemMessage(window, IDC_NONEICON, STM_SETICON, (WPARAM)hIcons[1], 0); + SendDlgItemMessage(window, IDC_MSGICON, STM_SETICON, (WPARAM)hIcons[2], 0); + SendDlgItemMessage(window, IDC_ONLINEICON, STM_SETICON, (WPARAM)hIcons[3], 0); + + this->ResetListOptions(listview); + + SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_SETEXTRACOLUMNS, 4, 0); + { + CLCINFOITEM cii = {0}; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT; + cii.pszText = TranslateT("** All contacts **"); + hItemAll = (HANDLE)SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_ADDINFOITEM, 0, (LPARAM)&cii); + + cii.pszText = TranslateT("** Unknown contacts **"); + hItemUnknown = (HANDLE)SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_ADDINFOITEM, 0, (LPARAM)&cii); + ConfigDatabase::ActiveUsersMap active_users = m_db.getActiveUsers(); + this->InitialiseItem(listview, hItemUnknown, active_users[0].message, active_users[0].status); + } + this->SetAllContactIcons(listview, window); + this->SetListGroupIcons(GetDlgItem(window, IDC_ACTIVE_USERS), (HANDLE)SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_GETNEXTITEM, CLGN_ROOT, 0), hItemAll, NULL); + +} + +void DialogConfigActive::SetAllChildIcons(HWND hwndList, HANDLE hFirstItem, int iColumn, int iImage) +{ + HANDLE hItem; + + int 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) { + HANDLE 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) { + int iOldIcon = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn); + if (iOldIcon != EMPTY_EXTRA_ICON && iOldIcon != iImage) + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_NEXTCONTACT, (LPARAM)hItem); + } +} + +void DialogConfigActive::SetIconsForColumn(HWND hwndList, HANDLE hItem, HANDLE hItemAll, int iColumn, int iImage) { + switch ( SendMessage(hwndList, CLM_GETITEMTYPE, (WPARAM)hItem, 0)) { + case CLCIT_CONTACT: + { + int oldiImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, iColumn); + if (oldiImage != EMPTY_EXTRA_ICON && oldiImage != iImage) + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); + } + break; + case CLCIT_INFO: + if (hItem == hItemAll) + SetAllChildIcons(hwndList, hItem, iColumn, iImage); + else + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(iColumn, iImage)); //hItemUnknown + break; + + case CLCIT_GROUP: + hItem = (HANDLE)SendMessage(hwndList, CLM_GETNEXTITEM, CLGN_CHILD, (LPARAM)hItem); + if (hItem) + SetAllChildIcons(hwndList, hItem, iColumn, iImage); + } +} + +void DialogConfigActive::InitialiseItem(HWND hwndList, HANDLE hItem, bool message, bool status) { + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(0, (message)?0:3)); //Message + + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1, (status)?0:4)); //Online + + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(2, 1)); + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(3, 2)); +} + +void DialogConfigActive::SetAllContactIcons(HWND hwndList, HWND window) { + ConfigDatabase::ActiveUsersMap active_users = m_db.getActiveUsers(); + ConfigDatabase::ActiveUsersMap::const_iterator iter; + for (iter = active_users.begin(); iter != active_users.end(); ++iter) + { + HANDLE hContact = iter->first; + if(hContact == 0) { + + } else { + HANDLE hItem = (HANDLE)SendMessage(hwndList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem && SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(1, 0)) == EMPTY_EXTRA_ICON) { + this->InitialiseItem(hwndList, hItem, iter->second.message, iter->second.status); + } + } + } +} + +void DialogConfigActive::ResetListOptions(HWND listview) { + SendMessage(listview, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP)NULL); + SendMessage(listview, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(listview, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(listview, CLM_SETLEFTMARGIN, 2, 0); + SendMessage(listview, CLM_SETINDENT, 10, 0); + SendMessage(listview, CLM_SETHIDEEMPTYGROUPS, 1, 0); + + for (int i=0; i <= FONTID_MAX; i++) + SendMessage(listview, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); + + SetWindowLong(listview, GWL_STYLE, GetWindowLong(listview, GWL_STYLE) | CLS_SHOWHIDDEN); +} + +void DialogConfigActive::SetListGroupIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem, int *groupChildCount) { + int iconOn[2] = {1, 1}; + int childCount[2] = {0, 0}, i; + int iImage; + HANDLE hItem, hChildItem; + + int 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 != EMPTY_EXTRA_ICON) + 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) : EMPTY_EXTRA_ICON)); + if (groupChildCount) groupChildCount[i]+=childCount[i]; + } + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(2, 1)); + SendMessage(hwndList, CLM_SETEXTRAIMAGE, (WPARAM)hParentItem, MAKELPARAM(3, 2)); +} + +//------------------------------------------------------------------------------ +void DialogConfigActive::save(HWND window) +{ + // store the checkboxes + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Online, (IsDlgButtonChecked(window, IDC_ACTIVE_ONLINE) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Away, (IsDlgButtonChecked(window, IDC_ACTIVE_AWAY) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Dnd, (IsDlgButtonChecked(window, IDC_ACTIVE_DND) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Na, (IsDlgButtonChecked(window, IDC_ACTIVE_NA) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Occupied, (IsDlgButtonChecked(window, IDC_ACTIVE_OCCUPIED) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_FreeForChat, (IsDlgButtonChecked(window, IDC_ACTIVE_FREEFORCHAT) != 0)); + m_db.setActiveFlag(ConfigDatabase::ActiveFlag_Invisible, (IsDlgButtonChecked(window, IDC_ACTIVE_INVISIBLE) != 0)); + + for (HANDLE hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { + HANDLE hItem = (HANDLE)SendDlgItemMessage(window, IDC_ACTIVE_USERS, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if (hItem) + SaveItemMask(GetDlgItem(window, IDC_ACTIVE_USERS), hContact, hItem); + } + + SaveItemMask( GetDlgItem(window, IDC_ACTIVE_USERS), NULL, hItemUnknown); + + m_db.save(); +} + +void DialogConfigActive::SaveItemMask(HWND hwndList, HANDLE hContact, HANDLE hItem) { + ConfigDatabase::act mask; + mask.message = true; + mask.status = true; + for (int i=0; i < 2; i++) { + int iImage = SendMessage(hwndList, CLM_GETEXTRAIMAGE, (WPARAM)hItem, MAKELPARAM(i, 0)); + if (iImage && iImage != EMPTY_EXTRA_ICON) { + if(i == 1) { //Online + mask.status = false; + } + if(i == 0) { //message + mask.message = false; + } + } + } + m_db.setActiveUser(hContact, mask); +} + +//------------------------------------------------------------------------------ +void DialogConfigActive::selectAllUsers(HWND window, bool state) +{ + HWND listview = GetDlgItem(window, IDC_ACTIVE_USERS); + + for (int i = 0; i < ListView_GetItemCount(listview); ++i) + { + ListView_SetCheckState(listview, i, state); + } + + changed(window); +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/DialogConfigActive.h b/plugins/WinterSpeak/src/DialogConfigActive.h new file mode 100644 index 0000000000..8dbbbd43a9 --- /dev/null +++ b/plugins/WinterSpeak/src/DialogConfigActive.h @@ -0,0 +1,49 @@ +#pragma once +#include "mirandadialog.h" + +class DialogConfigActive : public MirandaDialog +{ + public: + //-------------------------------------------------------------------------- + // Description : Initialise + // Parameters : db - reference to the database to initalise and save + // control to and from + //-------------------------------------------------------------------------- + DialogConfigActive(ConfigDatabase &db); + virtual ~DialogConfigActive(); + + //-------------------------------------------------------------------------- + // Description : process a dialog message + // Return : 0 - process ok + // 1 - error + //-------------------------------------------------------------------------- + static INT_PTR CALLBACK process(HWND window, UINT message, WPARAM wparam, LPARAM lparam); + + private: + //-------------------------------------------------------------------------- + // Description : load/save setting to the miranda database + //-------------------------------------------------------------------------- + void load(HWND window); + void save(HWND window); + void notify(HWND window, LPARAM lparam); + + //-------------------------------------------------------------------------- + // Description : select/unselect all the active status checkboxes + // Parameters : state - the state to apply to the checkboxes + //-------------------------------------------------------------------------- + void selectAllUsers(HWND window, bool state); + void ResetListOptions(HWND listview); + void InitialiseItem(HWND hwndList, HANDLE hItem, bool message, bool status); + void SetAllContactIcons(HWND listview, HWND window); + void SetIconsForColumn(HWND hwndList, HANDLE hItem, HANDLE hItemAll, int iColumn, int iImage); + void SetAllChildIcons(HWND hwndList, HANDLE hFirstItem, int iColumn, int iImage); + void SetListGroupIcons(HWND hwndList, HANDLE hFirstItem, HANDLE hParentItem, int *groupChildCount); + void SaveItemMask(HWND hwndList, HANDLE hContact, HANDLE hItem); + + static DialogConfigActive *m_instance; + ConfigDatabase &m_db; + HICON hIcons[4]; + HANDLE hItemUnknown; + HANDLE hItemAll; +}; + diff --git a/plugins/WinterSpeak/src/DialogConfigEngine.cpp b/plugins/WinterSpeak/src/DialogConfigEngine.cpp new file mode 100644 index 0000000000..2375dedcc7 --- /dev/null +++ b/plugins/WinterSpeak/src/DialogConfigEngine.cpp @@ -0,0 +1,229 @@ +#include "Common.h" +#include "DialogConfigEngine.h" + +DialogConfigEngine *DialogConfigEngine::m_instance = 0; + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +DialogConfigEngine::DialogConfigEngine(ConfigDatabase &db) : m_db(db), m_test_tts(0) +{ + m_instance = this; +} + +//------------------------------------------------------------------------------ +DialogConfigEngine::~DialogConfigEngine() +{ + m_instance = 0; +} + +//------------------------------------------------------------------------------ +INT_PTR CALLBACK DialogConfigEngine::process(HWND window, UINT message, WPARAM wparam, LPARAM lparam) +{ + if (!m_instance) + { + return 1; + } + + switch (message) + { + case WM_INITDIALOG: + m_instance->load(window); + break; + + case WM_NOTIFY: + if (PSN_APPLY == reinterpret_cast(lparam)->code) + { + m_instance->save(window); + m_instance->m_db.save(); + } + break; + + case WM_HSCROLL: + m_instance->changed(window); + break; + + case WM_COMMAND: + m_instance->command(window, wparam); + break; + } + + return 0; +} + +//------------------------------------------------------------------------------ +// private: +//------------------------------------------------------------------------------ +void DialogConfigEngine::command(HWND window, int control) +{ + switch (LOWORD(control)) + { + case IDC_WELCOME_MSG: + if (EN_CHANGE == HIWORD(control)) + { + changed(window); + } + break; + + case IDC_SELECT_VOICE: + if (CBN_SELCHANGE == HIWORD(control)) + { + changed(window); + } + break; + + case IDC_SELECT_ENGINE: + if (CBN_SELCHANGE == HIWORD(control)) + { + updateVoices(window); + changed(window); + } + break; + + case IDC_CONFIG_LEXICON: + if (createTts(window)) + { + if (!m_test_tts->lexiconDialog(window)) + { + MessageBox(window, L"Lexicon for this engine is not supported", L"Speak", MB_OK | MB_ICONEXCLAMATION); + } + } + break; + + case IDC_BUTTON_TEST: + if (createTts(window)) + { + m_test_tts->say(TranslateW(L"testing testing 1 2 3")); + } + break; + } +} + +//------------------------------------------------------------------------------ +void DialogConfigEngine::load(HWND window) +{ + TranslateDialogDefault(window); + + // add the available engines to the combo box + SpeechInterface si; + std::vector engines = si.getAvailableEngines(); + for (unsigned int i = 0; i < engines.size(); ++i) + { + SendDlgItemMessage(window, IDC_SELECT_ENGINE, CB_ADDSTRING, 0, (long)(engines[i].c_str())); + } + + VoiceDesc desc = m_db.getVoiceDesc(); + + // initialise the sliders + SendDlgItemMessage(window, IDC_SLIDER_VOLUME, TBM_SETPOS, TRUE, desc.volume); + SendDlgItemMessage(window, IDC_SLIDER_PITCH, TBM_SETPOS, TRUE, desc.pitch); + SendDlgItemMessage(window, IDC_SLIDER_RATE, TBM_SETPOS, TRUE, desc.rate); + + // select the speech engine + SendDlgItemMessage(window, IDC_SELECT_ENGINE, CB_SELECTSTRING, 0, reinterpret_cast(desc.engine.c_str())); + + // initialise the welcome message box + SetDlgItemText(window, IDC_WELCOME_MSG, m_db.getWelcomeMessage().c_str()); + + updateVoices(window); +} + +//------------------------------------------------------------------------------ +void DialogConfigEngine::save(HWND window) +{ + VoiceDesc desc; + getVoiceDesc(window, desc); + m_db.setVoiceDesc(desc); + + // store the welcome message + WCHAR *text = Hlp_GetDlgItemText(window, IDC_WELCOME_MSG); + m_db.setWelcomeMessage(text); +} + +//------------------------------------------------------------------------------ +void DialogConfigEngine::updateVoices(HWND window) +{ + SpeechInterface si; + m_test_tts = std::auto_ptr(si.createTts(getEngine(window))); + + if (!m_test_tts.get()) + { + return; + } + + // add the voices onto the list + std::vector voices = m_test_tts->getVoices(); + + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_RESETCONTENT, 0, 0); + for (unsigned int i = 0; i < voices.size(); ++i) + { + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_ADDSTRING, 0, + (long)voices[i].c_str()); + } + + // get the voice saved in the database + std::wstring voice = m_db.getVoiceDesc().voice; + + if (FAILED(SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_FINDSTRINGEXACT, 0, (long)voice.c_str()))) + { + // select the first one + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_SETCURSEL , 0, 0); + } + else + { + // select the saved voice + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_SELECTSTRING, 0, (long)voice.c_str()); + } +} + +//------------------------------------------------------------------------------ +void DialogConfigEngine::getVoiceDesc(HWND window, VoiceDesc &desc) +{ + // get the engine + WCHAR *text = Hlp_GetDlgItemText(window, IDC_SELECT_ENGINE); + desc.engine = text; + + // get the voice + WCHAR *voice = Hlp_GetDlgItemText(window, IDC_SELECT_VOICE); + desc.voice = voice; + /*std::auto_ptr voice(new char[50]); + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_GETLBTEXT, + SendDlgItemMessage(window, IDC_SELECT_VOICE, CB_GETCURSEL, 0, 0), + reinterpret_cast(voice.get())); + desc.voice = voice.get();*/ + + // get the voice setting sliders + desc.volume = SendDlgItemMessage(window, IDC_SLIDER_VOLUME, TBM_GETPOS, 0, 0); + desc.pitch = SendDlgItemMessage(window, IDC_SLIDER_PITCH, TBM_GETPOS, 0, 0); + desc.rate = SendDlgItemMessage(window, IDC_SLIDER_RATE, TBM_GETPOS, 0, 0); +} + +//------------------------------------------------------------------------------ +std::wstring DialogConfigEngine::getEngine(HWND window) +{ + WCHAR *text = Hlp_GetDlgItemText(window, IDC_SELECT_ENGINE); + /*char text[100]; + GetDlgItemText(window, IDC_SELECT_ENGINE, mir_a2u(text), sizeof(text));*/ + + return text; +} + +//------------------------------------------------------------------------------ +bool DialogConfigEngine::createTts(HWND window) +{ + VoiceDesc desc; + getVoiceDesc(window, desc); + + SpeechInterface si; + m_test_tts = std::auto_ptr(si.createTts(desc.engine)); + + if (!m_test_tts.get()) + { + return false; + } + + si.configureTts(m_test_tts.get(), desc); + return true; +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/DialogConfigEngine.h b/plugins/WinterSpeak/src/DialogConfigEngine.h new file mode 100644 index 0000000000..b72037288f --- /dev/null +++ b/plugins/WinterSpeak/src/DialogConfigEngine.h @@ -0,0 +1,41 @@ +#pragma once + +#include "MirandaDialog.h" +#include "ConfigDatabase.h" + +class TextToSpeech; + +class DialogConfigEngine : public MirandaDialog +{ + public: + DialogConfigEngine(ConfigDatabase &db); + virtual ~DialogConfigEngine(); + + //-------------------------------------------------------------------------- + // Description : process a dialog message + // Return : 0 - process ok + // 1 - error + //-------------------------------------------------------------------------- + static INT_PTR CALLBACK process(HWND window, UINT message, WPARAM wparam, LPARAM lparam); + + private: + void command(HWND window, int control); + + //-------------------------------------------------------------------------- + // Description : load/save setting to the miranda database + //-------------------------------------------------------------------------- + void load(HWND window); + void save(HWND window); + + //-------------------------------------------------------------------------- + // Description : update the voices combo box + //-------------------------------------------------------------------------- + void updateVoices(HWND window); + void getVoiceDesc(HWND window, VoiceDesc &desc); + std::wstring getEngine(HWND window); + bool createTts(HWND window); + + static DialogConfigEngine *m_instance; + ConfigDatabase &m_db; + std::auto_ptr m_test_tts; +}; diff --git a/plugins/WinterSpeak/src/EventInformation.cpp b/plugins/WinterSpeak/src/EventInformation.cpp new file mode 100644 index 0000000000..69437a71ea --- /dev/null +++ b/plugins/WinterSpeak/src/EventInformation.cpp @@ -0,0 +1,85 @@ +#include "Common.h" +#include "EventInformation.h" + + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +EventInformation::EventInformation() : m_event_strings(), m_event_info() +{ + // insert the event strings into a map for easy access + m_event_strings[EVENTTYPE_MESSAGE] = TranslateW(L"incoming message from %u"); + m_event_strings[EVENTTYPE_URL] = TranslateW(L"incoming U R L from %u"); + m_event_strings[EVENTTYPE_ADDED] = TranslateW(L"you have been added to %u's contact list"); + m_event_strings[EVENTTYPE_AUTHREQUEST] = TranslateW(L"%u requests your authorization"); + m_event_strings[EVENTTYPE_FILE] = TranslateW(L"there is an incoming file from %u"); + + ZeroMemory(&m_event_info, sizeof(m_event_info)); +} + +//------------------------------------------------------------------------------ +EventInformation::~EventInformation() +{ +} + +//------------------------------------------------------------------------------ +bool EventInformation::isValidEvent(HANDLE event) +{ + // clean up the old event + if (m_event_info.pBlob) + { + delete m_event_info.pBlob; + } + ZeroMemory(&m_event_info, sizeof(m_event_info)); + + // find out and assign the space we need for the new event + m_event_info.cbSize = sizeof(m_event_info); + m_event_info.cbBlob = db_event_getBlobSize(event);// CallService(MS_DB_EVENT_GETBLOBSIZE, reinterpret_cast(event), 0); + + if (-1 == m_event_info.cbBlob) + { + return false; + } + m_event_info.pBlob = new unsigned char[m_event_info.cbBlob]; + + // get the event info + db_event_get(event, &m_event_info); + //CallService(MS_DB_EVENT_GET, reinterpret_cast(event), reinterpret_cast(&m_event_info)); + + // if the event has already been read or was sent by me then exit + if (m_event_info.flags & (DBEF_SENT | DBEF_READ)) + { + return false; + } + + // if the event string doesn't exist in our list then exit + if (m_event_strings.find(m_event_info.eventType) == m_event_strings.end()) + { + return false; + } + + // event was good + return true; +} + +//------------------------------------------------------------------------------ +std::wstring EventInformation::getMessage() +{ + const std::wstring intro = TranslateW(L"%u says"); + + return intro + L" " + mir_a2t_cp((char*)m_event_info.pBlob,CP_UTF8); +} + +//------------------------------------------------------------------------------ +unsigned int EventInformation::getMessageSize() +{ + return std::wstring((WCHAR *)m_event_info.pBlob).size(); +} + +//------------------------------------------------------------------------------ +std::wstring EventInformation::eventString() +{ + return m_event_strings[m_event_info.eventType]; +} + +//============================================================================== \ No newline at end of file diff --git a/plugins/WinterSpeak/src/EventInformation.h b/plugins/WinterSpeak/src/EventInformation.h new file mode 100644 index 0000000000..2715dee7f9 --- /dev/null +++ b/plugins/WinterSpeak/src/EventInformation.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +class EventInformation +{ + public: + EventInformation(); + ~EventInformation(); + + //-------------------------------------------------------------------------- + // Description : is the event valid? + // Return : true = the event is valid + //-------------------------------------------------------------------------- + bool isValidEvent(HANDLE event); + + //-------------------------------------------------------------------------- + // Description : get the last event received + // Return : the last event or 0 if none yet received + //-------------------------------------------------------------------------- + unsigned short getLastEvent() { return m_event_info.eventType; } + + //-------------------------------------------------------------------------- + // Description : was the last event a messsage event? + // Return : true - yes it was + // false - no it wasn't + //-------------------------------------------------------------------------- +// bool isMessageEvent() +// { return (m_event_info.eventType == EVENTTYPE_MESSAGE); } + + //-------------------------------------------------------------------------- + // Description : get the message from the last event + // Return : the last message + //-------------------------------------------------------------------------- + std::wstring getMessage(); + + //-------------------------------------------------------------------------- + // Description : get the size of the message from the last event + // Return : the size of the message + //-------------------------------------------------------------------------- + unsigned int getMessageSize(); + + //-------------------------------------------------------------------------- + // Description : get the event string + //-------------------------------------------------------------------------- + std::wstring eventString(); + + private: + std::map m_event_strings; + + DBEVENTINFO m_event_info; +}; diff --git a/plugins/WinterSpeak/src/MirandaDialog.cpp b/plugins/WinterSpeak/src/MirandaDialog.cpp new file mode 100644 index 0000000000..fad87285f6 --- /dev/null +++ b/plugins/WinterSpeak/src/MirandaDialog.cpp @@ -0,0 +1,38 @@ +#include "Common.h" +#include "MirandaDialog.h" + + +MirandaDialog::MirandaDialog(void) +{ +} + + +MirandaDialog::~MirandaDialog(void) +{ +} + +void MirandaDialog::changed(HWND window) +{ + SendMessage(GetParent(window), PSM_CHANGED, 0, 0); +} + +WCHAR *MirandaDialog::Hlp_GetDlgItemText(HWND hwndDlg, int nIDDlgItem) { + + int len = SendDlgItemMessage(hwndDlg, nIDDlgItem, WM_GETTEXTLENGTH, 0, 0); + if (len < 0) + return NULL; + + WCHAR *res = (WCHAR*)mir_alloc((len+1)*sizeof(WCHAR)); + ZeroMemory(res, (len+1)*sizeof(WCHAR)); + GetDlgItemText(hwndDlg, nIDDlgItem, res, len+1); + + return res; +} + +int MirandaDialog::ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId) +{ + HICON hIcon = LoadSkinnedIcon(iconId); + int res = ImageList_AddIcon(hIml, hIcon); + Skin_ReleaseIcon(hIcon); + return res; +} \ No newline at end of file diff --git a/plugins/WinterSpeak/src/MirandaDialog.h b/plugins/WinterSpeak/src/MirandaDialog.h new file mode 100644 index 0000000000..bd9e2c91a0 --- /dev/null +++ b/plugins/WinterSpeak/src/MirandaDialog.h @@ -0,0 +1,12 @@ +#pragma once +class MirandaDialog +{ +public: + MirandaDialog(void); + virtual ~MirandaDialog(void); + static WCHAR *MirandaDialog::Hlp_GetDlgItemText(HWND hwndDlg, int nIDDlgItem); + static int ImageList_AddIcon_IconLibLoaded(HIMAGELIST hIml, int iconId); +protected: + void changed(HWND window); +}; + diff --git a/plugins/WinterSpeak/src/Observer.cpp b/plugins/WinterSpeak/src/Observer.cpp new file mode 100644 index 0000000000..b2bc38be5c --- /dev/null +++ b/plugins/WinterSpeak/src/Observer.cpp @@ -0,0 +1,6 @@ +#include "Common.h" +#include "Observer.h" + +Observer::~Observer(void) +{ +} diff --git a/plugins/WinterSpeak/src/Observer.h b/plugins/WinterSpeak/src/Observer.h new file mode 100644 index 0000000000..ec52b2c4d3 --- /dev/null +++ b/plugins/WinterSpeak/src/Observer.h @@ -0,0 +1,17 @@ +#pragma once + + +class Subject; + +class Observer +{ + public: + virtual ~Observer(); + + //-------------------------------------------------------------------------- + // Description : Called by a subject that this observer is observing + // to signify a change in state + // Parameters : subject - the subject that changed + //-------------------------------------------------------------------------- + virtual void update(Subject &subject) = 0; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/ProtocolInformation.cpp b/plugins/WinterSpeak/src/ProtocolInformation.cpp new file mode 100644 index 0000000000..d04f485a9b --- /dev/null +++ b/plugins/WinterSpeak/src/ProtocolInformation.cpp @@ -0,0 +1,78 @@ +#include "Common.h" +#include "ProtocolInformation.h" + + +//------------------------------------------------------------------------------ +ProtocolInformation *ProtocolInformation::m_instance = 0; + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +ProtocolInformation::ProtocolInformation() : m_protocol_timeout() +{ + m_instance = this; +} + +//------------------------------------------------------------------------------ +ProtocolInformation::~ProtocolInformation() +{ + m_instance = 0; + + // kill all the timers + for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); + iter != m_protocol_timeout.end(); + ++iter) + { + KillTimer(NULL, (*iter).second); + } +} + +//------------------------------------------------------------------------------ +void ProtocolInformation::disable(const char *protocol) +{ + if (NULL == protocol) + { + return; + } + + const unsigned int TIMEOUT = 10000; + + unsigned int t = SetTimer(NULL, NULL, TIMEOUT, ProtocolInformation::timeout); + m_protocol_timeout.push_back(std::make_pair(protocol, t)); +} + +//------------------------------------------------------------------------------ +bool ProtocolInformation::isDisabled(const char *protocol) const +{ + if (NULL == protocol) + { + return false; + } + + // iterate through the list and see if the protocol has a timer callback + for (ProtocolTimeoutQueue::const_iterator iter = m_protocol_timeout.begin(); + iter != m_protocol_timeout.end(); + ++iter) + { + if (0 == (*iter).first.compare(protocol)) + { + return true; + } + } + + return false; +} + +//------------------------------------------------------------------------------ +// private: +//------------------------------------------------------------------------------ +void CALLBACK ProtocolInformation::timeout(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) +{ + ProtocolTimeout pt = m_instance->m_protocol_timeout.front(); + + KillTimer(NULL, pt.second); + + m_instance->m_protocol_timeout.pop_front(); +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/ProtocolInformation.h b/plugins/WinterSpeak/src/ProtocolInformation.h new file mode 100644 index 0000000000..dcfb6eca18 --- /dev/null +++ b/plugins/WinterSpeak/src/ProtocolInformation.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +class ProtocolInformation +{ + public: + ProtocolInformation(); + ~ProtocolInformation(); + + void disable(const char *protocol); + bool isDisabled(const char *protocol) const; + + private: + typedef std::pair ProtocolTimeout; + typedef std::deque ProtocolTimeoutQueue; + + static void CALLBACK timeout(HWND hwnd, UINT uMsg, UINT idEvent, + DWORD dwTime); + + static ProtocolInformation *m_instance; + + ProtocolTimeoutQueue m_protocol_timeout; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeakAnnounce.cpp b/plugins/WinterSpeak/src/SpeakAnnounce.cpp new file mode 100644 index 0000000000..c95550b4af --- /dev/null +++ b/plugins/WinterSpeak/src/SpeakAnnounce.cpp @@ -0,0 +1,206 @@ +#include "Common.h" +#include "SpeakAnnounce.h" + + +SpeakAnnounce::SpeakAnnounce(HINSTANCE instance) : m_instance(instance), m_db(), m_dialog(m_db), m_user_info(), m_event_info(), m_protocol_info() +{ +} + +//------------------------------------------------------------------------------ +SpeakAnnounce::~SpeakAnnounce() +{ +} + +//------------------------------------------------------------------------------ +void SpeakAnnounce::statusChange(DBCONTACTWRITESETTING *write_setting, HANDLE user) +{ + const std::string STATUS = "Status"; + + // if the user is myself (NULL) then return + // if it's not a status change then return + // check and update the user's status, if status didn't change the return + if ((NULL == user) + || (STATUS != write_setting->szSetting) + || (!m_user_info.updateStatus(user, write_setting->value.wVal))) + { + return; + } + + // check if we just connected, and want to suppress status changes + if (!m_db.getStatusFlag(AnnounceDatabase::StatusFlag_SuppressConnect) + && m_protocol_info.isDisabled( + (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)user, 0))) + { + return; + } + + bool speak = false; + + switch (write_setting->value.wVal) + { + case ID_STATUS_OFFLINE: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Offline); + break; + case ID_STATUS_ONLINE: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Online); + break; + case ID_STATUS_AWAY: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Away); + break; + case ID_STATUS_DND: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Dnd); + break; + case ID_STATUS_NA: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Na); + break; + case ID_STATUS_OCCUPIED: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Occupied); + break; + case ID_STATUS_FREECHAT: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_FreeForChat); + break; + case ID_STATUS_INVISIBLE: + speak = m_db.getStatusFlag(AnnounceDatabase::StatusFlag_Invisible); + break; + } + + if (!speak) + { + return; + } + + // translate, insert name then speak + std::wstring status_str = TranslateW(m_user_info.statusString(user).c_str()); + m_user_info.insertName(status_str, user); + status(status_str, user); +} + +//------------------------------------------------------------------------------ +void SpeakAnnounce::incomingEvent(HANDLE user, HANDLE event) +{ + if (m_event_info.isValidEvent(event)) + { + bool speak = false; + switch (m_event_info.getLastEvent()) + { + case EVENTTYPE_MESSAGE: + speak = m_db.getEventFlag(AnnounceDatabase::EventFlag_Message); + break; + + case EVENTTYPE_URL: + speak = m_db.getEventFlag(AnnounceDatabase::EventFlag_Url); + break; + + case EVENTTYPE_ADDED: + speak = m_db.getEventFlag(AnnounceDatabase::EventFlag_Added); + break; + + case EVENTTYPE_AUTHREQUEST: + speak = m_db.getEventFlag(AnnounceDatabase::EventFlag_AuthRequest); + break; + + case EVENTTYPE_FILE: + speak = m_db.getEventFlag(AnnounceDatabase::EventFlag_File); + break; + + } + + if (!speak) + { + return; + } + std::wstring event_str = L""; + + if (EVENTTYPE_MESSAGE == m_event_info.getLastEvent()) + { + if (!readMessage(user)) + { + return; // message dialog is open so just leave without saying anything + } + if ((m_db.getEventFlag(AnnounceDatabase::EventFlag_ReadMsgLength)) && (m_event_info.getMessageSize() <= m_db.getMaxMsgSize())) + { + event_str = m_event_info.getMessage(); // conditions met to read the message + } + else + { + event_str = m_event_info.eventString(); + } + } + else + { + event_str = m_event_info.eventString(); + } + m_user_info.insertName(event_str, user); // translate the string, insert the name, then speak it + message(event_str, user); + } +} + +//------------------------------------------------------------------------------ +void SpeakAnnounce::protocolAck(ACKDATA *ack) +{ + if (ACKTYPE_STATUS != ack->type) + { + return; + } + + if (ID_STATUS_CONNECTING != (int)ack->hProcess) + { + return; + } + + m_protocol_info.disable((char *)ack->szModule); +} + +//------------------------------------------------------------------------------ +void SpeakAnnounce::message(const std::wstring &sentence, HANDLE user) +{ + CallService(ME_SPEAK_MESSAGE, reinterpret_cast(user), reinterpret_cast(sentence.c_str())); +} +void SpeakAnnounce::status(const std::wstring &sentence, HANDLE user) +{ + CallService(ME_SPEAK_STATUS, reinterpret_cast(user), reinterpret_cast(sentence.c_str())); +} + +//------------------------------------------------------------------------------ +bool SpeakAnnounce::readMessage(HANDLE contact) +{ + std::wstring title = m_user_info.nameString(contact) + L" (" + m_user_info.statusModeString(contact) + L"): "; + + HWND window = NULL; + + window = FindWindow(L"#32770", (title + TranslateW(L"Message Session")).c_str()); + if (window) + { + // check if we dont want to read message if dialog is open + if (m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogOpen)) + { + return false; + } + + // check if we dont want to read message if dialog if focused + if ((window == GetForegroundWindow()) && m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogFocused)) + { + return false; + } + } + + window = FindWindow(L"#32770", (title + TranslateW(L"Message Received")).c_str()); + if (window) + { + // check if we dont want to read message if dialog is open + if (m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogOpen)) + { + return false; + } + + // check if we dont want to read message if dialog if focused + if ((window == GetForegroundWindow()) && m_db.getEventFlag(AnnounceDatabase::EventFlag_DialogFocused)) + { + return false; + } + } + + return true; +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/SpeakAnnounce.h b/plugins/WinterSpeak/src/SpeakAnnounce.h new file mode 100644 index 0000000000..ff681e6fdb --- /dev/null +++ b/plugins/WinterSpeak/src/SpeakAnnounce.h @@ -0,0 +1,54 @@ +#pragma once + +#include "Common.h" +#include + +class SpeakAnnounce +{ + public: + SpeakAnnounce(HINSTANCE instance); + ~SpeakAnnounce(); + + //-------------------------------------------------------------------------- + // Description : handle a status change + //-------------------------------------------------------------------------- + void statusChange(DBCONTACTWRITESETTING *write_setting, HANDLE user); + + //-------------------------------------------------------------------------- + // Description : handle an event + //-------------------------------------------------------------------------- + void incomingEvent(HANDLE user, HANDLE event); + + //-------------------------------------------------------------------------- + // Description : handle a protocol state change + //-------------------------------------------------------------------------- + void protocolAck(ACKDATA *ack); + + //-------------------------------------------------------------------------- + // Description : speak a sentence + // Parameters : sentence - the sentence to speak + // user - the user who is speaking, or NULL for no user + // Returns : true - speak successful + // false - speak failed + //-------------------------------------------------------------------------- + void message(const std::wstring &sentence, HANDLE user); + void status(const std::wstring &sentence, HANDLE user); + + private: + //-------------------------------------------------------------------------- + // Description : check if the users message window is open and focused + // Parameters : contact - the user to check for + // Returns : true = message window is open + // false = message window not open + //-------------------------------------------------------------------------- + bool readMessage(HANDLE contact); + + HINSTANCE m_instance; + + AnnounceDatabase m_db; + AnnounceDialog m_dialog; + UserInformation m_user_info; + EventInformation m_event_info; + ProtocolInformation m_protocol_info; +}; + diff --git a/plugins/WinterSpeak/src/SpeakConfig.cpp b/plugins/WinterSpeak/src/SpeakConfig.cpp new file mode 100644 index 0000000000..40c9d48dbe --- /dev/null +++ b/plugins/WinterSpeak/src/SpeakConfig.cpp @@ -0,0 +1,107 @@ +#include "Common.h" +#include "SpeakConfig.h" + + +SpeakConfig::SpeakConfig(HINSTANCE instance) : m_instance(instance), m_db(), m_tts(0), m_dialog_engine(m_db), m_dialog_active(m_db) +{ + // create and configure the tts + SpeechInterface si; + VoiceDesc desc = m_db.getVoiceDesc(); + m_tts = std::auto_ptr(si.createTts(desc.engine)); + si.configureTts(m_tts.get(), desc); + + // observer the database for changes + m_db.attach(*this); + + message(m_db.getWelcomeMessage()); +} + +//------------------------------------------------------------------------------ +SpeakConfig::~SpeakConfig() +{ +} + +//------------------------------------------------------------------------------ +void SpeakConfig::update(Subject &subject) +{ + ConfigDatabase &db = static_cast(subject); + + SpeechInterface si; + VoiceDesc desc = db.getVoiceDesc(); + m_tts = std::auto_ptr(si.createTts(desc.engine)); + si.configureTts(m_tts.get(), desc); +} + +//------------------------------------------------------------------------------ +bool SpeakConfig::status(const std::wstring &sentence, HANDLE user) { + return say(sentence, user, false); +} +bool SpeakConfig::message(const std::wstring &sentence, HANDLE user) { + return say(sentence, user, true); +} +bool SpeakConfig::say(const std::wstring &sentence, HANDLE user, bool message) +{ + if (!m_tts.get()){ + return false; + } + + bool active = true; + + if (NULL != user) + { + // get the status of the protocol of this user + const char *protocol = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)user, 0); + + switch (CallProtoService(protocol, PS_GETSTATUS, 0, 0)) + { + case ID_STATUS_ONLINE: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Online); + break; + case ID_STATUS_AWAY: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Away); + break; + case ID_STATUS_DND: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Dnd); + break; + case ID_STATUS_NA: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Na); + break; + case ID_STATUS_OCCUPIED: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Occupied); + break; + case ID_STATUS_FREECHAT: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_FreeForChat); + break; + case ID_STATUS_INVISIBLE: + active = m_db.getActiveFlag(ConfigDatabase::ActiveFlag_Invisible); + break; + case ID_STATUS_OFFLINE: + // if we are offline for this protocol, then don't speak the + // sentence this is so we don't announce users offline status if + // we are disconnected. + active = false; + break; + default: + active = false; + break; + } + + // if its a user say, then check the users status + if (active) + { + if(message) { + active = m_db.getActiveUser(user).message; + } else { + active = m_db.getActiveUser(user).status; + } + } + } + + if (!active) + { + return false; + } + + bool ret = m_tts->say(sentence); + return ret; +} diff --git a/plugins/WinterSpeak/src/SpeakConfig.h b/plugins/WinterSpeak/src/SpeakConfig.h new file mode 100644 index 0000000000..e1a4cb421a --- /dev/null +++ b/plugins/WinterSpeak/src/SpeakConfig.h @@ -0,0 +1,41 @@ +#pragma once + +#include "Common.h" +#include "ConfigDatabase.h" +#include "TextToSpeech.h" + +class TextToSpeech; + +class SpeakConfig : public Observer +{ + public: + SpeakConfig(HINSTANCE instance); + virtual ~SpeakConfig(); + + //-------------------------------------------------------------------------- + // Description : Called by a subject that this observer is observing + // to signify a change in state + // Parameters : subject - the subject that changed + //-------------------------------------------------------------------------- + virtual void update(Subject &subject); + + //-------------------------------------------------------------------------- + // Description : speak a sentence + // Parameters : sentence - the sentence to speak + // user - the user to associate the say with + // NULL = ignore user + // Returns : true - speak successful + // false - speak failed + //-------------------------------------------------------------------------- + bool status(const std::wstring &sentence, HANDLE user = NULL); + bool message(const std::wstring &sentence, HANDLE user = NULL); + bool say(const std::wstring &sentence, HANDLE user, bool message); + + private: + HINSTANCE m_instance; + + ConfigDatabase m_db; + std::auto_ptr m_tts; + DialogConfigEngine m_dialog_engine; + DialogConfigActive m_dialog_active; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechApi51.cpp b/plugins/WinterSpeak/src/SpeechApi51.cpp new file mode 100644 index 0000000000..194a867172 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi51.cpp @@ -0,0 +1,253 @@ +#include "Common.h" +#include "SpeechApi51.h" +#include "SpeechApi51Lexicon.h" + +#include +#include + +#include +#include + +namespace +{ + +//------------------------------------------------------------------------------ +// Description : implement callback +//------------------------------------------------------------------------------ +/*class Sapi51Callback : public ISpNotifyCallback +{ + public: + Sapi51Callback(); + + virtual STDMETHODIMP NotifyCallback(WPARAM wParam, LPARAM lParam) + { + + return S_OK; + } +};*/ + +} + +//------------------------------------------------------------------------------ +SpeechApi51::SpeechApi51() : m_sapi(0), m_state(TextToSpeech::State_Unloaded), m_voice(L""), m_volume(50), m_pitch(50), m_rate(50) +{ +} + +//------------------------------------------------------------------------------ +SpeechApi51::~SpeechApi51() +{ + unload(); + + CoUninitialize(); +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::isAvailable() +{ + CoInitialize(NULL); + + ISpVoice *sapi; + bool ret = true; + + if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, reinterpret_cast(&sapi)))) + { + ret = false; + } + else + { + sapi->Release(); + } + + return ret; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::load() +{ + if (isLoaded()) + { + return true; + } + + CoInitialize(NULL); + + if (FAILED(CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, reinterpret_cast(&m_sapi)))) + { + return false; + } + + m_state = TextToSpeech::State_Loaded; + + // adjust the volume and rate settings + setVoice(m_voice); + setVolume(m_volume); + setRate(m_rate); + + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::unload() +{ + if (isLoaded()) + { + m_sapi->Release(); + m_sapi = 0; + } + + m_state = TextToSpeech::State_Unloaded; + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::isLoaded() const +{ + return (TextToSpeech::State_Loaded == m_state); +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::say(const std::wstring &sentence) +{ + if (!isLoaded()) + { + return false; + } + + // prepend the pitch setting + std::wstringstream output; + output << " " << sentence; + + const std::wstring& wstr = output.str(); // extends lifetime of temporary + const LPCWSTR p = wstr.c_str(); + //std::auto_ptr sapi_sentence(new wchar_t[output.str().size() + 1]); + //mbstowcs(sapi_sentence.get(), output.str().c_str(), output.str().size() + 1); + + // speak the sentence + if (FAILED(m_sapi->Speak(p, SPF_IS_XML | SPF_ASYNC, NULL))) + { + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::setVolume(int volume) +{ + m_volume = volume; + + if (isLoaded() && FAILED(m_sapi->SetVolume(volume))) + { + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::setPitch(int pitch) +{ + m_pitch = (pitch / 5) - 10; + + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::setRate(int rate) +{ + m_rate = rate; + + // convert it to the range -10 to 10 + if (isLoaded() && FAILED(m_sapi->SetRate((rate / 5.0) - 10))) + { + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +bool SpeechApi51::setVoice(const std::wstring &voice) +{ + m_voice = voice; + + if (!isLoaded()) + { + return true; + } + + // get a voice enumerator + CComPtr cpEnum; + if (FAILED(SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum))) + { + return false; + } + + // iterate through the list till we find a matching voice + ISpObjectToken *voice_token; + while (S_OK == cpEnum->Next(1, &voice_token, NULL)) + { + CSpDynamicString voice_str; + + if (SUCCEEDED(SpGetDescription(voice_token, &voice_str)) + && (voice == voice_str.Copy())) + { + m_sapi->SetVoice(voice_token); + return true; + } + } + + return false; +} + +//------------------------------------------------------------------------------ +std::vector SpeechApi51::getVoices() const +{ + std::vector ret; + + CoInitialize(NULL); + + // get a voice enumerator + CComPtr cpEnum; + if (S_OK != SpEnumTokens(SPCAT_VOICES, NULL, NULL, &cpEnum)) + { + return ret; + } + + // iterate through the voices and add them to the string vector + ISpObjectToken *voice_token; + while (S_OK == cpEnum->Next(1, &voice_token, NULL)) + { + CSpDynamicString voice_str; + + if (SUCCEEDED(SpGetDescription(voice_token, &voice_str))) + { + ret.push_back(voice_str.Copy()); + } + } + + return ret; +} + + +//------------------------------------------------------------------------------ +bool SpeechApi51::lexiconDialog(HWND window) +{ + // open the dialog + SpeechApi51Lexicon dialog(window); + + if (!dialog.display()) + { + return false; + } + + return true; +} + +//------------------------------------------------------------------------------ +std::wstring SpeechApi51::getDescription() +{ + return L"Microsoft SAPI v5.1"; +} + +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechApi51.h b/plugins/WinterSpeak/src/SpeechApi51.h new file mode 100644 index 0000000000..b7505e1410 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi51.h @@ -0,0 +1,83 @@ +#pragma once + +#include "TextToSpeech.h" + +struct ISpVoice; +class Sapi51Callback; + +class SpeechApi51 : public TextToSpeech +{ + public: + SpeechApi51(); + virtual ~SpeechApi51(); + + //-------------------------------------------------------------------------- + // Description : is the api available for use + // Return : true - it is available + // false - it is not available + //-------------------------------------------------------------------------- + virtual bool isAvailable(); + + //-------------------------------------------------------------------------- + // Description : load/unload/reload the speech api + // Return : true - the action succeeded + // false - the action failed + //-------------------------------------------------------------------------- + virtual bool load(); + virtual bool unload(); + + //-------------------------------------------------------------------------- + // Description : check if the speech api is loaded + // Return : true - the speech_api is loaded + // false - its not loaded + //-------------------------------------------------------------------------- + virtual bool isLoaded() const; + + //-------------------------------------------------------------------------- + // Description : speak a sentence + // Parameters : sentence - the sentence to speak + // Returns : true - speak successful + // false - speak failed + //-------------------------------------------------------------------------- + virtual bool say(const std::wstring &sentence); + + //-------------------------------------------------------------------------- + // Description : set the voice settings + // Parameters : range from 0 to 100 + //-------------------------------------------------------------------------- + virtual bool setVolume(int volume); + virtual bool setPitch(int pitch); + virtual bool setRate(int rate); + + //-------------------------------------------------------------------------- + // Description : set the voice + //-------------------------------------------------------------------------- + virtual bool setVoice(const std::wstring &voice); + + //-------------------------------------------------------------------------- + // Description : get the available voices + //-------------------------------------------------------------------------- + virtual std::vector getVoices() const; + + //-------------------------------------------------------------------------- + // Description : open the lexicon dialog for this engine + // Parameters : window - handle to the parent window + // Return : true - dialog completely successfully + // false - dialog failed + //-------------------------------------------------------------------------- + virtual bool lexiconDialog(HWND window); + + //-------------------------------------------------------------------------- + // Description : get the description of the tts engine + //-------------------------------------------------------------------------- + static std::wstring getDescription(); + + private: + ISpVoice *m_sapi; + + TextToSpeech::State m_state; + std::wstring m_voice; + int m_volume; + int m_pitch; + int m_rate; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechApi51Lexicon.cpp b/plugins/WinterSpeak/src/SpeechApi51Lexicon.cpp new file mode 100644 index 0000000000..2a64b0fb6a --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi51Lexicon.cpp @@ -0,0 +1,75 @@ +#include "Common.h" +#include "SpeechApi51Lexicon.h" +#include "SpeechApi51.h" + + +extern HINSTANCE g_hInst; + +//------------------------------------------------------------------------------ +SpeechApi51Lexicon::SpeechApi51Lexicon(HWND window) : m_parent_window(window), m_window(0) +{ +} + +//------------------------------------------------------------------------------ +SpeechApi51Lexicon::~SpeechApi51Lexicon() +{ +} + +//------------------------------------------------------------------------------ +bool SpeechApi51Lexicon::display() +{ + m_window = CreateDialog( + g_hInst, + MAKEINTRESOURCE(IDD_TTS_LEXICON), + m_parent_window, + dialogEvent); + + if (!m_window) + { + return false; + } + + ShowWindow(m_window, SW_SHOW); + +/* WNDCLASS wc; + + wc.style = 0; +! wc.lpfnWndProc = (WNDPROC)MainWndProc; // Window procedure for this class. + wc.cbClsExtra = 0; // No per-class extra data. +! wc.cbWndExtra = 0; // No per-window extra data. + wc.hInstance = hInstance; // Application that owns the class. + wc.hIcon = NULL; + wc.hCursor = NULL; + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = "Comdlg32WClass"; // Name used in call to CreateWindow. + + return (RegisterClass(&wc));*/ + + return true; +} + +//------------------------------------------------------------------------------ +INT_PTR CALLBACK SpeechApi51Lexicon::dialogEvent(HWND hwndDlg, UINT uMsg, WPARAM wParam, + LPARAM lParam) +{ + + return TRUE; +} + +//------------------------------------------------------------------------------ +void SpeechApi51Lexicon::addLexicon() +{ +} + +//------------------------------------------------------------------------------ +void SpeechApi51Lexicon::deleteLexicon() +{ +} + +//------------------------------------------------------------------------------ +void SpeechApi51Lexicon::displayLexicon() +{ +} + +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechApi51Lexicon.h b/plugins/WinterSpeak/src/SpeechApi51Lexicon.h new file mode 100644 index 0000000000..85dd2230fe --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechApi51Lexicon.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +class SpeechApi51; + +class SpeechApi51Lexicon +{ + public: + //-------------------------------------------------------------------------- + // Description : Constuctor + // Parameters : window - handle to the parent window + //-------------------------------------------------------------------------- + SpeechApi51Lexicon(HWND window); + + ~SpeechApi51Lexicon(); + + //-------------------------------------------------------------------------- + // Description : display the lexicon dialog + // Return : true - display ok + // false - display failed + //-------------------------------------------------------------------------- + bool display(); + + private: + static INT_PTR CALLBACK dialogEvent(HWND hwndDlg, UINT uMsg, + WPARAM wParam, LPARAM lParam); + + void addLexicon(); + void deleteLexicon(); + void displayLexicon(); + + HWND m_parent_window; + HWND m_window; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/SpeechInterface.cpp b/plugins/WinterSpeak/src/SpeechInterface.cpp new file mode 100644 index 0000000000..500165f356 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechInterface.cpp @@ -0,0 +1,68 @@ +#include "Common.h" +#include "SpeechInterface.h" +#include "SpeechApi51.h" + + +SpeechInterface::SpeechInterface() +{ +} + +//------------------------------------------------------------------------------ +SpeechInterface::~SpeechInterface() +{ +} + +//------------------------------------------------------------------------------ +TextToSpeech * SpeechInterface::createTts(std::wstring &engine) const +{ + TextToSpeech *tts = 0; + + /*if (SpeechApi40a::getDescription() == engine) + { + tts = new SpeechApi40a(); + } + else*/ + if (SpeechApi51::getDescription() == engine) + { + tts = new SpeechApi51(); + } + + return tts; +} + +//------------------------------------------------------------------------------ +void SpeechInterface::configureTts(TextToSpeech *tts, const VoiceDesc &desc) const +{ + if (!tts) + { + return; + } + + tts->setVoice(desc.voice); + tts->setVolume(desc.volume); + tts->setRate(desc.rate); + tts->setPitch(desc.pitch); + tts->load(); +} + +//------------------------------------------------------------------------------ +std::vector SpeechInterface::getAvailableEngines() +{ + std::vector engines; + + /*SpeechApi40a sapi40a; + if (sapi40a.isAvailable()) + { + engines.push_back(SpeechApi40a::getDescription()); + }*/ + + SpeechApi51 sapi51; + if (sapi51.isAvailable()) + { + engines.push_back(SpeechApi51::getDescription()); + } + + return engines; +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/SpeechInterface.h b/plugins/WinterSpeak/src/SpeechInterface.h new file mode 100644 index 0000000000..eec7eae4f0 --- /dev/null +++ b/plugins/WinterSpeak/src/SpeechInterface.h @@ -0,0 +1,32 @@ +#pragma once + +#include + +class TextToSpeech; + +class SpeechInterface +{ + public: + SpeechInterface(); + ~SpeechInterface(); + + //-------------------------------------------------------------------------- + // Description : create the text to speech object + // Parameters : engine - the name of the engine to create + // Returns : an instance of the text to speech engine + //-------------------------------------------------------------------------- + TextToSpeech * createTts(std::wstring &engine) const; + + //-------------------------------------------------------------------------- + // Description : configure the tts object + // Parameters : tts - the tts object to configure + // desc - the description of the voice + //-------------------------------------------------------------------------- + void configureTts(TextToSpeech *tts, const VoiceDesc &desc) const; + + //-------------------------------------------------------------------------- + // Description : create a vector of available engines + //-------------------------------------------------------------------------- + std::vector getAvailableEngines(); +}; + diff --git a/plugins/WinterSpeak/src/Subject.cpp b/plugins/WinterSpeak/src/Subject.cpp new file mode 100644 index 0000000000..b502aac4fb --- /dev/null +++ b/plugins/WinterSpeak/src/Subject.cpp @@ -0,0 +1,55 @@ +#include "Common.h" +#include "Subject.h" +#include "Observer.h" + + +//------------------------------------------------------------------------------ +// public: +//------------------------------------------------------------------------------ +Subject::Subject() : m_observer_list() +{ +} + +//------------------------------------------------------------------------------ +Subject::~Subject() +{ +} + +//------------------------------------------------------------------------------ +void Subject::notify() +{ + // call update for all observers in the list + for (std::list::iterator iter = m_observer_list.begin(); iter != m_observer_list.end(); ++iter) + { + (*iter)->update(*this); + } +} + +//------------------------------------------------------------------------------ +void Subject::attach(Observer &observer) +{ + for (std::list::iterator iter = m_observer_list.begin(); iter != m_observer_list.end(); ++iter) + { + if (*iter == &observer) + { + return; + } + } + m_observer_list.push_back(&observer); +} + +//------------------------------------------------------------------------------ +void Subject::detach(const Observer &observer) +{ + for (std::list::iterator iter = m_observer_list.begin(); iter != m_observer_list.end(); ++iter) + { + if (*iter == &observer) + { + m_observer_list.erase(iter); + } + } +} + +//============================================================================== + + diff --git a/plugins/WinterSpeak/src/Subject.h b/plugins/WinterSpeak/src/Subject.h new file mode 100644 index 0000000000..f4bba3b075 --- /dev/null +++ b/plugins/WinterSpeak/src/Subject.h @@ -0,0 +1,38 @@ +#pragma once + +#include "Observer.h" + +#include +class Subject +{ +public: + Subject(); + virtual ~Subject(); + + //-------------------------------------------------------------------------- + // Description : Notify all observers of a state change + //-------------------------------------------------------------------------- + void notify(); + + //-------------------------------------------------------------------------- + // Description : Attach an observer to the subject + // Parameters : observer - the observer + //-------------------------------------------------------------------------- + void attach(Observer &observer); + + //-------------------------------------------------------------------------- + // Description : Detach an observer from the subject + // Parameters : observer - the observer + //-------------------------------------------------------------------------- + void detach(const Observer &observer); + + private: + //-------------------------------------------------------------------------- + // Description : Disallow assignment operator and copy constructor + //-------------------------------------------------------------------------- + Subject(const Subject &rhs); + const Subject & operator=(const Subject &rhs); + + std::list m_observer_list; +}; + diff --git a/plugins/WinterSpeak/src/TextToSpeech.cpp b/plugins/WinterSpeak/src/TextToSpeech.cpp new file mode 100644 index 0000000000..ddb1185225 --- /dev/null +++ b/plugins/WinterSpeak/src/TextToSpeech.cpp @@ -0,0 +1,14 @@ +#include "Common.h" +#include "TextToSpeech.h" + +//------------------------------------------------------------------------------ +TextToSpeech::TextToSpeech() +{ +} + +//------------------------------------------------------------------------------ +TextToSpeech::~TextToSpeech() +{ +} + +//------------------------------------------------------------------------------ \ No newline at end of file diff --git a/plugins/WinterSpeak/src/TextToSpeech.h b/plugins/WinterSpeak/src/TextToSpeech.h new file mode 100644 index 0000000000..f426c43e87 --- /dev/null +++ b/plugins/WinterSpeak/src/TextToSpeech.h @@ -0,0 +1,74 @@ +#pragma once + +#include "Common.h" +#include +#include + +class TextToSpeech +{ + public: + enum State + { + State_Loaded, + State_Unloaded, + }; + + TextToSpeech(); + virtual ~TextToSpeech(); + + //-------------------------------------------------------------------------- + // Description : is the api available for use + // Return : true - it is available + // false - it is not available + //-------------------------------------------------------------------------- + virtual bool isAvailable() = 0; + + //-------------------------------------------------------------------------- + // Description : load/unload/reload the speech api + // Return : true - the action succeeded + // false - the action failed + //-------------------------------------------------------------------------- + virtual bool load() = 0; + virtual bool unload() = 0; + + //-------------------------------------------------------------------------- + // Description : check if the speech api is loaded + // Return : true - the speech_api is loaded + // false - its not loaded + //-------------------------------------------------------------------------- + virtual bool isLoaded() const = 0; + + //-------------------------------------------------------------------------- + // Description : speak a sentence + // Parameters : sentence - the sentence to speak + // Returns : true - speak successful + // false - speak failed + //-------------------------------------------------------------------------- + virtual bool say(const std::wstring &sentence) = 0; + + //-------------------------------------------------------------------------- + // Description : set the voice settings + // Parameters : range from 0 to 100 + //-------------------------------------------------------------------------- + virtual bool setVolume(int volume) = 0; + virtual bool setPitch(int pitch) = 0; + virtual bool setRate(int rate) = 0; + + //-------------------------------------------------------------------------- + // Description : set the voice + //-------------------------------------------------------------------------- + virtual bool setVoice(const std::wstring &voice) = 0; + + //-------------------------------------------------------------------------- + // Description : get the available voices + //-------------------------------------------------------------------------- + virtual std::vector getVoices() const = 0; + + //-------------------------------------------------------------------------- + // Description : open the lexicon dialog for this engine + // Parameters : window - handle to the parent window + // Return : true - dialog completely successfully + // false - dialog failed + //-------------------------------------------------------------------------- + virtual bool lexiconDialog(HWND window) = 0; +}; \ No newline at end of file diff --git a/plugins/WinterSpeak/src/UserInformation.cpp b/plugins/WinterSpeak/src/UserInformation.cpp new file mode 100644 index 0000000000..fa5db0b0e5 --- /dev/null +++ b/plugins/WinterSpeak/src/UserInformation.cpp @@ -0,0 +1,78 @@ +#include "Common.h" +#include "UserInformation.h" + + +UserInformation::UserInformation() : m_status_info(), m_status_strings() { + // insert the status strings into a map for easy access + m_status_strings[ID_STATUS_OFFLINE] = L"%u is now offline"; + m_status_strings[ID_STATUS_ONLINE] = L"%u is now online"; + m_status_strings[ID_STATUS_AWAY] = L"%u is away"; + m_status_strings[ID_STATUS_INVISIBLE] = L"%u is invisible"; + m_status_strings[ID_STATUS_NA] = L"%u is not available"; + m_status_strings[ID_STATUS_DND] = L"%u does not want to be disturbed"; + m_status_strings[ID_STATUS_OCCUPIED] = L"%u is occupied"; + m_status_strings[ID_STATUS_FREECHAT] = L"%u is free for chat"; +} + +//------------------------------------------------------------------------------ +UserInformation::~UserInformation() +{ +} + +//------------------------------------------------------------------------------ +bool UserInformation::updateStatus(HANDLE user, int status) +{ + bool ret = false; + + // if the user exists and their status hasn't changed, then return false + if ((m_status_info.find(user) != m_status_info.end()) + && (m_status_info[user] != status)) + { + ret = true; + } + + // update the status + m_status_info[user] = status; + + return ret; +} + +//------------------------------------------------------------------------------ +std::wstring UserInformation::statusString(HANDLE user) +{ + return m_status_strings[m_status_info[user]]; +} + +//------------------------------------------------------------------------------ +std::wstring UserInformation::statusModeString(HANDLE user) +{ + int status = CallService(MS_CLIST_GETSTATUSMODEDESCRIPTION, m_status_info[user], 0); + + if (NULL == status) + { + return L""; + } + + return reinterpret_cast(status); +} + +//------------------------------------------------------------------------------ +void UserInformation::insertName(std::wstring &str, HANDLE user) const +{ + // insert the user's name into the string + str.replace(str.find(L"%u"), 2, nameString(user)); +} + +//------------------------------------------------------------------------------ +std::wstring UserInformation::nameString(HANDLE user) const +{ + //WCHAR *ret = reinterpret_cast(CallService(MS_CLIST_GETCONTACTDISPLAYNAME, reinterpret_cast(user), 0)); + char* ret = (char *)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, WPARAM(user), 0); + if (0 == ret) + { + return L""; + } + return TranslateW(mir_a2t(ret)); +} + +//============================================================================== diff --git a/plugins/WinterSpeak/src/UserInformation.h b/plugins/WinterSpeak/src/UserInformation.h new file mode 100644 index 0000000000..a9d972d96d --- /dev/null +++ b/plugins/WinterSpeak/src/UserInformation.h @@ -0,0 +1,53 @@ +#pragma once + +#include +#include + +class UserInformation +{ + public: + UserInformation(); + ~UserInformation(); + + //-------------------------------------------------------------------------- + // Description : update the users status + // Parameters : user - the current user + // status - the users status + // Returns : true - the status changed + // false - the status stayed the same + //-------------------------------------------------------------------------- + bool updateStatus(HANDLE user, int status); + + //-------------------------------------------------------------------------- + // Description : get a string containing the users current status string + // Parameters : user - the current user + // Returns : the string containing the users status + //-------------------------------------------------------------------------- + std::wstring statusString(HANDLE user); + + //-------------------------------------------------------------------------- + // Description : return the status mode of the user + // Parameters : user - the current user + // Returns : the string containing the users status mode + //-------------------------------------------------------------------------- + std::wstring statusModeString(HANDLE user); + + //-------------------------------------------------------------------------- + // Description : insert the name into the string at the %u location + // Parameters : str - the string to have the username inserted into + // user - the current user + //-------------------------------------------------------------------------- + void insertName(std::wstring &str, HANDLE user) const; + + //-------------------------------------------------------------------------- + // Description : get the name string for the user + // Parameters : user - the current user + // Returns : a string containing the user's name + //-------------------------------------------------------------------------- + std::wstring nameString(HANDLE user) const; + + private: + std::map m_status_info; + std::map m_status_strings; +}; + diff --git a/plugins/WinterSpeak/src/Version.h b/plugins/WinterSpeak/src/Version.h new file mode 100644 index 0000000000..6dcfc0d27f --- /dev/null +++ b/plugins/WinterSpeak/src/Version.h @@ -0,0 +1,14 @@ +#define __MAJOR_VERSION 0 +#define __MINOR_VERSION 9 +#define __RELEASE_NUM 8 +#define __BUILD_NUM 0 + +#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM + +#define __PLUGIN_NAME "Speak" +#define __FILENAME "speak.dll" +#define __DESCRIPTION "Miranda interface to the Microsoft Speech API" +#define __AUTHOR "Ryan Winter, BlubbFish" +#define __AUTHOREMAIL "miranda@blubbfish.net" +#define __AUTHORWEB "http://miranda-ng.org/p/WinterSpeak/" +#define __COPYRIGHT "© 2002 Ryan Winter, © 2013 BlubbFish" diff --git a/plugins/WinterSpeak/src/m_speak.h b/plugins/WinterSpeak/src/m_speak.h new file mode 100644 index 0000000000..d044b29595 --- /dev/null +++ b/plugins/WinterSpeak/src/m_speak.h @@ -0,0 +1,4 @@ + + +#define ME_SPEAK_STATUS "Speak/Status" +#define ME_SPEAK_MESSAGE "Speak/Message" \ No newline at end of file diff --git a/plugins/WinterSpeak/src/main.cpp b/plugins/WinterSpeak/src/main.cpp new file mode 100644 index 0000000000..debe87cf29 --- /dev/null +++ b/plugins/WinterSpeak/src/main.cpp @@ -0,0 +1,172 @@ +#include "Common.h" + + +HINSTANCE g_hInst; +int hLangpack; +DWORD g_mirandaVersion; + +SpeakConfig *g_speak_config = 0; +SpeakAnnounce *g_speak_announce = 0; +HANDLE g_dialog_options_initialise; +HANDLE g_event_status_change; +HANDLE g_event_message_added; +HANDLE g_protocol_ack; + +PLUGININFOEX pluginInfo={ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {81E189DC-C251-45F6-9EDF-A0F3A05C4248} + { 0x81e189dc, 0xc251, 0x45f6, { 0x9e, 0xdf, 0xa0, 0xf3, 0xa0, 0x5c, 0x42, 0x48 } } +}; + +//----------------------------------------------------------------------------- +// Description : External hook +//----------------------------------------------------------------------------- +int status(WPARAM wParam, LPARAM lParam) +{ + return g_speak_config->status(reinterpret_cast(lParam), reinterpret_cast(wParam)); +} +int message(WPARAM wParam, LPARAM lParam) +{ + return g_speak_config->message(reinterpret_cast(lParam), reinterpret_cast(wParam)); +} + +//----------------------------------------------------------------------------- +// Description : an status change event occured +//----------------------------------------------------------------------------- +int eventStatusChange(WPARAM wParam, LPARAM lParam) +{ + g_speak_announce->statusChange( + reinterpret_cast(lParam), + reinterpret_cast(wParam)); + + return 0; +} + +//----------------------------------------------------------------------------- +// Description : a message event occured +//----------------------------------------------------------------------------- +int eventMessageAdded(WPARAM wParam, LPARAM lParam) +{ + g_speak_announce->incomingEvent(reinterpret_cast(wParam), reinterpret_cast(lParam)); + return 0; +} + +//----------------------------------------------------------------------------- +// Description : a messaging protocol changed state +//----------------------------------------------------------------------------- +int protocolAck(WPARAM wParam, LPARAM lParam) +{ + g_speak_announce->protocolAck(reinterpret_cast(lParam)); + + return 0; +} + +int dialogOptionsInitialise(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = { sizeof(odp) }; + + odp.hInstance = g_hInst; + odp.ptszGroup = LPGENT("Speak"); + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + + if (g_speak_config) + { + odp.pszTemplate = MAKEINTRESOURCEA(IDD_CONFIG); + odp.ptszTitle = LPGENT("Engine/Voice"); + odp.pfnDlgProc = DialogConfigEngine::process; + Options_AddPage(wParam, &odp); + + odp.pszTemplate = MAKEINTRESOURCEA(IDD_ACTIVEMODES); + odp.ptszTitle = LPGENT("Active Modes"); + odp.pfnDlgProc = DialogConfigActive::process; + Options_AddPage(wParam, &odp); + } + + if (g_speak_announce) + { + odp.pszTemplate = MAKEINTRESOURCEA(IDD_ANNOUNCE); + odp.ptszTitle = LPGENT("Announce"); + odp.pfnDlgProc = AnnounceDialog::process; + Options_AddPage(wParam, &odp); + } + return 0; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + g_mirandaVersion = mirandaVersion; + return &pluginInfo; +} + +extern "C" __declspec(dllexport) int Load(void) +{ + mir_getLP( &pluginInfo ); + //pluginLink = link; + + if (!g_speak_config) + { + g_speak_config = new SpeakConfig(g_hInst); + + // expose to allow miranda + plugins to access my speak routines + CreateServiceFunction(ME_SPEAK_STATUS, status); + CreateServiceFunction(ME_SPEAK_MESSAGE, message); + } + + if (!g_speak_announce) + { + g_speak_announce = new SpeakAnnounce(g_hInst); + + // tap into contact setting change event + g_event_status_change = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, eventStatusChange); + + // a new message event has occured + g_event_message_added = HookEvent(ME_DB_EVENT_ADDED, eventMessageAdded); + + // a messaging protocol changed state + g_protocol_ack = HookEvent(ME_PROTO_ACK, protocolAck); + + } + + // a option dialog box request has occured + g_dialog_options_initialise = HookEvent(ME_OPT_INITIALISE, dialogOptionsInitialise); + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + UnhookEvent(g_dialog_options_initialise); + + if (g_speak_config) + { + delete g_speak_config; + g_speak_config = 0; + } + + if (g_speak_announce) + { + UnhookEvent(g_event_status_change); + UnhookEvent(g_event_message_added); + UnhookEvent(g_protocol_ack); + + delete g_speak_announce; + g_speak_announce = 0; + } + + return 0; +} + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + DisableThreadLibraryCalls(hinstDLL); + g_hInst = hinstDLL; + return TRUE; +} \ No newline at end of file diff --git a/plugins/WinterSpeak/src/resource.h b/plugins/WinterSpeak/src/resource.h new file mode 100644 index 0000000000..6775f8d314 --- /dev/null +++ b/plugins/WinterSpeak/src/resource.h @@ -0,0 +1,71 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by Restart.rc +// +#define IDD_CONFIG 101 +#define IDD_ANNOUNCE 102 +#define IDD_ACTIVEMODES 103 +#define IDI_RECVMSG 136 +#define IDI_USERONLINE 201 +#define IDI_FILLEDBLOB 212 +#define IDI_EMPTYBLOB 213 +#define IDC_SELECT_ENGINE 1001 +#define IDC_SELECT_VOICE 1002 +#define IDC_SLIDER_RATE 1003 +#define IDC_SLIDER_VOLUME 1004 +#define IDC_SLIDER_PITCH 1005 +#define IDC_LOAD_SAPI 1006 +#define IDC_WELCOME_MSG 1007 +#define IDC_ACTIVE_OFFLINE 1008 +#define IDC_ACTIVE_ONLINE 1009 +#define IDC_ACTIVE_AWAY 1010 +#define IDC_ACTIVE_DND 1011 +#define IDC_ACTIVE_NA 1012 +#define IDC_ACTIVE_OCCUPIED 1013 +#define IDC_ACTIVE_FREEFORCHAT 1014 +#define IDC_ACTIVE_INVISIBLE 1015 +#define IDC_BUTTON_TEST 1016 +#define IDC_STATUS_OFFLINE 1100 +#define IDC_STATUS_ONLINE 1101 +#define IDC_STATUS_AWAY 1102 +#define IDC_STATUS_DND 1103 +#define IDC_STATUS_NA 1104 +#define IDC_STATUS_OCCUPIED 1105 +#define IDC_STATUS_FREEFORCHAT 1106 +#define IDC_STATUS_INVISIBLE 1107 +#define IDC_SPEAK_STATUS_MSG 1108 +#define IDC_EVENT_MESSAGE 1109 +#define IDC_EVENT_URL 1110 +#define IDC_EVENT_FILE 1111 +#define IDC_EVENT_AUTHREQUEST 1112 +#define IDC_EVENT_ADDED 1113 +#define IDC_READ_MSG_LENGTH 1114 +#define IDC_MAX_MSG 1115 +#define IDC_DIALOG_OPEN 1116 +#define IDC_DIALOG_FOCUSED 1117 +#define IDC_ACTIVE_USERS 1118 +#define IDC_ONLINEICON 1207 +#define IDC_MSGICON 1375 +#define IDC_ALLICON 1208 +#define IDC_NONEICON 1209 +#define IDC_SUPPRESS_CONNECT 1121 +#define IDC_CONFIG_LEXICON 1122 + +#define IDD_TTS_LEXICON 201 +#define IDC_TTS_LEXICON_LIST 2001 +#define IDC_TTS_LEXICON_ORIGINAL 2002 +#define IDC_TTS_LEXICON_FINAL 2003 +#define IDC_TTS_LEXICON_ADD 2004 +#define IDC_TTS_LEXICON_REMOVE 2005 +#define IDC_TTS_LEXICON_TEST 2006 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/plugins/WinterSpeak/src/stdafx.cpp b/plugins/WinterSpeak/src/stdafx.cpp new file mode 100644 index 0000000000..1976d867da --- /dev/null +++ b/plugins/WinterSpeak/src/stdafx.cpp @@ -0,0 +1,18 @@ +/* +Copyright (C) 2012-13 Miranda NG Project (http://miranda-ng.org) + +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 version 2 +of the License. + +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, see . +*/ + +#include "common.h" \ No newline at end of file diff --git a/plugins/WinterSpeak/src/voice_desc.h b/plugins/WinterSpeak/src/voice_desc.h new file mode 100644 index 0000000000..37ae72b0e9 --- /dev/null +++ b/plugins/WinterSpeak/src/voice_desc.h @@ -0,0 +1,10 @@ +#include + +struct VoiceDesc +{ + std::wstring engine; + std::wstring voice; + int volume; + int pitch; + int rate; +}; \ No newline at end of file -- cgit v1.2.3