├── LICENSE ├── README.md ├── Sapi4 ├── Include │ ├── buildnum.h │ ├── buildnum.rc │ ├── spchtel.h │ ├── spchwrap.h │ └── speech.h └── Lib │ └── spchwrap.lib ├── UGlobalHotkey ├── .gitignore ├── .qmake.stash ├── README.md ├── hotkeymap.h ├── uexception.cpp ├── uexception.h ├── uglobal.h ├── uglobalhotkey-headers.pri ├── uglobalhotkey-libs.pri ├── uglobalhotkey-sources.pri ├── uglobalhotkey.pri ├── uglobalhotkey.pro ├── uglobalhotkey.sln ├── uglobalhotkey.vcxproj ├── uglobalhotkey.vcxproj.filters ├── uglobalhotkeys.cpp ├── uglobalhotkeys.h ├── ukeysequence.cpp └── ukeysequence.h ├── UltraTTS.sln └── UltraTTS ├── Options.ui ├── OptionsDlg.cpp ├── OptionsDlg.h ├── Sapi ├── TTS.cpp ├── TTS.h ├── TTS4.cpp ├── TTS4.h ├── TTS5.cpp └── TTS5.h ├── UltraTTS.cpp ├── UltraTTS.h ├── UltraTTS.ico ├── UltraTTS.qrc ├── UltraTTS.rc ├── UltraTTS.ui ├── UltraTTS.vcxproj ├── UltraTTS.vcxproj.filters ├── Utils ├── Functions.cpp ├── Functions.h ├── LangDetect.cpp └── LangDetect.h ├── images ├── accessories-calculator.png ├── accessories-text-editor.png ├── artsfftscope.png ├── block.png ├── bold.png ├── copy.png ├── create.png ├── cut.png ├── edit_redo.png ├── edit_undo.png ├── exit.png ├── font.png ├── info.png ├── italic.png ├── new.png ├── ok.png ├── open.png ├── paste.png ├── pencil.png ├── player_pause.png ├── player_play.png ├── player_play2.png ├── player_stop.png ├── print.png ├── read_cb.png ├── rotateleft.png ├── rotateright.png ├── save.png ├── save_as.png ├── underline.png ├── zoomin.png └── zoomout.png ├── main.cpp ├── stdafx.cpp └── stdafx.h /README.md: -------------------------------------------------------------------------------- 1 | # UltraTTS 2 | Simple yet Powerfull Sapi 4/5 TTS Reader 3 | 4 | 5 | If you are into TTS you surly know BalaBolka, it is a advanced TTS tool to create audio-books, using SAPI Voices. It can also read text from clipboard as well as install a global hot key to issue a Ctrl+C and than read whatever ended up in the clipboard. While it excels in its job as a audio-book maker, it is lacking features as a TTS Reader. Unfortunately the tool, while being free, is not open source so improving on its TTS Reader qualities is not possible. But what is possible is to create an own Open Source GPLv3 tool which would excel in just being a TTS Reader, and looking familiar. 6 | 7 | Hence UltraTTS the tool provides a set of features helpful for people using TTS a lot. 8 | 9 | 1.) Ultra TTS can auto detect the language of the text and if a corresponding voice is installed it will be used, so no more having to open the UI and switch the language whenever you read something different. The auto detect functionality even works within text blocks. for example when quoting a english sentence in a german publication. 10 | 11 | 2.) Ultra TTS by default queues texts such that you can clich for example through a multi page article and than lean back or do whatever productive you want to do in the mean time and listen to all of it on one go. 12 | 13 | 3.) Ultra TTS can use Cortana Voices if installed. 14 | 15 | 4.) The text read out is always copied to the tab such that if you want you can re read it even if you already changed your clipboard content and closed the page the text was on. 16 | 17 | 5.) All important things can be done with global hot keys. 18 | 19 | 6.) After successfully grabbed a text from clipboard the original clipboard content is restored. 20 | 21 | -------------------------------------------------------------------------------- /Sapi4/Include/buildnum.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/Sapi4/Include/buildnum.h -------------------------------------------------------------------------------- /Sapi4/Include/buildnum.rc: -------------------------------------------------------------------------------- 1 | /* Each RC file that includes this file for version 2 | * stamping, must define the following items: 3 | * 4 | * #define VER_FILE_TYPE VFT_ // VFT_APP, VFT_DLL, VFT_DRV, VFT_VXD 5 | * #define VER_FILE_DESC "Your app name\0" // don't forget the explicit null. 6 | * #define VER_FILE_SUBTYPE 0 // All but driver should be 0 7 | * #define VER_FILE_INTNAME "\0" //don't forget the null. 8 | * 9 | * Change Log: 10 | * 8/31/93 - benm - Tweaked to handle internal name correctly. 11 | */ 12 | #ifndef BUILDNUM_RC 13 | #define BUILDNUM_RC 14 | 15 | #include 16 | #ifndef VS_FF_DEBUG 17 | #include 18 | #endif 19 | 20 | // Default internal name to be same as file desc. 21 | #ifndef VER_INTERNAL_NAME 22 | #define VER_INTERNAL_NAME VER_FILE_DESC 23 | #endif 24 | 25 | VS_VERSION_INFO VERSIONINFO 26 | FILEVERSION BN_FILE_VERSION 27 | PRODUCTVERSION BN_PRODUCT_VERSION 28 | FILEFLAGSMASK BN_FLAGSMASK 29 | FILEFLAGS BN_FLAGS 30 | FILEOS VOS_NT_WINDOWS32 31 | 32 | FILETYPE VER_FILE_TYPE 33 | FILESUBTYPE VER_FILE_SUBTYPE 34 | 35 | BEGIN 36 | BLOCK "StringFileInfo" 37 | BEGIN 38 | BLOCK "040904E4" 39 | BEGIN 40 | VALUE "CompanyName", "Microsoft Corporation\0" 41 | VALUE "FileDescription", VER_FILE_DESC 42 | VALUE "FileVersion", BN_FILE_VERSION_STR 43 | VALUE "InternalName", VER_INTERNAL_NAME 44 | VALUE "LegalCopyright", BN_COPYRIGHT 45 | VALUE "ProductName", BN_PRODUCTNAME 46 | VALUE "ProductVersion", BUILD_NUMBER 47 | VALUE "OriginalFilename", VER_ORIGINAL_FILENAME 48 | END 49 | 50 | BLOCK "040904B0" 51 | BEGIN 52 | VALUE "CompanyName", "Microsoft Corporation\0" 53 | VALUE "FileDescription", VER_FILE_DESC 54 | VALUE "FileVersion", BN_FILE_VERSION_STR 55 | VALUE "InternalName", VER_INTERNAL_NAME 56 | VALUE "LegalCopyright", BN_COPYRIGHT 57 | VALUE "ProductName", BN_PRODUCTNAME 58 | VALUE "ProductVersion", BUILD_NUMBER 59 | VALUE "OriginalFilename", VER_ORIGINAL_FILENAME 60 | END 61 | END 62 | 63 | BLOCK "VarFileInfo" 64 | BEGIN 65 | VALUE "Translation", 0x409, 1252 66 | END 67 | END 68 | 69 | #endif // BUILDNUM_RC 70 | -------------------------------------------------------------------------------- /Sapi4/Include/spchtel.h: -------------------------------------------------------------------------------- 1 | /***************************************************************** 2 | Spchtel.H - Header file to use the Microsoft Speech telephony controls. 3 | 4 | Copyright 1998 by Microsoft corporation.All rights reserved. 5 | */ 6 | 7 | #ifndef _SPCHTEL_H_ 8 | #define _SPCHTEL_H_ 9 | 10 | // Flag values for the ITelControl::TypeSet call 11 | #define INFOTYPE_PC 0x00000001 12 | #define INFOTYPE_TAPI20 0x00000002 13 | #define INFOTYPE_TAPI30 0x00000004 14 | 15 | // Common return codes from controls 16 | // not usually handled, often returned 17 | #define TCR_ABORT ((DWORD)-1L) // the user has hung up 18 | #define TCR_NORESPONSE ((DWORD)-2L) // the user hasn't repsonded to the questions 19 | #define TCR_ASKOPERATOR ((DWORD)-3L) // the user has asked for an operator (often control just auto replies) 20 | #define TCR_ASKHANGUP ((DWORD)-4L) // the user has asked to hang up. App must handle 21 | #define TCR_ASKBACK ((DWORD)-5L) // the user has asked to go back and redo the previous thing 22 | 23 | // usually handled by control, unless overrided 24 | #define TCR_ASKWHERE ((DWORD)-10L) // the user has asked where he/she is (usualy handled by control) 25 | #define TCR_ASKHELP ((DWORD)-11L) // the user has asked for help (usually handled by control) 26 | #define TCR_ASKREPEAT ((DWORD)-12L) // the user has asked for the question to be repeated (usually handled by the control) 27 | #define TCR_ASKSPEAKFASTER ((DWORD)-13L) // the user has asked to speak faster. usually handled by the control 28 | #define TCR_ASKSPEAKSLOWER ((DWORD)-14L) // the user has asked to speak slower. Usually handled by the control 29 | 30 | 31 | 32 | // {F9D18BF8-E0ED-11d0-AB8B-08002BE4E3B7} 33 | DEFINE_GUID (CLSID_TelInfo, 34 | 0xf9d18bf8, 0xe0ed, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 35 | 36 | /* 37 | * ITelNotifySink 38 | */ 39 | #undef INTERFACE 40 | #define INTERFACE ITelNotifySink 41 | 42 | // {CD0C7D7C-E1CD-11d0-AB8B-08002BE4E3B7} 43 | DEFINE_GUID(IID_ITelNotifySink, 44 | 0xcd0c7d7c, 0xe1cd, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 45 | 46 | DECLARE_INTERFACE_ (ITelNotifySink, IUnknown) { 47 | // IUnkown members 48 | STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; 49 | STDMETHOD_(ULONG,AddRef) (THIS) PURE; 50 | STDMETHOD_(ULONG,Release) (THIS) PURE; 51 | 52 | // ITelNotifySink members 53 | STDMETHOD (DTMF) (THIS_ WCHAR) PURE; 54 | STDMETHOD (Abort) (THIS_ DWORD) PURE; 55 | }; 56 | typedef ITelNotifySink FAR *PITELNOTIFYSINK; 57 | 58 | 59 | /* 60 | * ITelControlNotifySink 61 | */ 62 | #undef INTERFACE 63 | #define INTERFACE ITelControlNotifySink 64 | 65 | // {A55E2436-E297-11d0-AB8B-08002BE4E3B7} 66 | DEFINE_GUID(IID_ITelControlNotifySink, 67 | 0xa55e2436, 0xe297, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 68 | 69 | DECLARE_INTERFACE_ (ITelControlNotifySink, IUnknown) { 70 | // IUnkown members 71 | STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; 72 | STDMETHOD_(ULONG,AddRef) (THIS) PURE; 73 | STDMETHOD_(ULONG,Release) (THIS) PURE; 74 | 75 | // ITelControlNotifySink members 76 | STDMETHOD (Finish) (THIS_ DWORD, PVOID, DWORD) PURE; 77 | STDMETHOD (Info) (THIS_ DWORD, PVOID, DWORD) PURE; 78 | }; 79 | typedef ITelControlNotifySink FAR *PITELCONTROLNOTIFYSINK; 80 | 81 | 82 | /* 83 | * ITelInfo 84 | */ 85 | #undef INTERFACE 86 | #define INTERFACE ITelInfo 87 | 88 | // {250F0433-E0EB-11d0-AB8B-08002BE4E3B7} 89 | DEFINE_GUID(IID_ITelInfo, 90 | 0x250f0433, 0xe0eb, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 91 | 92 | DECLARE_INTERFACE_ (ITelInfo, IUnknown) { 93 | // IUnkown members 94 | STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; 95 | STDMETHOD_(ULONG,AddRef) (THIS) PURE; 96 | STDMETHOD_(ULONG,Release) (THIS) PURE; 97 | 98 | // ITelInfo members 99 | STDMETHOD (ObjectGet) (THIS_ GUID, LPUNKNOWN *) PURE; 100 | STDMETHOD (ObjectSet) (THIS_ GUID, LPUNKNOWN) PURE; 101 | STDMETHOD (DWORDGet) (THIS_ GUID, DWORD *) PURE; 102 | STDMETHOD (DWORDSet) (THIS_ GUID, DWORD) PURE; 103 | STDMETHOD (MemoryGet) (THIS_ GUID, PVOID *, DWORD *) PURE; 104 | STDMETHOD (MemorySet) (THIS_ GUID, PVOID, DWORD) PURE; 105 | STDMETHOD (SendDTMF) (THIS_ WCHAR) PURE; 106 | STDMETHOD (SendAbort) (THIS_ DWORD) PURE; 107 | STDMETHOD (TypeSet) (THIS_ DWORD) PURE; 108 | STDMETHOD (WaveDeviceSet) (THIS_ DWORD, DWORD) PURE; 109 | STDMETHOD (AudioSourceCreate) (THIS_ LPUNKNOWN *) PURE; 110 | STDMETHOD (AudioDestCreate) (THIS_ LPUNKNOWN *) PURE; 111 | STDMETHOD (QuickCreate) (THIS_ HMODULE, PSRMODEINFOW, PTTSMODEINFOW, 112 | PCWSTR, BOOL) PURE; 113 | }; 114 | typedef ITelInfo FAR *PITELINFO; 115 | 116 | 117 | /* 118 | * ITelControl 119 | */ 120 | #undef INTERFACE 121 | #define INTERFACE ITelControl 122 | 123 | // {17674DEB-E298-11d0-AB8B-08002BE4E3B7} 124 | DEFINE_GUID(IID_ITelControl, 125 | 0x17674deb, 0xe298, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 126 | 127 | DECLARE_INTERFACE_ (ITelControl, IUnknown) { 128 | // IUnkown members 129 | STDMETHOD (QueryInterface) (THIS_ REFIID, LPVOID FAR *) PURE; 130 | STDMETHOD_(ULONG,AddRef) (THIS) PURE; 131 | STDMETHOD_(ULONG,Release) (THIS) PURE; 132 | 133 | // ITelControl members 134 | STDMETHOD (FromMemory) (THIS_ PVOID, DWORD) PURE; 135 | STDMETHOD (FromStream) (THIS_ IStream *) PURE; 136 | #ifdef STRICT 137 | STDMETHOD (FromResource) (THIS_ PVOID, DWORD) PURE; 138 | #else 139 | STDMETHOD (FromResource) (THIS_ HINSTANCE, DWORD) PURE; 140 | #endif 141 | STDMETHOD (FromFile) (THIS_ PCWSTR) PURE; 142 | STDMETHOD (Compile) (THIS_ LPWSTR*, DWORD*) PURE; 143 | STDMETHOD (IsCompiled) (THIS_ BOOL*) PURE; 144 | STDMETHOD (LanguageGet) (THIS_ LANGUAGEW*) PURE; 145 | STDMETHOD (ToMemory) (THIS_ PVOID*, DWORD*) PURE; 146 | STDMETHOD (ToStream) (THIS_ IStream *) PURE; 147 | STDMETHOD (ToFile) (THIS_ PCWSTR) PURE; 148 | STDMETHOD (TextGet) (THIS_ LPWSTR*, DWORD*) PURE; 149 | STDMETHOD (TextDefaultGet) (THIS_ LPWSTR*, DWORD*) PURE; 150 | STDMETHOD (ObjectSet) (THIS_ PITELINFO) PURE; 151 | STDMETHOD (Start) (THIS_ PITELCONTROLNOTIFYSINK) PURE; 152 | STDMETHOD (Abort) (THIS) PURE; 153 | }; 154 | typedef ITelControl FAR *PITELCONTROL; 155 | 156 | 157 | // 158 | // GUID identifiers for objects 159 | // 160 | // {44DB6739-E10E-11d0-AB8B-08002BE4E3B7} 161 | DEFINE_GUID(TELOBJ_SPEECHRECOG, 162 | 0x44db6739, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 163 | 164 | // {44DB673B-E10E-11d0-AB8B-08002BE4E3B7} 165 | DEFINE_GUID(TELOBJ_TTSQUEUE, 166 | 0x44db673b, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 167 | 168 | // {44DB673C-E10E-11d0-AB8B-08002BE4E3B7} 169 | DEFINE_GUID(TELOBJ_LOGGING, 170 | 0x44db673c, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 171 | 172 | // {44DB673D-E10E-11d0-AB8B-08002BE4E3B7} 173 | DEFINE_GUID(TELOBJ_TAPI30, 174 | 0x44db673d, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 175 | 176 | // {44DB673E-E10E-11d0-AB8B-08002BE4E3B7} 177 | DEFINE_GUID(TELOBJ_NOTIFYSINK, 178 | 0x44db673e, 0xe10e, 0x11d0, 0xab, 0x8b, 0x8, 0x0, 0x2b, 0xe4, 0xe3, 0xb7); 179 | 180 | 181 | // hcall for TAPI 182 | // {F40CC4C0-0D0A-11d2-BEF0-006008317CE8} 183 | DEFINE_GUID(TELDWORD_HCALL, 184 | 0xf40cc4c0, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 185 | 186 | // hline for tapi 187 | // {F40CC4C1-0D0A-11d2-BEF0-006008317CE8} 188 | DEFINE_GUID(TELDWORD_HLINE, 189 | 0xf40cc4c1, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 190 | 191 | // If this is set to TRUE, then beeps on a recognition are enabled. 192 | // Disabling speeds up the response time of the system, but some people 193 | // will speak before the beep. It's a tradeoff. 194 | // {DB7F6130-0D2D-11d2-BEF1-006008317CE8} 195 | DEFINE_GUID(TELDWORD_EnableRecognizeBeeps, 196 | 0xdb7f6130, 0xd2d, 0x11d2, 0xbe, 0xf1, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 197 | 198 | // if set to true, and we're using tapi, then we should use tapi 199 | // beeps rather than recordings for recognition acknowledgement 200 | // beeps. This doesn't work properly on most telephony cards, and there's no 201 | // way to tell, so be careful about using it 202 | // {F40CC4C2-0D0A-11d2-BEF0-006008317CE8} 203 | DEFINE_GUID(TELDWORD_UseTAPIBeep, 204 | 0xf40cc4c2, 0xd0a, 0x11d2, 0xbe, 0xf0, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 205 | 206 | // disable the ability for a user to change the speed 207 | // {59596FBE-F936-11d0-8FAD-08002BE4E62A} 208 | DEFINE_GUID(TELDWORD_DisableSpeedChange, 209 | 0x59596fbe, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 210 | 211 | // enable the ability for the user to ask for an operator 212 | // {59596FBF-F936-11d0-8FAD-08002BE4E62A} 213 | DEFINE_GUID(TELDWORD_EnableOperator, 214 | 0x59596fbf, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 215 | 216 | // eanble the user to ask to hang up. If TRUE application must handle 217 | // {59596FC0-F936-11d0-8FAD-08002BE4E62A} 218 | DEFINE_GUID(TELDWORD_EnableAskHangUp, 219 | 0x59596fc0, 0xf936, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 220 | 221 | // if TRUE, then the system supports full duplex 222 | // both full duplex and echo cancelling must be TRUE for telephony controls to have barge in 223 | // {10FEF992-343F-11d1-BE71-006008317CE8} 224 | DEFINE_GUID(TELDWORD_FullDuplex, 225 | 0x10fef992, 0x343f, 0x11d1, 0xbe, 0x71, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 226 | 227 | // if TRUE, then the system has echo cancelling built in. 228 | // both full duplex and echo cancelling must be TRUE for telephony controls to have barge in 229 | // {10FEF991-343F-11d1-BE71-006008317CE8} 230 | DEFINE_GUID(TELDWORD_EchoCancel, 231 | 0x10fef991, 0x343f, 0x11d1, 0xbe, 0x71, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 232 | 233 | /************************************************************************** 234 | Telephon controls in spchtel.dll. */ 235 | 236 | // {53961A01-459B-11d1-BE77-006008317CE8} 237 | DEFINE_GUID(CLSID_YesNoControl, 238 | 0x53961a01, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 239 | 240 | // {53961A02-459B-11d1-BE77-006008317CE8} 241 | DEFINE_GUID(CLSID_ExtensionControl, 242 | 0x53961a02, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 243 | 244 | // {53961A03-459B-11d1-BE77-006008317CE8} 245 | DEFINE_GUID(CLSID_PhoneNumControl, 246 | 0x53961a03, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 247 | 248 | // {53961A04-459B-11d1-BE77-006008317CE8} 249 | DEFINE_GUID(CLSID_GrammarControl, 250 | 0x53961a04, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 251 | 252 | // {53961A05-459B-11d1-BE77-006008317CE8} 253 | DEFINE_GUID(CLSID_DateControl, 254 | 0x53961a05, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 255 | 256 | // {53961A06-459B-11d1-BE77-006008317CE8} 257 | DEFINE_GUID(CLSID_TimeControl, 258 | 0x53961a06, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 259 | 260 | // {53961A07-459B-11d1-BE77-006008317CE8} 261 | DEFINE_GUID(CLSID_RecordControl, 262 | 0x53961a07, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 263 | 264 | // {53961A08-459B-11d1-BE77-006008317CE8} 265 | DEFINE_GUID(CLSID_SpellingControl, 266 | 0x53961a08, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 267 | 268 | // {53961A09-459B-11d1-BE77-006008317CE8} 269 | DEFINE_GUID(CLSID_NameControl, 270 | 0x53961a09, 0x459b, 0x11d1, 0xbe, 0x77, 0x0, 0x60, 0x8, 0x31, 0x7c, 0xe8); 271 | 272 | 273 | 274 | /************************************************************************** 275 | Sample telephony controls GUIDs. These samples appear in the SDK. */ 276 | // {C869F0DE-EF29-11d0-8FAD-08002BE4E62A} 277 | DEFINE_GUID(CLSID_SampleYesNoControl, 278 | 0xc869f0de, 0xef29, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 279 | 280 | // {9DE44BA9-F94A-11d0-8FAD-08002BE4E62A} 281 | DEFINE_GUID(CLSID_SampleExtensionControl, 282 | 0x9de44ba9, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 283 | 284 | // {9DE44BAA-F94A-11d0-8FAD-08002BE4E62A} 285 | DEFINE_GUID(CLSID_SamplePhoneNumControl, 286 | 0x9de44baa, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 287 | 288 | // {9DE44BAB-F94A-11d0-8FAD-08002BE4E62A} 289 | DEFINE_GUID(CLSID_SampleGrammarControl, 290 | 0x9de44bab, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 291 | 292 | // {9DE44BAC-F94A-11d0-8FAD-08002BE4E62A} 293 | DEFINE_GUID(CLSID_SampleDateControl, 294 | 0x9de44bac, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 295 | 296 | // {9DE44BAD-F94A-11d0-8FAD-08002BE4E62A} 297 | DEFINE_GUID(CLSID_SampleTimeControl, 298 | 0x9de44bad, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 299 | 300 | // {275931C6-FD27-11d0-8FAE-08002BE4E62A} 301 | DEFINE_GUID(CLSID_SampleRecordControl, 302 | 0x275931c6, 0xfd27, 0x11d0, 0x8f, 0xae, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 303 | 304 | // {9DE44BAE-F94A-11d0-8FAD-08002BE4E62A} 305 | DEFINE_GUID(CLSID_SampleSpellingControl, 306 | 0x9de44bae, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 307 | 308 | // {9DE44BAF-F94A-11d0-8FAD-08002BE4E62A} 309 | DEFINE_GUID(CLSID_SampleNameControl, 310 | 0x9de44baf, 0xf94a, 0x11d0, 0x8f, 0xad, 0x8, 0x0, 0x2b, 0xe4, 0xe6, 0x2a); 311 | 312 | 313 | #endif // _SPCHTEL_H_ -------------------------------------------------------------------------------- /Sapi4/Lib/spchwrap.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/Sapi4/Lib/spchwrap.lib -------------------------------------------------------------------------------- /UGlobalHotkey/.gitignore: -------------------------------------------------------------------------------- 1 | # C++ objects and libs 2 | 3 | *.slo 4 | *.lo 5 | *.o 6 | *.a 7 | *.la 8 | *.lai 9 | *.so 10 | *.dll 11 | *.dylib 12 | 13 | # Qt-es 14 | 15 | *.pro.user 16 | *.pro.user.* 17 | moc_*.cpp 18 | qrc_*.cpp 19 | Makefile 20 | *-build-* 21 | build 22 | build* 23 | *build 24 | -------------------------------------------------------------------------------- /UGlobalHotkey/.qmake.stash: -------------------------------------------------------------------------------- 1 | QMAKE_CXX.INCDIRS = \ 2 | "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Tools\\MSVC\\14.15.26726\\ATLMFC\\include" \ 3 | "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Tools\\MSVC\\14.15.26726\\include" \ 4 | "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\include\\um" \ 5 | "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\ucrt" \ 6 | "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\shared" \ 7 | "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\um" \ 8 | "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\winrt" \ 9 | "C:\\Program Files (x86)\\Windows Kits\\10\\include\\10.0.17134.0\\cppwinrt" 10 | QMAKE_CXX.LIBDIRS = \ 11 | "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Tools\\MSVC\\14.15.26726\\ATLMFC\\lib\\x86" \ 12 | "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Enterprise\\VC\\Tools\\MSVC\\14.15.26726\\lib\\x86" \ 13 | "C:\\Program Files (x86)\\Windows Kits\\NETFXSDK\\4.6.1\\lib\\um\\x86" \ 14 | "C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17134.0\\ucrt\\x86" \ 15 | "C:\\Program Files (x86)\\Windows Kits\\10\\lib\\10.0.17134.0\\um\\x86" 16 | QMAKE_CXX.QT_COMPILER_STDCXX = 199711L 17 | QMAKE_CXX.QMAKE_MSC_VER = 1915 18 | QMAKE_CXX.QMAKE_MSC_FULL_VER = 191526730 19 | QMAKE_CXX.COMPILER_MACROS = \ 20 | QT_COMPILER_STDCXX \ 21 | QMAKE_MSC_VER \ 22 | QMAKE_MSC_FULL_VER 23 | -------------------------------------------------------------------------------- /UGlobalHotkey/README.md: -------------------------------------------------------------------------------- 1 | ## UGlobalHotkey 2 | 3 | ### Decription 4 | UGlobalHotkey is an extension for Qt framework, which implements global hotkeys functionality for Windows Linux and MacOSX platforms. 5 | It is written by [bakwc](https://github.com/bakwc), extracted from [Pastexen](https://github.com/bakwc/Pastexen) and turned into a shared library by me. 6 | 7 | ### Building from source 8 | * You can either open project with QtCreator and press Build button 9 | * Or build it using terminal: 10 | ``` 11 | qmake 12 | make 13 | ``` 14 | 15 | ### Usage example 16 | ``` 17 | UGlobalHotkeys *hotkeyManager = new UGlobalHotkeys(); 18 | hotkeyManager->RegisterHotkey("Ctrl+Shift+F12"); 19 | connect(hotkeyManager, &UGlobalHotkeys::Activated, [=](size_t id) 20 | { 21 | qDebug() << "Activated: " << QString::number(id); 22 | }); 23 | ``` 24 | 25 | ### License 26 | UGlobalHotkey library is licensed as Public Domain, so you are free to do anything with it. -------------------------------------------------------------------------------- /UGlobalHotkey/hotkeymap.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(Q_OS_WIN) 4 | inline size_t QtKeyToWin(size_t key) { 5 | // TODO: other maping or full keys list 6 | 7 | if (key >= 0x01000030 && key <= 0x01000047) { 8 | return VK_F1 + (key - Qt::Key_F1); 9 | } 10 | 11 | return key; 12 | } 13 | #elif defined(Q_OS_LINUX) 14 | #include "ukeysequence.h" 15 | #include "xcb/xcb.h" 16 | #include "xcb/xcb_keysyms.h" 17 | #include "X11/keysym.h" 18 | 19 | struct UKeyData { 20 | int key; 21 | int mods; 22 | }; 23 | 24 | inline UKeyData QtKeyToLinux(const UKeySequence &keySeq) 25 | { 26 | UKeyData data = {0, 0}; 27 | 28 | auto key = keySeq.GetSimpleKeys(); 29 | if (key.size() > 0) 30 | data.key = key[0]; 31 | else 32 | throw UException("Invalid hotkey"); 33 | 34 | // Key conversion 35 | // Qt's F keys need conversion 36 | if (data.key >= Qt::Key_F1 && data.key <= Qt::Key_F35) { 37 | const size_t DIFF = Qt::Key_F1 - XK_F1; 38 | data.key -= DIFF; 39 | } else if (data.key >= Qt::Key_Space && data.key <= Qt::Key_QuoteLeft) { 40 | // conversion is not necessary, if the value in the range Qt::Key_Space - Qt::Key_QuoteLeft 41 | } else { 42 | throw UException("Invalid hotkey: key conversion is not defined"); 43 | } 44 | 45 | // Modifiers conversion 46 | auto mods = keySeq.GetModifiers(); 47 | 48 | for (auto i : mods) { 49 | if (i == Qt::Key_Shift) 50 | data.mods |= XCB_MOD_MASK_SHIFT; 51 | else if (i == Qt::Key_Control) 52 | data.mods |= XCB_MOD_MASK_CONTROL; 53 | else if (i == Qt::Key_Alt) 54 | data.mods |= XCB_MOD_MASK_1; 55 | else if (i == Qt::Key_Meta) 56 | data.mods |= XCB_MOD_MASK_4; // ! 57 | } 58 | 59 | return data; 60 | } 61 | #elif defined(Q_OS_MAC) 62 | 63 | #include "ukeysequence.h" 64 | #include 65 | #include 66 | 67 | struct UKeyData { 68 | uint32_t key; 69 | uint32_t mods; 70 | }; 71 | 72 | static std::unordered_map KEY_MAP = { 73 | {Qt::Key_A, kVK_ANSI_A}, 74 | {Qt::Key_B, kVK_ANSI_B}, 75 | {Qt::Key_C, kVK_ANSI_C}, 76 | {Qt::Key_D, kVK_ANSI_D}, 77 | {Qt::Key_E, kVK_ANSI_E}, 78 | {Qt::Key_F, kVK_ANSI_F}, 79 | {Qt::Key_G, kVK_ANSI_G}, 80 | {Qt::Key_H, kVK_ANSI_H}, 81 | {Qt::Key_I, kVK_ANSI_I}, 82 | {Qt::Key_J, kVK_ANSI_J}, 83 | {Qt::Key_K, kVK_ANSI_K}, 84 | {Qt::Key_L, kVK_ANSI_L}, 85 | {Qt::Key_M, kVK_ANSI_M}, 86 | {Qt::Key_N, kVK_ANSI_N}, 87 | {Qt::Key_O, kVK_ANSI_O}, 88 | {Qt::Key_P, kVK_ANSI_P}, 89 | {Qt::Key_Q, kVK_ANSI_Q}, 90 | {Qt::Key_R, kVK_ANSI_R}, 91 | {Qt::Key_S, kVK_ANSI_S}, 92 | {Qt::Key_T, kVK_ANSI_T}, 93 | {Qt::Key_U, kVK_ANSI_U}, 94 | {Qt::Key_V, kVK_ANSI_V}, 95 | {Qt::Key_W, kVK_ANSI_W}, 96 | {Qt::Key_X, kVK_ANSI_X}, 97 | {Qt::Key_Y, kVK_ANSI_Y}, 98 | {Qt::Key_Z, kVK_ANSI_Z}, 99 | {Qt::Key_0, kVK_ANSI_0}, 100 | {Qt::Key_1, kVK_ANSI_1}, 101 | {Qt::Key_2, kVK_ANSI_2}, 102 | {Qt::Key_3, kVK_ANSI_3}, 103 | {Qt::Key_4, kVK_ANSI_4}, 104 | {Qt::Key_5, kVK_ANSI_5}, 105 | {Qt::Key_6, kVK_ANSI_6}, 106 | {Qt::Key_7, kVK_ANSI_7}, 107 | {Qt::Key_8, kVK_ANSI_8}, 108 | {Qt::Key_9, kVK_ANSI_9}, 109 | {Qt::Key_F1, kVK_F1}, 110 | {Qt::Key_F2, kVK_F2}, 111 | {Qt::Key_F3, kVK_F3}, 112 | {Qt::Key_F4, kVK_F4}, 113 | {Qt::Key_F5, kVK_F5}, 114 | {Qt::Key_F6, kVK_F6}, 115 | {Qt::Key_F7, kVK_F7}, 116 | {Qt::Key_F8, kVK_F8}, 117 | {Qt::Key_F9, kVK_F9}, 118 | {Qt::Key_F10, kVK_F10}, 119 | {Qt::Key_F11, kVK_F11}, 120 | {Qt::Key_F12, kVK_F12}, 121 | {Qt::Key_F13, kVK_F13}, 122 | {Qt::Key_F14, kVK_F14}, 123 | }; 124 | 125 | static std::unordered_map MOD_MAP = { 126 | {Qt::Key_Shift, shiftKey}, 127 | {Qt::Key_Alt, optionKey}, 128 | {Qt::Key_Control, controlKey}, 129 | {Qt::Key_Option, optionKey}, 130 | {Qt::Key_Meta, cmdKey}, 131 | }; 132 | 133 | inline UKeyData QtKeyToMac(const UKeySequence &keySeq) { 134 | UKeyData data = {0, 0}; 135 | auto key = keySeq.GetSimpleKeys(); 136 | auto mods = keySeq.GetModifiers(); 137 | if (key.size() == 1 && KEY_MAP.find(key[0]) != KEY_MAP.end()) 138 | data.key = KEY_MAP[key[0]]; 139 | else 140 | throw UException("Invalid hotkey"); 141 | for (auto&& mod: mods) { 142 | if (MOD_MAP.find(mod) == MOD_MAP.end()) 143 | throw UException("Invalid hotkey"); 144 | data.mods += MOD_MAP[mod]; 145 | } 146 | return data; 147 | } 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /UGlobalHotkey/uexception.cpp: -------------------------------------------------------------------------------- 1 | #include "uexception.h" 2 | 3 | UException::UException(const QString& message) throw() 4 | : Message(message.toLocal8Bit()) 5 | { 6 | } 7 | 8 | UException::~UException() throw () { 9 | } 10 | 11 | const char* UException::what() const throw () { 12 | return Message.data(); 13 | } 14 | -------------------------------------------------------------------------------- /UGlobalHotkey/uexception.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "uglobal.h" 7 | 8 | class UGLOBALHOTKEY_EXPORT UException : public std::exception 9 | { 10 | public: 11 | UException(const QString& message) throw(); 12 | const char* what() const throw(); 13 | ~UException() throw (); 14 | private: 15 | QByteArray Message; 16 | }; 17 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobal.h: -------------------------------------------------------------------------------- 1 | #ifndef UGLOBAL_H 2 | #define UGLOBAL_H 3 | 4 | #include 5 | 6 | #if defined(UGLOBALHOTKEY_LIBRARY) 7 | # define UGLOBALHOTKEY_EXPORT Q_DECL_EXPORT 8 | #elif defined(UGLOBALHOTKEY_NOEXPORT) 9 | # define UGLOBALHOTKEY_EXPORT 10 | #else 11 | # define UGLOBALHOTKEY_EXPORT Q_DECL_IMPORT 12 | #endif 13 | 14 | #endif // UGLOBAL_H 15 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey-headers.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD/ 2 | 3 | HEADERS += \ 4 | $$PWD/ukeysequence.h \ 5 | $$PWD/uglobalhotkeys.h \ 6 | $$PWD/uexception.h \ 7 | $$PWD/hotkeymap.h \ 8 | $$PWD/uglobal.h 9 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey-libs.pri: -------------------------------------------------------------------------------- 1 | # Linking options for different platforms 2 | 3 | linux: LIBS += -lxcb -lxcb-keysyms 4 | mac: LIBS += -framework Carbon 5 | 6 | windows { 7 | *-g++* { 8 | LIBS += -luser32 9 | } 10 | *-msvc* { 11 | LIBS += user32.lib 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey-sources.pri: -------------------------------------------------------------------------------- 1 | INCLUDEPATH += $$PWD/ 2 | 3 | QT += gui-private 4 | 5 | SOURCES += \ 6 | $$PWD/ukeysequence.cpp \ 7 | $$PWD/uglobalhotkeys.cpp \ 8 | $$PWD/uexception.cpp 9 | 10 | 11 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey.pri: -------------------------------------------------------------------------------- 1 | # Switch ABI to no-export mode (vs import, which is default) 2 | DEFINES += UGLOBALHOTKEY_NOEXPORT 3 | include(uglobalhotkey-headers.pri) 4 | include(uglobalhotkey-sources.pri) 5 | include(uglobalhotkey-libs.pri) 6 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey.pro: -------------------------------------------------------------------------------- 1 | QT = core gui 2 | unix { 3 | QT += gui-private 4 | } 5 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 6 | 7 | TARGET = UGlobalHotkey 8 | TEMPLATE = lib 9 | CONFIG += c++11 10 | 11 | # Switch ABI to export (vs import, which is default) 12 | DEFINES += UGLOBALHOTKEY_LIBRARY 13 | 14 | include(uglobalhotkey-headers.pri) 15 | include(uglobalhotkey-sources.pri) 16 | include(uglobalhotkey-libs.pri) 17 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2041 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uglobalhotkey", "uglobalhotkey.vcxproj", "{E647D210-1860-340F-A7B7-4137A60B2483}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x86 = Debug|x86 11 | Release|x86 = Release|x86 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {E647D210-1860-340F-A7B7-4137A60B2483}.Debug|x86.ActiveCfg = Debug|Win32 15 | {E647D210-1860-340F-A7B7-4137A60B2483}.Debug|x86.Build.0 = Debug|Win32 16 | {E647D210-1860-340F-A7B7-4137A60B2483}.Release|x86.ActiveCfg = Release|Win32 17 | {E647D210-1860-340F-A7B7-4137A60B2483}.Release|x86.Build.0 = Release|Win32 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {67AAD6EA-DDA8-4035-BDD8-7E39F2C181E9} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | Win32 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | 14 | {E647D210-1860-340F-A7B7-4137A60B2483} 15 | UGlobalHotkey 16 | Qt4VSv1.0 17 | 7.0 18 | 10.0.17134.0 19 | 20 | 21 | 22 | v140_xp 23 | release\ 24 | false 25 | NotSet 26 | DynamicLibrary 27 | release\ 28 | UGlobalHotkey 29 | 30 | 31 | v140_xp 32 | debug\ 33 | false 34 | NotSet 35 | DynamicLibrary 36 | debug\ 37 | UGlobalHotkey 38 | 39 | 40 | 41 | $(MSBuildProjectDirectory)\QtMsBuild 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | $(SolutionDir)$(Platform)\$(Configuration)\ 59 | $(Configuration)\ 60 | UGlobalHotkey 61 | true 62 | false 63 | $(SolutionDir)$(Platform)\$(Configuration)\ 64 | $(Configuration)\ 65 | UGlobalHotkey 66 | true 67 | 68 | 69 | 70 | .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(QTDIR)\include;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtGui\5.11.2;$(QTDIR)\include\QtGui\5.11.2\QtGui;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtCore\5.11.2;$(QTDIR)\include\QtCore\5.11.2\QtCore;$(QTDIR)\include\QtCore;release;\include;$(QTDIR)\mkspecs\win32-msvc;%(AdditionalIncludeDirectories) 71 | -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) 72 | release\ 73 | false 74 | None 75 | 4577;4467;%(DisableSpecificWarnings) 76 | Sync 77 | $(IntDir) 78 | MaxSpeed 79 | _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;NDEBUG;%(PreprocessorDefinitions) 80 | false 81 | $(IntDir)vc$(PlatformToolsetVersion).pdb 82 | MultiThreadedDLL 83 | true 84 | true 85 | Level3 86 | true 87 | 88 | 89 | user32.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Core.lib;%(AdditionalDependencies) 90 | $(QTDIR)\lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories) 91 | true 92 | false 93 | true 94 | true 95 | false 96 | $(OutDir)\UGlobalHotkey.dll 97 | true 98 | Windows 99 | true 100 | 101 | 102 | Unsigned 103 | None 104 | 0 105 | 106 | 107 | _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) 108 | 109 | 110 | $(QTDIR) 111 | $(Configuration)\moc_%(Filename).cpp 112 | UNICODE;_UNICODE;$(Platform);_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_NO_DEBUG;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB 113 | msvc 114 | ./$(Configuration)/moc_predefs.h 115 | Moc'ing %(Identity)... 116 | %(FullPath) 117 | output 118 | .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;$(QTDIR)\mkspecs/$(Platform)-msvc;.;$(QTDIR)\include;$(QTDIR)\include/QtWidgets;$(QTDIR)\include/QtGui/5.11.2;$(QTDIR)\include/QtGui/5.11.2/QtGui;$(QTDIR)\include/QtGui;$(QTDIR)\include/QtANGLE;$(QTDIR)\include/QtCore/5.11.2;$(QTDIR)\include/QtCore/5.11.2/QtCore;$(QTDIR)\include/QtCore;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\ATLMFC\include;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\include;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\cppwinrt 119 | 120 | 121 | 122 | 123 | .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;.;$(QTDIR)\include;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtGui\5.11.2;$(QTDIR)\include\QtGui\5.11.2\QtGui;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtCore\5.11.2;$(QTDIR)\include\QtCore\5.11.2\QtCore;$(QTDIR)\include\QtCore;debug;\include;$(QTDIR)\mkspecs\win32-msvc;%(AdditionalIncludeDirectories) 124 | -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 %(AdditionalOptions) 125 | debug\ 126 | false 127 | ProgramDatabase 128 | 4577;4467;%(DisableSpecificWarnings) 129 | Sync 130 | $(IntDir) 131 | Disabled 132 | _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;%(PreprocessorDefinitions) 133 | false 134 | MultiThreadedDebugDLL 135 | true 136 | true 137 | Level3 138 | true 139 | $(IntDir)vc$(PlatformToolsetVersion).pdb 140 | 141 | 142 | user32.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Cored.lib;%(AdditionalDependencies) 143 | $(QTDIR)\lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories) 144 | true 145 | true 146 | true 147 | true 148 | $(OutDir)\UGlobalHotkey.dll 149 | true 150 | Windows 151 | true 152 | 153 | 154 | Unsigned 155 | None 156 | 0 157 | 158 | 159 | _WINDOWS;UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB;_DEBUG;%(PreprocessorDefinitions) 160 | 161 | 162 | $(QTDIR) 163 | $(Configuration)\moc_%(Filename).cpp 164 | UNICODE;_UNICODE;$(Platform);_ENABLE_EXTENDED_ALIGNED_STORAGE;UGLOBALHOTKEY_LIBRARY;QT_WIDGETS_LIB;QT_GUI_LIB;QT_CORE_LIB 165 | msvc 166 | ./$(Configuration)/moc_predefs.h 167 | Moc'ing %(Identity)... 168 | %(FullPath) 169 | output 170 | .\GeneratedFiles\$(ConfigurationName);.\GeneratedFiles;$(QTDIR)\mkspecs/$(Platform)-msvc;.;$(QTDIR)\include;$(QTDIR)\include/QtWidgets;$(QTDIR)\include/QtGui/5.11.2;$(QTDIR)\include/QtGui/5.11.2/QtGui;$(QTDIR)\include/QtGui;$(QTDIR)\include/QtANGLE;$(QTDIR)\include/QtCore/5.11.2;$(QTDIR)\include/QtCore/5.11.2/QtCore;$(QTDIR)\include/QtCore;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\ATLMFC\include;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Tools\MSVC\14.15.26726\include;C:\Program Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.17134.0\cppwinrt 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | Document 190 | true 191 | $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) 192 | cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -Zi -MDd -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >debug\moc_predefs.h 193 | Generate moc_predefs.h 194 | debug\moc_predefs.h;%(Outputs) 195 | 196 | 197 | Document 198 | $(QTDIR)\mkspecs\features\data\dummy.cpp;%(AdditionalInputs) 199 | cl -Bx"$(QTDIR)\bin\qmake.exe" -nologo -Zc:wchar_t -FS -Zc:rvalueCast -Zc:inline -Zc:strictStrings -Zc:throwingNew -Zc:referenceBinding -Zc:__cplusplus -O2 -MD -W3 -w34100 -w34189 -w44996 -w44456 -w44457 -w44458 -wd4577 -wd4467 -E $(QTDIR)\mkspecs\features\data\dummy.cpp 2>NUL >release\moc_predefs.h 200 | Generate moc_predefs.h 201 | release\moc_predefs.h;%(Outputs) 202 | true 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkey.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 6 | cpp;c;cxx;moc;h;def;odl;idl;res; 7 | 8 | 9 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 10 | cpp;c;cxx;moc;h;def;odl;idl;res; 11 | 12 | 13 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 14 | h;hpp;hxx;hm;inl;inc;xsd 15 | 16 | 17 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 18 | h;hpp;hxx;hm;inl;inc;xsd 19 | 20 | 21 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 22 | cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx 23 | 24 | 25 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 26 | cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx 27 | 28 | 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | 41 | 42 | Header Files 43 | 44 | 45 | Header Files 46 | 47 | 48 | Header Files 49 | 50 | 51 | Header Files 52 | 53 | 54 | Header Files 55 | 56 | 57 | 58 | 59 | Generated Files 60 | 61 | 62 | Generated Files 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkeys.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #if defined(Q_OS_WIN) 3 | #include 4 | #elif defined(Q_OS_LINUX) 5 | #include 6 | #include 7 | #include 8 | #endif 9 | 10 | #include "hotkeymap.h" 11 | #include "uglobalhotkeys.h" 12 | 13 | UGlobalHotkeys::UGlobalHotkeys(QWidget *parent) 14 | : QWidget(parent) 15 | { 16 | #if defined(Q_OS_LINUX) 17 | qApp->installNativeEventFilter(this); 18 | QWindow wndw; 19 | void* v = qApp->platformNativeInterface()->nativeResourceForWindow("connection", &wndw); 20 | X11Connection = (xcb_connection_t*)v; 21 | X11Wid = xcb_setup_roots_iterator(xcb_get_setup(X11Connection)).data->root; 22 | X11KeySymbs = xcb_key_symbols_alloc(X11Connection); 23 | #endif 24 | } 25 | 26 | void UGlobalHotkeys::registerHotkey(const QString& keySeq, size_t id) { 27 | registerHotkey(UKeySequence(keySeq), id); 28 | } 29 | 30 | #if defined(Q_OS_MAC) 31 | OSStatus macHotkeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { 32 | Q_UNUSED(nextHandler); 33 | EventHotKeyID hkCom; 34 | GetEventParameter(theEvent,kEventParamDirectObject,typeEventHotKeyID,NULL, 35 | sizeof(hkCom),NULL,&hkCom); 36 | size_t id = hkCom.id; 37 | 38 | UGlobalHotkeys* caller = (UGlobalHotkeys*)userData; 39 | caller->onHotkeyPressed(id); 40 | return noErr; 41 | } 42 | #endif 43 | 44 | void UGlobalHotkeys::registerHotkey(const UKeySequence& keySeq, size_t id) { 45 | if (keySeq.Size() == 0) { 46 | throw UException("Empty hotkeys"); 47 | } 48 | #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) 49 | if (Registered.find(id) != Registered.end()) { 50 | unregisterHotkey(id); 51 | } 52 | #endif 53 | #if defined(Q_OS_WIN) 54 | size_t winMod = 0; 55 | size_t key = VK_F2; 56 | 57 | for (size_t i = 0; i != keySeq.Size(); i++) { 58 | if (keySeq[i] == Qt::Key_Control) { 59 | winMod |= MOD_CONTROL; 60 | } else if (keySeq[i] == Qt::Key_Alt) { 61 | winMod |= MOD_ALT; 62 | } else if (keySeq[i] == Qt::Key_Shift) { 63 | winMod |= MOD_SHIFT; 64 | } else if (keySeq[i] == Qt::Key_Meta) { 65 | winMod |= MOD_WIN; 66 | } else { 67 | key = QtKeyToWin(keySeq[i]); 68 | } 69 | } 70 | 71 | if (!RegisterHotKey((HWND)winId(), id, winMod, key)) { 72 | qDebug() << "Error activating hotkey!"; 73 | } else { 74 | Registered.insert(id); 75 | } 76 | #elif defined(Q_OS_LINUX) 77 | regLinuxHotkey(keySeq, id); 78 | #endif 79 | #if defined(Q_OS_MAC) 80 | unregisterHotkey(id); 81 | 82 | EventHotKeyRef gMyHotKeyRef; 83 | EventHotKeyID gMyHotKeyID; 84 | EventTypeSpec eventType; 85 | eventType.eventClass=kEventClassKeyboard; 86 | eventType.eventKind=kEventHotKeyPressed; 87 | 88 | InstallApplicationEventHandler(&macHotkeyHandler, 1, &eventType, this, NULL); 89 | 90 | gMyHotKeyID.signature = uint32_t(id); 91 | gMyHotKeyID.id=uint32_t(id); 92 | 93 | UKeyData macKey = QtKeyToMac(keySeq); 94 | 95 | RegisterEventHotKey(macKey.key, macKey.mods, gMyHotKeyID, 96 | GetApplicationEventTarget(), 0, &gMyHotKeyRef); 97 | 98 | HotkeyRefs[id] = gMyHotKeyRef; 99 | 100 | #endif 101 | } 102 | 103 | void UGlobalHotkeys::unregisterHotkey(size_t id) { 104 | #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) 105 | Q_ASSERT(Registered.find(id) != Registered.end() && "Unregistered hotkey"); 106 | #endif 107 | #if defined(Q_OS_WIN) 108 | UnregisterHotKey((HWND)winId(), id); 109 | #elif defined(Q_OS_LINUX) 110 | unregLinuxHotkey(id); 111 | #endif 112 | #if defined(Q_OS_WIN) || defined(Q_OS_LINUX) 113 | Registered.remove(id); 114 | #endif 115 | #if defined(Q_OS_MAC) 116 | if (HotkeyRefs.find(id) != HotkeyRefs.end()) { 117 | UnregisterEventHotKey(HotkeyRefs[id]); 118 | } 119 | #endif 120 | } 121 | 122 | void UGlobalHotkeys::unregisterAllHotkeys() 123 | { 124 | #ifdef Q_OS_WIN 125 | QSet Temp = Registered; 126 | for (size_t id : Temp) 127 | this->unregisterHotkey(id); 128 | #elif defined(Q_OS_LINUX) 129 | for (size_t id :Registered.keys()) 130 | this->unregisterHotkey(id); 131 | #endif 132 | } 133 | 134 | UGlobalHotkeys::~UGlobalHotkeys() { 135 | #if defined(Q_OS_WIN) 136 | for (QSet::iterator i = Registered.begin(); i != Registered.end(); i++) { 137 | UnregisterHotKey((HWND)winId(), *i); 138 | } 139 | #elif defined(Q_OS_LINUX) 140 | xcb_key_symbols_free(X11KeySymbs); 141 | #endif 142 | } 143 | 144 | #if defined(Q_OS_MAC) 145 | void UGlobalHotkeys::onHotkeyPressed(size_t id) { 146 | emit activated(id); 147 | } 148 | #endif 149 | 150 | #if defined(Q_OS_WIN) 151 | bool UGlobalHotkeys::winEvent(MSG * message, long * result) { 152 | Q_UNUSED(result); 153 | if (message->message == WM_HOTKEY) { 154 | size_t id = message->wParam; 155 | Q_ASSERT(Registered.find(id) != Registered.end() && "Unregistered hotkey"); 156 | emit activated(id); 157 | } 158 | return false; 159 | } 160 | 161 | bool UGlobalHotkeys::nativeEvent(const QByteArray &eventType, 162 | void *message, long *result) 163 | { 164 | Q_UNUSED(eventType); 165 | return winEvent((MSG*)message, result); 166 | } 167 | 168 | #elif defined(Q_OS_LINUX) 169 | 170 | bool UGlobalHotkeys::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { 171 | Q_UNUSED(eventType); 172 | Q_UNUSED(result); 173 | return linuxEvent(static_cast(message)); 174 | } 175 | 176 | bool UGlobalHotkeys::linuxEvent(xcb_generic_event_t *message) 177 | { 178 | if ( (message->response_type & ~0x80) == XCB_KEY_PRESS ) { 179 | xcb_key_press_event_t *ev = (xcb_key_press_event_t*)message; 180 | auto ind = Registered.key( {ev->detail, (ev->state & ~XCB_MOD_MASK_2)} ); 181 | 182 | if (ind == 0) // this is not hotkeys 183 | return false; 184 | 185 | emit activated(ind); 186 | return true; 187 | } 188 | return false; 189 | } 190 | 191 | void UGlobalHotkeys::regLinuxHotkey(const UKeySequence &keySeq, size_t id) 192 | { 193 | UHotkeyData data; 194 | UKeyData keyData = QtKeyToLinux(keySeq); 195 | 196 | xcb_keycode_t *keyC = xcb_key_symbols_get_keycode(X11KeySymbs, keyData.key); 197 | 198 | data.keyCode = *keyC; 199 | data.mods = keyData.mods; 200 | 201 | xcb_grab_key(X11Connection, 1, X11Wid, data.mods, data.keyCode, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 202 | // NumLk 203 | xcb_grab_key(X11Connection, 1, X11Wid, data.mods | XCB_MOD_MASK_2, data.keyCode,XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC); 204 | 205 | Registered.insert(id, data); 206 | } 207 | 208 | void UGlobalHotkeys::unregLinuxHotkey(size_t id) 209 | { 210 | UHotkeyData data = Registered.take(id); 211 | xcb_ungrab_key(X11Connection, data.keyCode, X11Wid, data.mods); 212 | xcb_ungrab_key(X11Connection, data.keyCode, X11Wid, data.mods | XCB_MOD_MASK_2); 213 | } 214 | #endif 215 | -------------------------------------------------------------------------------- /UGlobalHotkey/uglobalhotkeys.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if defined(Q_OS_LINUX) 8 | #include "xcb/xcb.h" 9 | #include "xcb/xcb_keysyms.h" 10 | #elif defined(Q_OS_MAC) 11 | #include 12 | #endif 13 | 14 | #include "ukeysequence.h" 15 | #include "uexception.h" 16 | #include "uglobal.h" 17 | 18 | #if defined(Q_OS_LINUX) 19 | struct UHotkeyData { 20 | xcb_keycode_t keyCode; 21 | int mods; 22 | bool operator ==(const UHotkeyData& data) const { 23 | return data.keyCode == this->keyCode && data.mods == this->mods; 24 | } 25 | }; 26 | #endif 27 | 28 | class UGLOBALHOTKEY_EXPORT UGlobalHotkeys : public QWidget 29 | #if defined(Q_OS_LINUX) 30 | , public QAbstractNativeEventFilter 31 | #endif 32 | { 33 | Q_OBJECT 34 | public: 35 | explicit UGlobalHotkeys(QWidget *parent = 0); 36 | void registerHotkey(const QString& keySeq, size_t id = 1); 37 | void registerHotkey(const UKeySequence& keySeq, size_t id = 1); 38 | void unregisterHotkey(size_t id = 1); 39 | void unregisterAllHotkeys(); 40 | ~UGlobalHotkeys(); 41 | protected: 42 | #if defined(Q_OS_WIN) 43 | bool winEvent (MSG * message, long * result); 44 | bool nativeEvent(const QByteArray &eventType, void *message, long *result); 45 | #elif defined(Q_OS_LINUX) 46 | bool nativeEventFilter(const QByteArray &eventType, void *message, long *result); 47 | bool linuxEvent(xcb_generic_event_t *message); 48 | void regLinuxHotkey(const UKeySequence& keySeq, size_t id); 49 | void unregLinuxHotkey(size_t id); 50 | #endif 51 | public: 52 | #if defined (Q_OS_MAC) 53 | void onHotkeyPressed(size_t id); 54 | #endif 55 | signals: 56 | void activated(size_t id); 57 | private: 58 | #if defined(Q_OS_WIN) 59 | QSet Registered; 60 | #elif defined(Q_OS_LINUX) 61 | QHash Registered; 62 | xcb_connection_t* X11Connection; 63 | xcb_window_t X11Wid; 64 | xcb_key_symbols_t* X11KeySymbs; 65 | #elif defined(Q_OS_MAC) 66 | QHash HotkeyRefs; 67 | #endif 68 | }; 69 | -------------------------------------------------------------------------------- /UGlobalHotkey/ukeysequence.cpp: -------------------------------------------------------------------------------- 1 | #include "ukeysequence.h" 2 | 3 | #include 4 | 5 | UKeySequence::UKeySequence(QObject *parent) 6 | : QObject(parent) 7 | { 8 | } 9 | 10 | UKeySequence::UKeySequence(const QString& str, QObject *parent) 11 | : QObject(parent) 12 | { 13 | FromString(str); 14 | } 15 | 16 | bool IsModifier(int key) { 17 | return (key == Qt::Key_Shift || 18 | key == Qt::Key_Control || 19 | key == Qt::Key_Alt || 20 | key == Qt::Key_Meta); 21 | } 22 | 23 | static QString KeyToStr(int key) { 24 | if (key == Qt::Key_Shift) { 25 | return "Shift"; 26 | } 27 | if (key == Qt::Key_Control) { 28 | return "Ctrl"; 29 | } 30 | if (key == Qt::Key_Alt) { 31 | return "Alt"; 32 | } 33 | if (key == Qt::Key_Meta) { 34 | return "Meta"; 35 | } 36 | QKeySequence seq(key); 37 | return seq.toString(); 38 | } 39 | 40 | void UKeySequence::FromString(const QString& str) { 41 | QStringList keys = str.split('+'); 42 | for (int i = 0; i < keys.size(); i++) { 43 | AddKey(keys[i]); 44 | } 45 | } 46 | 47 | QString UKeySequence::ToString() { 48 | QVector simpleKeys = GetSimpleKeys(); 49 | QVector modifiers = GetModifiers(); 50 | QStringList result; 51 | for (int i = 0; i < modifiers.size(); i++) { 52 | result.push_back(KeyToStr(modifiers[i])); 53 | } 54 | for (int i = 0; i < simpleKeys.size(); i++) { 55 | result.push_back(KeyToStr(simpleKeys[i])); 56 | } 57 | return result.join('+'); 58 | } 59 | 60 | QVector UKeySequence::GetSimpleKeys() const { 61 | QVector result; 62 | for (int i = 0; i < Keys.size(); i++) { 63 | if (!IsModifier(Keys[i])) { 64 | result.push_back(Keys[i]); 65 | } 66 | } 67 | return result; 68 | } 69 | 70 | QVector UKeySequence::GetModifiers() const { 71 | QVector result; 72 | for (int i = 0; i < Keys.size(); i++) { 73 | if (IsModifier(Keys[i])) { 74 | result.push_back(Keys[i]); 75 | } 76 | } 77 | return result; 78 | } 79 | 80 | void UKeySequence::AddModifiers(Qt::KeyboardModifiers mod) { 81 | if (mod == Qt::NoModifier) { 82 | return; 83 | } 84 | if (mod & Qt::ShiftModifier) { 85 | AddKey(Qt::Key_Shift); 86 | } 87 | if (mod & Qt::ControlModifier) { 88 | AddKey(Qt::Key_Control); 89 | } 90 | if (mod & Qt::AltModifier) { 91 | AddKey(Qt::Key_Alt); 92 | } 93 | if (mod & Qt::MetaModifier) { 94 | AddKey(Qt::Key_Meta); 95 | } 96 | } 97 | 98 | void UKeySequence::AddKey(const QString& key) { 99 | if (key.contains("+") || key.contains(",")) { 100 | throw UException("Wrong key"); 101 | } 102 | 103 | QString mod = key.toLower(); 104 | qDebug() << "mod: " << mod; 105 | if (mod == "alt") { 106 | AddKey(Qt::Key_Alt); 107 | return; 108 | } 109 | if (mod == "shift" || mod == "shft") { 110 | AddKey(Qt::Key_Shift); 111 | return; 112 | } 113 | if (mod == "control" || mod == "ctrl") { 114 | AddKey(Qt::Key_Control); 115 | return; 116 | } 117 | if (mod == "win" || mod == "meta") { 118 | AddKey(Qt::Key_Meta); 119 | return; 120 | } 121 | QKeySequence seq(key); 122 | if (seq.count() != 1) { 123 | throw UException("Wrong key"); 124 | } 125 | AddKey(seq[0]); 126 | } 127 | 128 | void UKeySequence::AddKey(int key) { 129 | if (key <= 0) { 130 | return; 131 | } 132 | for (int i = 0; i < Keys.size(); i++) { 133 | if (Keys[i] == key) { 134 | return; 135 | } 136 | } 137 | qDebug() << "Key added: " << key; 138 | Keys.push_back(key); 139 | } 140 | 141 | void UKeySequence::AddKey(const QKeyEvent* event) { 142 | AddKey(event->key()); 143 | AddModifiers(event->modifiers()); 144 | } 145 | -------------------------------------------------------------------------------- /UGlobalHotkey/ukeysequence.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "uexception.h" 10 | #include "uglobal.h" 11 | 12 | class UGLOBALHOTKEY_EXPORT UKeySequence : public QObject 13 | { 14 | Q_OBJECT 15 | public: 16 | explicit UKeySequence(QObject *parent = 0); 17 | explicit UKeySequence(const QString& str, QObject *parent = 0); 18 | void FromString(const QString& str); 19 | QString ToString(); 20 | void AddKey(int key); 21 | void AddKey(const QString& key); 22 | void AddModifiers(Qt::KeyboardModifiers mod); 23 | void AddKey(const QKeyEvent* event); 24 | inline size_t Size() const { 25 | return Keys.size(); 26 | } 27 | inline int operator [] (size_t n) const { 28 | if ((int)n > Keys.size()) { 29 | throw UException("Out of bounds"); 30 | } 31 | return Keys[n]; 32 | } 33 | QVector GetSimpleKeys() const; 34 | QVector GetModifiers() const; 35 | private: 36 | QVector Keys; 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /UltraTTS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28010.2041 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UltraTTS", "UltraTTS\UltraTTS.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "uglobalhotkey", "UGlobalHotkey\uglobalhotkey.vcxproj", "{E647D210-1860-340F-A7B7-4137A60B2483}" 9 | EndProject 10 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cld", "cld\cld.vcxproj", "{5D4AF8E4-ABE0-45EB-B7B7-CA488748C48B}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|x86 = Debug|x86 15 | Release|x86 = Release|x86 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32 19 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32 20 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32 21 | {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32 22 | {E647D210-1860-340F-A7B7-4137A60B2483}.Debug|x86.ActiveCfg = Debug|Win32 23 | {E647D210-1860-340F-A7B7-4137A60B2483}.Debug|x86.Build.0 = Debug|Win32 24 | {E647D210-1860-340F-A7B7-4137A60B2483}.Release|x86.ActiveCfg = Release|Win32 25 | {E647D210-1860-340F-A7B7-4137A60B2483}.Release|x86.Build.0 = Release|Win32 26 | {5D4AF8E4-ABE0-45EB-B7B7-CA488748C48B}.Debug|x86.ActiveCfg = Debug|Win32 27 | {5D4AF8E4-ABE0-45EB-B7B7-CA488748C48B}.Debug|x86.Build.0 = Debug|Win32 28 | {5D4AF8E4-ABE0-45EB-B7B7-CA488748C48B}.Release|x86.ActiveCfg = Release|Win32 29 | {5D4AF8E4-ABE0-45EB-B7B7-CA488748C48B}.Release|x86.Build.0 = Release|Win32 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {FF3063CB-28F5-4A2A-9DD7-1D17B9D6B942} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /UltraTTS/Options.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | OptionsDlg 4 | 5 | 6 | 7 | 0 8 | 0 9 | 563 10 | 254 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 390 20 | 220 21 | 75 22 | 23 23 | 24 | 25 | 26 | Cancel 27 | 28 | 29 | 30 | 31 | 32 | 480 33 | 220 34 | 75 35 | 23 36 | 37 | 38 | 39 | OK 40 | 41 | 42 | 43 | 44 | 45 | 10 46 | 10 47 | 341 48 | 231 49 | 50 | 51 | 52 | Global HotKeys 53 | 54 | 55 | 56 | 57 | 10 58 | 20 59 | 151 60 | 17 61 | 62 | 63 | 64 | Copy and read 65 | 66 | 67 | 68 | 69 | 70 | 160 71 | 20 72 | 131 73 | 20 74 | 75 | 76 | 77 | 78 | 79 | 80 | 160 81 | 50 82 | 131 83 | 20 84 | 85 | 86 | 87 | 88 | 89 | 90 | 160 91 | 140 92 | 131 93 | 20 94 | 95 | 96 | 97 | 98 | 99 | 100 | 160 101 | 110 102 | 131 103 | 20 104 | 105 | 106 | 107 | 108 | 109 | 110 | 160 111 | 170 112 | 131 113 | 20 114 | 115 | 116 | 117 | 118 | 119 | 120 | 160 121 | 80 122 | 131 123 | 20 124 | 125 | 126 | 127 | 128 | 129 | 130 | 300 131 | 20 132 | 25 133 | 19 134 | 135 | 136 | 137 | X 138 | 139 | 140 | 141 | 142 | 143 | 300 144 | 50 145 | 25 146 | 19 147 | 148 | 149 | 150 | X 151 | 152 | 153 | 154 | 155 | 156 | 300 157 | 80 158 | 25 159 | 19 160 | 161 | 162 | 163 | X 164 | 165 | 166 | 167 | 168 | 169 | 300 170 | 110 171 | 25 172 | 19 173 | 174 | 175 | 176 | X 177 | 178 | 179 | 180 | 181 | 182 | 300 183 | 140 184 | 25 185 | 19 186 | 187 | 188 | 189 | X 190 | 191 | 192 | 193 | 194 | 195 | 300 196 | 170 197 | 25 198 | 19 199 | 200 | 201 | 202 | X 203 | 204 | 205 | 206 | 207 | 208 | 10 209 | 50 210 | 151 211 | 17 212 | 213 | 214 | 215 | Copy and read later 216 | 217 | 218 | 219 | 220 | 221 | 10 222 | 80 223 | 151 224 | 17 225 | 226 | 227 | 228 | Pause / Resume 229 | 230 | 231 | 232 | 233 | 234 | 10 235 | 110 236 | 151 237 | 17 238 | 239 | 240 | 241 | Read next 242 | 243 | 244 | 245 | 246 | 247 | 10 248 | 140 249 | 151 250 | 17 251 | 252 | 253 | 254 | Read Previouse 255 | 256 | 257 | 258 | 259 | 260 | 10 261 | 170 262 | 151 263 | 17 264 | 265 | 266 | 267 | Stop reading 268 | 269 | 270 | 271 | 272 | 273 | 10 274 | 200 275 | 151 276 | 17 277 | 278 | 279 | 280 | Stop reading 281 | 282 | 283 | 284 | 285 | 286 | 160 287 | 200 288 | 131 289 | 20 290 | 291 | 292 | 293 | 294 | 295 | 296 | 300 297 | 200 298 | 25 299 | 19 300 | 301 | 302 | 303 | X 304 | 305 | 306 | 307 | 308 | 309 | 310 | 360 311 | 10 312 | 191 313 | 91 314 | 315 | 316 | 317 | Other 318 | 319 | 320 | 321 | 322 | 10 323 | 20 324 | 161 325 | 17 326 | 327 | 328 | 329 | Beep when grabbed 330 | 331 | 332 | 333 | 334 | 335 | 10 336 | 40 337 | 161 338 | 17 339 | 340 | 341 | 342 | Minimize to SysTray 343 | 344 | 345 | 346 | 347 | 348 | 10 349 | 60 350 | 81 351 | 16 352 | 353 | 354 | 355 | Section Delay 356 | 357 | 358 | 359 | 360 | 361 | 100 362 | 60 363 | 51 364 | 20 365 | 366 | 367 | 368 | 369 | 370 | 371 | 160 372 | 60 373 | 21 374 | 16 375 | 376 | 377 | 378 | ms 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | okButton 387 | clicked() 388 | OptionsDlg 389 | accept() 390 | 391 | 392 | 351 393 | 38 394 | 395 | 396 | 233 397 | 29 398 | 399 | 400 | 401 | 402 | cancelButton 403 | clicked() 404 | OptionsDlg 405 | reject() 406 | 407 | 408 | 330 409 | 66 410 | 411 | 412 | 197 413 | 125 414 | 415 | 416 | 417 | 418 | clrCopy 419 | clicked() 420 | kseCopy 421 | clear() 422 | 423 | 424 | 382 425 | 39 426 | 427 | 428 | 270 429 | 39 430 | 431 | 432 | 433 | 434 | clrNow 435 | clicked() 436 | kseNow 437 | clear() 438 | 439 | 440 | 382 441 | 69 442 | 443 | 444 | 270 445 | 69 446 | 447 | 448 | 449 | 450 | crlPause 451 | clicked() 452 | ksePause 453 | clear() 454 | 455 | 456 | 382 457 | 99 458 | 459 | 460 | 270 461 | 99 462 | 463 | 464 | 465 | 466 | clrNext 467 | clicked() 468 | kseNext 469 | clear() 470 | 471 | 472 | 382 473 | 129 474 | 475 | 476 | 270 477 | 129 478 | 479 | 480 | 481 | 482 | clrPrev 483 | clicked() 484 | ksePrev 485 | clear() 486 | 487 | 488 | 382 489 | 159 490 | 491 | 492 | 270 493 | 159 494 | 495 | 496 | 497 | 498 | clrStop 499 | clicked() 500 | kseStop 501 | clear() 502 | 503 | 504 | 382 505 | 189 506 | 507 | 508 | 270 509 | 189 510 | 511 | 512 | 513 | 514 | clrAdd 515 | clicked() 516 | kseAdd 517 | clear() 518 | 519 | 520 | 382 521 | 219 522 | 523 | 524 | 270 525 | 219 526 | 527 | 528 | 529 | 530 | 531 | -------------------------------------------------------------------------------- /UltraTTS/OptionsDlg.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "OptionsDlg.h" 3 | 4 | 5 | COptionsDlg::COptionsDlg(QSettings* pCfg, QWidget *parent, Qt::WindowFlags f) 6 | : QDialog(parent, f) 7 | { 8 | m_pCfg = pCfg; 9 | 10 | ui.setupUi(this); 11 | 12 | connect(ui.okButton, SIGNAL(clicked()), SLOT(onApply())); 13 | 14 | ui.chkCopy->setChecked(m_pCfg->value("UseHotKey_CopyAndRead", true).toBool()); 15 | ui.kseCopy->setKeySequence(QKeySequence(m_pCfg->value("HotKey_CopyAndRead", "F1").toString())); 16 | ui.chkNow->setChecked(m_pCfg->value("UseHotKey_CopyAndReadNow", true).toBool()); 17 | ui.kseNow->setKeySequence(QKeySequence(m_pCfg->value("HotKey_CopyAndReadNow", "Alt+F1").toString())); 18 | ui.chkPause->setChecked(m_pCfg->value("UseHotKey_PauseRead", true).toBool()); 19 | ui.ksePause->setKeySequence(QKeySequence(m_pCfg->value("HotKey_PauseRead", "Ctrl+F1").toString())); 20 | ui.chkNext->setChecked(m_pCfg->value("UseHotKey_ReadNext", true).toBool()); 21 | ui.kseNext->setKeySequence(QKeySequence(m_pCfg->value("HotKey_ReadNext", "Shift+Ctrl+F1").toString())); 22 | ui.chkPrev->setChecked(m_pCfg->value("UseHotKey_ReadPreviouse", true).toBool()); 23 | ui.ksePrev->setKeySequence(QKeySequence(m_pCfg->value("HotKey_ReadPreviouse", "Shift+Alt+F1").toString())); 24 | ui.chkStop->setChecked(m_pCfg->value("UseHotKey_StopReading", true).toBool()); 25 | ui.kseStop->setKeySequence(QKeySequence(m_pCfg->value("HotKey_StopReading", "Ctrl+Alt+F1").toString())); 26 | ui.chkAdd->setChecked(m_pCfg->value("UseHotKey_StopReading", true).toBool()); 27 | ui.kseAdd->setKeySequence(QKeySequence(m_pCfg->value("HotKey_CopyAndAdd", "Shift+F1").toString())); 28 | 29 | ui.chkBeep->setChecked(m_pCfg->value("PlaySound", true).toBool()); 30 | ui.chkSysTray->setChecked(m_pCfg->value("SysTray", true).toBool()); 31 | ui.editDelay->setText(QString::number(m_pCfg->value("SectionDelay", 750).toInt())); 32 | 33 | ui.editDelay->setValidator(new QIntValidator(0, 10000, this)); 34 | } 35 | 36 | 37 | COptionsDlg::~COptionsDlg() 38 | { 39 | } 40 | 41 | void COptionsDlg::onApply() 42 | { 43 | m_pCfg->setValue("UseHotKey_CopyAndRead", ui.chkCopy->isChecked()); 44 | m_pCfg->setValue("HotKey_CopyAndRead", ui.kseCopy->keySequence().toString()); 45 | m_pCfg->setValue("UseHotKey_CopyAndReadNow", ui.chkNow->isChecked()); 46 | m_pCfg->setValue("HotKey_CopyAndReadNow", ui.kseNow->keySequence().toString()); 47 | m_pCfg->setValue("UseHotKey_PauseRead", ui.chkPause->isChecked()); 48 | m_pCfg->setValue("HotKey_PauseRead", ui.ksePause->keySequence().toString()); 49 | m_pCfg->setValue("UseHotKey_ReadNext", ui.chkNext->isChecked()); 50 | m_pCfg->setValue("HotKey_ReadNext", ui.kseNext->keySequence().toString()); 51 | m_pCfg->setValue("UseHotKey_ReadPreviouse", ui.chkPrev->isChecked()); 52 | m_pCfg->setValue("HotKey_ReadPreviouse", ui.ksePrev->keySequence().toString()); 53 | m_pCfg->setValue("UseHotKey_StopReading", ui.chkStop->isChecked()); 54 | m_pCfg->setValue("HotKey_StopReading", ui.kseStop->keySequence().toString()); 55 | m_pCfg->setValue("UseHotKey_CopyAndAdd", ui.chkAdd->isChecked()); 56 | m_pCfg->setValue("HotKey_CopyAndAdd", ui.kseAdd->keySequence().toString()); 57 | 58 | m_pCfg->setValue("PlaySound", ui.chkBeep->isChecked()); 59 | m_pCfg->setValue("SysTray", ui.chkSysTray->isChecked()); 60 | m_pCfg->setValue("SectionDelay", ui.editDelay->text().toInt()); 61 | } 62 | -------------------------------------------------------------------------------- /UltraTTS/OptionsDlg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "ui_Options.h" 4 | 5 | class COptionsDlg : public QDialog 6 | { 7 | Q_OBJECT 8 | public: 9 | COptionsDlg(QSettings* pCfg, QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags()); 10 | virtual ~COptionsDlg(); 11 | 12 | private slots: 13 | void onApply(); 14 | 15 | private: 16 | Ui::OptionsDlg ui; 17 | 18 | protected: 19 | QSettings* m_pCfg; 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TTS.h" 3 | 4 | #include "TTS4.h" 5 | #include "TTS5.h" 6 | 7 | 8 | CTTS* CTTS::NewTTS() 9 | { 10 | return new CTTSApi(); 11 | } 12 | 13 | CTTS* CTTS::NewTTS4() 14 | { 15 | return new CTTS4(); 16 | } 17 | 18 | CTTS* CTTS::NewTTS5() 19 | { 20 | return new CTTS5(); 21 | } 22 | 23 | ///////////////////////////////////////////////////////////////////// 24 | 25 | CTTS_Impl::CTTS_Impl() 26 | { 27 | m_bPause = false; 28 | m_bStop = true; 29 | 30 | m_DefaultVolume = 0; 31 | m_MinVolume = 0; 32 | m_MaxVolume = 0; 33 | 34 | m_DefaultRate = 0; 35 | m_MinRate = 0; 36 | m_MaxRate = 0; 37 | 38 | m_DefaultPitch = 0; 39 | m_MinPitch = 0; 40 | m_MaxPitch = 0; 41 | } 42 | 43 | ///////////////////////////////////////////////////////////////////// 44 | 45 | const wchar_t CTTSApi::Voices_Platform[] = L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech Server\\v11.0\\Voices"; 46 | const wchar_t CTTSApi::Voices_OneCore[] = L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices"; 47 | const wchar_t CTTSApi::Voices_Speech[] = L"HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech\\Voices"; 48 | const wchar_t CTTSApi::Voices_Cortana[] = L"HKEY_CLASSES_ROOT\\Local Settings\\Software\\Microsoft\\Windows\\CurrentVersion\\AppContainer\\Storage\\microsoft.windows.cortana_cw5n1h2txyewy\\SOFTWARE\\Microsoft\\Speech_OneCore\\Isolated\\jWXZvMzcRxToSdOzNgXV_L3ZSrLDNbZuY5NZNWCCUd8\\HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Speech_OneCore\\Voices"; 49 | 50 | 51 | CTTSApi::CTTSApi() 52 | { 53 | m_Use4 = false; 54 | 55 | CTTSApi* that = this; 56 | 57 | m_pTTS4 = new CTTS4(); 58 | m_pTTS4->SetCallBacks([that]() { 59 | if (that->m_Use4) 60 | that->OnStop(); 61 | }, [that](int pos, int len, int total) { 62 | if (that->m_Use4) 63 | that->OnProgress(pos,len, total); 64 | }); 65 | 66 | m_pTTS5 = new CTTS5(); 67 | m_pTTS5->SetCallBacks([that]() { 68 | if (!that->m_Use4) 69 | that->OnStop(); 70 | }, [that](int pos, int len, int total) { 71 | if (!that->m_Use4) 72 | that->OnProgress(pos, len, total); 73 | }); 74 | } 75 | 76 | CTTSApi::~CTTSApi() 77 | { 78 | delete m_pTTS4; 79 | delete m_pTTS5; 80 | } 81 | 82 | bool CTTSApi::Speak(const std::wstring& str, bool ProcessXML) 83 | { 84 | if (m_Use4) 85 | return m_pTTS4->Speak(str); 86 | return m_pTTS5->Speak(str, ProcessXML); 87 | } 88 | 89 | bool CTTSApi::Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML) 90 | { 91 | if (m_Use4) 92 | return m_pTTS4->Speak2Wave(path, str, ProcessXML); 93 | return m_pTTS5->Speak2Wave(path, str, ProcessXML); 94 | } 95 | 96 | bool CTTSApi::IsSpeaking() 97 | { 98 | if (m_Use4) 99 | return m_pTTS4->IsSpeaking(); 100 | return m_pTTS5->IsSpeaking(); 101 | } 102 | 103 | void CTTSApi::Pause() 104 | { 105 | if (m_Use4) 106 | return m_pTTS4->Pause(); 107 | return m_pTTS5->Pause(); 108 | } 109 | 110 | bool CTTSApi::IsPaused() 111 | { 112 | if (m_Use4) 113 | return m_pTTS4->IsPaused(); 114 | return m_pTTS5->IsPaused(); 115 | } 116 | 117 | void CTTSApi::Skip(int SkipNum) 118 | { 119 | if (m_Use4) 120 | return m_pTTS4->Skip(SkipNum); 121 | return m_pTTS5->Skip(SkipNum); 122 | } 123 | 124 | void CTTSApi::Inject(const std::wstring& str) 125 | { 126 | if (m_Use4) 127 | return m_pTTS4->Inject(str); 128 | return m_pTTS5->Inject(str); 129 | } 130 | 131 | void CTTSApi::Stop() 132 | { 133 | if (m_Use4) 134 | return m_pTTS4->Stop(); 135 | return m_pTTS5->Stop(); 136 | } 137 | 138 | 139 | void CTTSApi::SetRate(int Rate) 140 | { 141 | if (m_Use4) 142 | return m_pTTS4->SetRate(Rate); 143 | return m_pTTS5->SetRate(Rate); 144 | } 145 | 146 | int CTTSApi::GetRate() 147 | { 148 | if (m_Use4) 149 | return m_pTTS4->GetRate(); 150 | return m_pTTS5->GetRate(); 151 | } 152 | 153 | void CTTSApi::SetPitch(int Pitch) 154 | { 155 | if (m_Use4) 156 | return m_pTTS4->SetPitch(Pitch); 157 | return m_pTTS5->SetPitch(Pitch); 158 | } 159 | 160 | int CTTSApi::GetPitch() 161 | { 162 | if (m_Use4) 163 | return m_pTTS4->GetPitch(); 164 | return m_pTTS5->GetPitch(); 165 | } 166 | 167 | void CTTSApi::SetVolume(int Volume) 168 | { 169 | if (m_Use4) 170 | return m_pTTS4->SetVolume(Volume); 171 | return m_pTTS5->SetVolume(Volume); 172 | } 173 | 174 | int CTTSApi::GetVolume() 175 | { 176 | if (m_Use4) 177 | return m_pTTS4->GetVolume(); 178 | return m_pTTS5->GetVolume(); 179 | } 180 | 181 | int CTTSApi::GetMinRate() 182 | { 183 | if (m_Use4) 184 | return m_pTTS4->GetMinRate(); 185 | return m_pTTS5->GetMinRate(); 186 | } 187 | int CTTSApi::GetDefaultRate() 188 | { 189 | if (m_Use4) 190 | return m_pTTS4->GetDefaultRate(); 191 | return m_pTTS5->GetDefaultRate(); 192 | } 193 | int CTTSApi::GetMaxRate() 194 | { 195 | if (m_Use4) 196 | return m_pTTS4->GetMaxRate(); 197 | return m_pTTS5->GetMaxRate(); 198 | } 199 | 200 | int CTTSApi::GetMinPitch() 201 | { 202 | if (m_Use4) 203 | return m_pTTS4->GetMinPitch(); 204 | return m_pTTS5->GetMinPitch(); 205 | } 206 | int CTTSApi::GetDefaultPitch() 207 | { 208 | if (m_Use4) 209 | return m_pTTS4->GetDefaultPitch(); 210 | return m_pTTS5->GetDefaultPitch(); 211 | } 212 | int CTTSApi::GetMaxPitch() 213 | { 214 | if (m_Use4) 215 | return m_pTTS4->GetMaxPitch(); 216 | return m_pTTS5->GetMaxPitch(); 217 | } 218 | 219 | int CTTSApi::GetMinVolume() 220 | { 221 | if (m_Use4) 222 | return m_pTTS4->GetMinVolume(); 223 | return m_pTTS5->GetMinVolume(); 224 | } 225 | int CTTSApi::GetDefaultVolume() 226 | { 227 | if (m_Use4) 228 | return m_pTTS4->GetDefaultVolume(); 229 | return m_pTTS5->GetDefaultVolume(); 230 | } 231 | int CTTSApi::GetMaxVolume() 232 | { 233 | if (m_Use4) 234 | return m_pTTS4->GetMaxVolume(); 235 | return m_pTTS5->GetMaxVolume(); 236 | } 237 | 238 | std::vector CTTSApi::GetVoices() 239 | { 240 | std::vector list = m_pTTS5->GetVoices(); 241 | std::vector list4 = m_pTTS4->GetVoices(); 242 | if (!list4.empty()) 243 | list.insert(list.end(), list4.begin(), list4.end()); 244 | return list; 245 | } 246 | 247 | bool CTTSApi::SelectVoice(const std::wstring& name) 248 | { 249 | if (m_pTTS5->SelectVoice(name)) 250 | m_Use4 = false; 251 | else if (m_pTTS4->SelectVoice(name)) 252 | m_Use4 = true; 253 | else 254 | return false; 255 | return true; 256 | } 257 | 258 | bool CTTSApi::EnumVoices(const std::wstring& regKey) 259 | { 260 | if (regKey.empty()) 261 | return m_pTTS4->EnumVoices(regKey); 262 | return m_pTTS5->EnumVoices(regKey); 263 | } 264 | 265 | void CTTSApi::ClearVoices() 266 | { 267 | m_pTTS5->ClearVoices(); 268 | m_pTTS4->ClearVoices(); 269 | } -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | struct SVoice { 4 | std::wstring Name; 5 | std::wstring Vendor; 6 | // // Speaker 7 | // // Product 8 | enum EAge 9 | { 10 | eAdult = 0, 11 | eChild = 1, 12 | eElderly = 2 13 | }; 14 | EAge Age; 15 | enum EGender 16 | { 17 | eNeutral = 0, 18 | eFemale = 1, 19 | eMale = 2 20 | }; 21 | EGender Gender; 22 | LANGID LangID; 23 | std::wstring Lang; 24 | // // Style 25 | bool Sapi4; 26 | }; 27 | 28 | class CTTS 29 | { 30 | public: 31 | virtual ~CTTS() {} 32 | 33 | static CTTS* NewTTS(); 34 | static CTTS* NewTTS4(); 35 | static CTTS* NewTTS5(); 36 | 37 | virtual bool Speak(const std::wstring& str, bool ProcessXML = false) = 0; 38 | virtual bool Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML = false) = 0; 39 | virtual bool IsSpeaking() = 0; 40 | virtual void Pause() = 0; 41 | virtual bool IsPaused() = 0; 42 | virtual void Skip(int SkipNum) = 0; 43 | virtual void Inject(const std::wstring& str) = 0; 44 | virtual void Stop() = 0; 45 | 46 | virtual void SetRate(int Rate) = 0; 47 | virtual int GetRate() = 0; 48 | virtual void SetPitch(int Pitch) = 0; 49 | virtual int GetPitch() = 0; 50 | virtual void SetVolume(int Volume) = 0; 51 | virtual int GetVolume() = 0; 52 | 53 | virtual int GetMinRate() = 0; 54 | virtual int GetDefaultRate() = 0; 55 | virtual int GetMaxRate() = 0; 56 | 57 | virtual int GetMinPitch() = 0; 58 | virtual int GetDefaultPitch() = 0; 59 | virtual int GetMaxPitch() = 0; 60 | 61 | virtual int GetMinVolume() = 0; 62 | virtual int GetDefaultVolume() = 0; 63 | virtual int GetMaxVolume() = 0; 64 | 65 | virtual std::vector GetVoices() = 0; 66 | virtual bool SelectVoice(const std::wstring& name) = 0; 67 | 68 | virtual bool EnumVoices(const std::wstring& regKey = L"") = 0; 69 | virtual void ClearVoices() = 0; 70 | 71 | void SetCallBacks(std::function pOnStop, std::function pOnProgress) { m_pOnStop = pOnStop; m_pOnProgress = pOnProgress; } 72 | 73 | void OnStop() { if (m_pOnStop) m_pOnStop(); } 74 | void OnProgress(int pos, int len, int total) { if (m_pOnProgress) m_pOnProgress(pos, len, total); } 75 | 76 | protected: 77 | 78 | std::function m_pOnStop; 79 | std::function m_pOnProgress; 80 | }; 81 | 82 | class CTTS_Impl: public CTTS 83 | { 84 | public: 85 | CTTS_Impl(); 86 | 87 | bool IsSpeaking() { return !m_bStop; } 88 | bool IsPaused() { return m_bPause; } 89 | 90 | int GetMinRate() { return m_MinRate; } 91 | int GetDefaultRate() { return m_DefaultRate; } 92 | int GetMaxRate() { return m_MaxRate; } 93 | 94 | int GetMinPitch() { return m_MinPitch; } 95 | int GetDefaultPitch() { return m_DefaultPitch; } 96 | int GetMaxPitch() { return m_MaxPitch; } 97 | 98 | int GetMinVolume() { return m_MinVolume; } 99 | int GetDefaultVolume() { return m_DefaultVolume; } 100 | int GetMaxVolume() { return m_MaxVolume; } 101 | 102 | protected: 103 | bool m_bPause; 104 | bool m_bStop; 105 | 106 | int m_DefaultVolume; 107 | int m_MinVolume; 108 | int m_MaxVolume; 109 | 110 | int m_DefaultRate; 111 | int m_MinRate; 112 | int m_MaxRate; 113 | 114 | int m_DefaultPitch; 115 | int m_MinPitch; 116 | int m_MaxPitch; 117 | }; 118 | 119 | class CTTSApi : public CTTS 120 | { 121 | public: 122 | CTTSApi(); 123 | ~CTTSApi(); 124 | 125 | static const wchar_t CTTSApi::Voices_Platform[]; 126 | static const wchar_t CTTSApi::Voices_OneCore[]; 127 | static const wchar_t CTTSApi::Voices_Speech[]; 128 | static const wchar_t CTTSApi::Voices_Cortana[]; 129 | 130 | virtual bool Speak(const std::wstring& str, bool ProcessXML = false); 131 | virtual bool Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML = false); 132 | virtual bool IsSpeaking(); 133 | virtual void Pause(); 134 | virtual bool IsPaused(); 135 | virtual void Skip(int SkipNum); 136 | virtual void Inject(const std::wstring& str); 137 | virtual void Stop(); 138 | 139 | virtual void SetRate(int Rate); 140 | virtual int GetRate(); 141 | virtual void SetPitch(int Pitch); 142 | virtual int GetPitch(); 143 | virtual void SetVolume(int Volume); 144 | virtual int GetVolume(); 145 | 146 | virtual int GetMinRate(); 147 | virtual int GetDefaultRate(); 148 | virtual int GetMaxRate(); 149 | 150 | virtual int GetMinPitch(); 151 | virtual int GetDefaultPitch(); 152 | virtual int GetMaxPitch(); 153 | 154 | virtual int GetMinVolume(); 155 | virtual int GetDefaultVolume(); 156 | virtual int GetMaxVolume(); 157 | 158 | virtual std::vector GetVoices(); 159 | virtual bool SelectVoice(const std::wstring& name); 160 | 161 | virtual bool EnumVoices(const std::wstring& regKey = L""); 162 | virtual void ClearVoices(); 163 | 164 | protected: 165 | class CTTS4* m_pTTS4; 166 | class CTTS5* m_pTTS5; 167 | bool m_Use4; 168 | 169 | 170 | }; -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS4.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TTS4.h" 3 | 4 | 5 | CTTS4::CTTS4() 6 | { 7 | m_BufferLength = 0; 8 | 9 | if (!InitTTS()) 10 | TerminateTTS(); 11 | 12 | //EnumVoices(); 13 | } 14 | 15 | CTTS4::~CTTS4() 16 | { 17 | TerminateTTS(); 18 | 19 | ClearVoices(); 20 | } 21 | 22 | bool CTTS4::Speak(const std::wstring& str, bool ProcessXML) 23 | { 24 | qDebug() << "Speak"; 25 | 26 | if (m_bPause) 27 | Stop(); 28 | 29 | m_BufferLength = str.size(); 30 | 31 | SDATA text; 32 | text.dwSize = str.size() + 1; 33 | text.pData = (TCHAR *)malloc(text.dwSize * sizeof(TCHAR)); 34 | wcscpy((TCHAR*)text.pData, str.c_str()); 35 | 36 | VOICECHARSET vcs = CHARSET_TEXT; // CHARSET_IPAPHONETIC 37 | 38 | HRESULT hr; 39 | hr = m_pITTSCentral->TextData(vcs, ProcessXML, text, m_pTestBufNotify, IID_ITTSBufNotifySink); 40 | free(text.pData); 41 | 42 | m_bStop = false; 43 | m_bPause = false; 44 | 45 | return SUCCEEDED(hr); 46 | } 47 | 48 | void CTTS4::Pause() 49 | { 50 | qDebug() << "Pause"; 51 | 52 | if (!m_pITTSCentral) 53 | return; 54 | 55 | if (m_bPause) { 56 | m_bPause = false; 57 | m_pITTSCentral->AudioResume(); 58 | } 59 | else { 60 | m_bPause = true; 61 | m_pITTSCentral->AudioPause(); 62 | } 63 | } 64 | 65 | void CTTS4::Inject(const std::wstring& str) 66 | { 67 | if(m_pITTSCentral) 68 | m_pITTSCentral->Inject(str.c_str()); 69 | } 70 | 71 | void CTTS4::Stop() 72 | { 73 | qDebug() << "Stop"; 74 | 75 | if (m_pITTSCentral) 76 | m_pITTSCentral->AudioReset(); // this sometimes crashes??? wtf 77 | 78 | bool bWasPaused = m_bPause; 79 | 80 | m_bStop = true; 81 | m_bPause = false; 82 | 83 | if(bWasPaused) 84 | OnStop(); 85 | } 86 | 87 | void CTTS4::ShowGeneralWnd(HWND wnd) 88 | { 89 | m_pITTSDialogs->GeneralDlg(wnd, NULL); 90 | } 91 | 92 | BOOL CTTS4::InitTTS(void) 93 | { 94 | HRESULT hRes; 95 | 96 | m_pITTSCentral = NULL; 97 | m_pITTSEnum = NULL; 98 | m_pITTSAttributes = NULL; 99 | m_pITTSDialogs = NULL; 100 | m_pILexPronounce = NULL; 101 | m_dwRegKey = 0xFFFFFFFF; 102 | m_pTestNotify = NULL; 103 | m_pTestBufNotify = NULL; 104 | m_pIAF = NULL; 105 | #ifdef DIRECTSOUND 106 | m_pIAD = NULL; 107 | #else 108 | m_pIMMD = NULL; 109 | #endif 110 | 111 | hRes = CoCreateInstance(CLSID_TTSEnumerator, NULL, CLSCTX_ALL, IID_ITTSEnum, (void**)&m_pITTSEnum); 112 | 113 | if (FAILED(hRes)) 114 | { 115 | //MessageBox(NULL, TEXT("Error creating TTSEnumerator (CoCreateInstance)."), NULL, MB_OK); 116 | return FALSE; 117 | } 118 | 119 | if ((m_pTestNotify = new CTestNotify(this)) == NULL) 120 | MessageBox(NULL, TEXT("Error creating notify pointer."), TEXT("Warning"), MB_OK); 121 | 122 | if ((m_pTestBufNotify = new CTestBufNotify(this)) == NULL) 123 | MessageBox(NULL, TEXT("Error creating buf notify pointer."), TEXT("Warning"), MB_OK); 124 | 125 | return TRUE; 126 | } 127 | 128 | BOOL CTTS4::TerminateTTS(void) 129 | { 130 | if (m_pITTSEnum) { 131 | m_pITTSEnum->Release(); 132 | m_pITTSEnum = NULL; 133 | } 134 | if (m_pITTSAttributes) { 135 | m_pITTSAttributes->Release(); 136 | m_pITTSAttributes = NULL; 137 | } 138 | if (m_pILexPronounce) { 139 | m_pILexPronounce->Release(); 140 | m_pILexPronounce = NULL; 141 | } 142 | if (m_pITTSDialogs) { 143 | m_pITTSDialogs->Release(); 144 | m_pITTSDialogs = NULL; 145 | } 146 | if (m_pITTSCentral) { 147 | m_pITTSCentral->UnRegister(m_dwRegKey); 148 | m_pITTSCentral->Release(); 149 | m_pITTSCentral = NULL; 150 | } 151 | if (m_pIAF) { 152 | m_pIAF->Release(); 153 | m_pIAF = NULL; 154 | } 155 | 156 | #ifdef DIRECTSOUND 157 | if (m_pIAD) { 158 | while (m_pIAD->Release()); 159 | m_pIAD = NULL; 160 | } 161 | #else 162 | if (m_pIMMD) { 163 | while (m_pIMMD->Release()); 164 | m_pIMMD = NULL; 165 | } 166 | #endif 167 | 168 | if (m_pTestNotify) { 169 | delete(m_pTestNotify); 170 | m_pTestNotify = NULL; 171 | } 172 | if (m_pTestBufNotify) { 173 | delete(m_pTestBufNotify); 174 | m_pTestBufNotify = NULL; 175 | } 176 | return TRUE; 177 | } 178 | 179 | bool CTTS4::EnumVoices(const std::wstring& regKey) 180 | { 181 | if (!m_pITTSEnum) 182 | return false; 183 | 184 | HRESULT hRes; 185 | PITTSENUM pClone1; 186 | TTSMODEINFO TTSModeInfo; 187 | DWORD dwNumTimes; 188 | int index = 0; 189 | 190 | hRes = m_pITTSEnum->Clone(&pClone1); 191 | if (FAILED(hRes)) 192 | { 193 | MessageBox(NULL, TEXT("Couldn't clone ITTSEnum state, aborting enumeration test"), TEXT("Error"), MB_OK); 194 | return 0; 195 | } 196 | 197 | hRes = pClone1->Next(1, &TTSModeInfo, &dwNumTimes); 198 | if (dwNumTimes == 0) return FALSE; 199 | 200 | while (dwNumTimes) { 201 | 202 | std::wstring name(TTSModeInfo.szModeName); 203 | if (m_Voices.find(name) == m_Voices.end()) 204 | { 205 | SVoice4* pVoice = new SVoice4(); 206 | pVoice->Name = name; 207 | pVoice->Vendor = std::wstring(TTSModeInfo.szMfgName); 208 | // // Speaker = std::wstring(TTSModeInfo.szSpeaker); 209 | // // Product = std::wstring(TTSModeInfo.szProductName); 210 | if (TTSModeInfo.wAge <= 12) 211 | pVoice->Age = SVoice4::eChild; 212 | else if (TTSModeInfo.wAge > 60) 213 | pVoice->Age = SVoice4::eElderly; 214 | else 215 | pVoice->Age = SVoice4::eAdult; 216 | pVoice->Gender = (SVoice4::EGender)TTSModeInfo.wGender; 217 | pVoice->LangID = TTSModeInfo.language.LanguageID; 218 | WCHAR strNameBuffer[LOCALE_NAME_MAX_LENGTH+1]; 219 | //LCIDToLocaleName(pVoice->LangID, strNameBuffer, LOCALE_NAME_MAX_LENGTH, 0); 220 | GetLocaleInfoW(MAKELCID(pVoice->LangID, SORT_DEFAULT), LOCALE_SENGLANGUAGE, strNameBuffer, LOCALE_NAME_MAX_LENGTH); 221 | pVoice->Lang = strNameBuffer; 222 | pVoice->Sapi4 = true; 223 | // // Style = std::wstring(TTSModeInfo.szStyle); 224 | pVoice->guid = TTSModeInfo.gModeID; 225 | 226 | m_Voices[name] = pVoice; 227 | } 228 | 229 | hRes = pClone1->Next(1, &TTSModeInfo, &dwNumTimes); 230 | } 231 | 232 | pClone1->Release(); 233 | pClone1 = NULL; 234 | return TRUE; 235 | } 236 | 237 | std::vector CTTS4::GetVoices() 238 | { 239 | std::vector list; 240 | for (std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 241 | list.push_back(I->second); 242 | return list; 243 | } 244 | 245 | bool CTTS4::SelectVoice(const std::wstring& name) 246 | { 247 | for (std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 248 | { 249 | if (I->second->Name == name) 250 | return VoiceChange(I->second); 251 | } 252 | return false; 253 | } 254 | 255 | void CTTS4::ClearVoices() 256 | { 257 | for (std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 258 | { 259 | delete I->second; 260 | } 261 | m_Voices.clear(); 262 | } 263 | 264 | bool CTTS4::VoiceChange(SVoice4* pVoice, PIAUDIOFILE dev) 265 | { 266 | if (pVoice && m_guid == pVoice->guid) 267 | return true; 268 | 269 | HRESULT hRes; 270 | 271 | if (m_pITTSAttributes) { 272 | m_pITTSAttributes->Release(); 273 | m_pITTSAttributes = NULL; 274 | } 275 | if (m_pILexPronounce) { 276 | m_pILexPronounce->Release(); 277 | m_pILexPronounce = NULL; 278 | } 279 | if (m_pITTSDialogs) { 280 | m_pITTSDialogs->Release(); 281 | m_pITTSDialogs = NULL; 282 | } 283 | if (m_pITTSCentral) { 284 | m_pITTSCentral->UnRegister(m_dwRegKey); 285 | m_pITTSCentral->Release(); 286 | 287 | m_pITTSCentral = NULL; 288 | } 289 | #ifdef DIRECTSOUND 290 | if (m_pIAD) { 291 | while (m_pIAD->Release()); 292 | m_pIAD = NULL; 293 | } 294 | #else // DIRECTSOUND 295 | if (m_pIMMD) { 296 | while (m_pIMMD->Release()); 297 | m_pIMMD = NULL; 298 | } 299 | #endif 300 | 301 | #ifdef DIRECTSOUND 302 | hRes = CoCreateInstance(CLSID_AudioDestDirect, NULL, CLSCTX_ALL, IID_IAudioDirect, (void**)&m_pIAD); 303 | if (FAILED(hRes)) 304 | { 305 | MessageBox(TEXT("Can't find CLSID_AudioDestDirect"), NULL, MB_OK); 306 | return; 307 | } 308 | 309 | // crreate direct sound stuff 310 | LPDIRECTSOUND lpDirectSound; 311 | hRes = CoCreateInstance(CLSID_DirectSound, NULL, 312 | CLSCTX_ALL, IID_IDirectSound, (LPVOID*)&lpDirectSound); 313 | if (hRes) { 314 | MessageBox(TEXT("Can't find IID_IDirectSound"), NULL, MB_OK); 315 | return; 316 | } 317 | hRes = lpDirectSound->Initialize(NULL); 318 | if (hRes) { 319 | MessageBox(TEXT("Can't initialize DirectSound"), NULL, MB_OK); 320 | return; 321 | } 322 | hRes = lpDirectSound->SetCooperativeLevel(m_hWnd, DSSCL_NORMAL); 323 | 324 | // tell the audio object about our stuff 325 | m_pIAD->Init((PVOID)lpDirectSound, IID_IDirectSound); 326 | 327 | m_pIAD->AddRef(); 328 | if (dev) 329 | hRes = m_pITTSEnum->Select(pVoice ? pVoice->guid : m_guid, &m_pITTSCentral, dev); 330 | else 331 | hRes = m_pITTSEnum->Select(pVoice ? pVoice->guid m_guid, &m_pITTSCentral, m_pIAD); 332 | #else // DIRECTSOUND 333 | hRes = CoCreateInstance(CLSID_MMAudioDest, NULL, CLSCTX_ALL, IID_IAudioMultiMediaDevice, (void**)&m_pIMMD); 334 | if (FAILED(hRes)) 335 | { 336 | MessageBox(NULL, TEXT("Error creating AudioDest Object(CoCreateInstance)."), NULL, MB_OK); 337 | } 338 | 339 | hRes = m_pIMMD->DeviceNumSet(0XFFFFFFFF); 340 | 341 | m_pIMMD->AddRef(); 342 | if(dev) 343 | hRes = m_pITTSEnum->Select(pVoice ? pVoice->guid : m_guid, &m_pITTSCentral, dev); 344 | else 345 | hRes = m_pITTSEnum->Select(pVoice ? pVoice->guid : m_guid, &m_pITTSCentral, m_pIMMD); 346 | 347 | #endif // DIRECTSOUND 348 | if (FAILED(hRes)) 349 | return FALSE; 350 | 351 | if(pVoice) 352 | m_guid = pVoice->guid; 353 | 354 | m_pITTSCentral->QueryInterface(IID_ITTSAttributes, (void**)&m_pITTSAttributes); 355 | 356 | m_pITTSCentral->QueryInterface(IID_ITTSDialogs, (void**)&m_pITTSDialogs); 357 | 358 | m_pITTSCentral->QueryInterface(IID_ILexPronounce, (void**)&m_pILexPronounce); 359 | 360 | 361 | WORD wMin, wMax, wNor; 362 | 363 | m_pITTSAttributes->PitchSet(TTSATTR_MINPITCH); 364 | m_pITTSAttributes->PitchGet(&wMin); 365 | m_MinPitch = wMin; 366 | 367 | m_pITTSAttributes->PitchSet(TTSATTR_MAXPITCH); 368 | m_pITTSAttributes->PitchGet(&wMax); 369 | m_MaxPitch = wMax; 370 | 371 | DWORD dwMin, dwMax, dwNor; 372 | 373 | m_pITTSAttributes->SpeedSet(TTSATTR_MINSPEED); 374 | m_pITTSAttributes->SpeedGet(&dwMin); 375 | m_MinRate = dwMin; 376 | 377 | m_pITTSAttributes->SpeedSet(TTSATTR_MAXSPEED); 378 | m_pITTSAttributes->SpeedGet(&dwMax); 379 | m_MaxRate = dwMax; 380 | 381 | m_MinVolume = 0; 382 | m_MaxVolume = 100; 383 | 384 | 385 | // Reset the voice 386 | m_pITTSCentral->Inject(L"\\rst\\"); 387 | 388 | hRes = m_pITTSAttributes->PitchGet(&wNor); 389 | if (hRes != S_OK) 390 | m_DefaultPitch = wNor; 391 | 392 | hRes = m_pITTSAttributes->SpeedGet(&dwNor); 393 | if (hRes != S_OK) 394 | m_DefaultRate = dwNor; 395 | 396 | hRes = m_pITTSAttributes->VolumeGet(&dwNor); 397 | dwNor &= 0xffff; 398 | dwNor /= 655; 399 | if (hRes != S_OK) 400 | m_DefaultVolume = dwNor; 401 | 402 | m_pITTSCentral->Register((void*)m_pTestNotify, IID_ITTSNotifySink, &m_dwRegKey); 403 | 404 | // get the gender 405 | //TTSMODEINFO tm; 406 | //m_pITTSCentral->ModeGet(&tm); 407 | //PaintGender(tm.wGender == GENDER_MALE); 408 | return TRUE; 409 | } 410 | 411 | void CTTS4::SetRate(int Rate) 412 | { 413 | if(m_pITTSAttributes) 414 | m_pITTSAttributes->SpeedSet(Rate); 415 | } 416 | 417 | int CTTS4::GetRate() 418 | { 419 | DWORD speed; 420 | if (m_pITTSAttributes) 421 | m_pITTSAttributes->SpeedGet(&speed); 422 | return speed; 423 | } 424 | 425 | void CTTS4::SetPitch(int Pitch) 426 | { 427 | if(m_pITTSAttributes) 428 | m_pITTSAttributes->PitchSet(Pitch); 429 | } 430 | 431 | int CTTS4::GetPitch() 432 | { 433 | WORD pitch; 434 | if (m_pITTSAttributes) 435 | m_pITTSAttributes->PitchGet(&pitch); 436 | return pitch; 437 | } 438 | 439 | void CTTS4::SetVolume(int Volume) 440 | { 441 | DWORD dwVolume = 0xffff * Volume / 100; 442 | dwVolume |= dwVolume << 16; 443 | if(m_pITTSAttributes) 444 | m_pITTSAttributes->VolumeSet(dwVolume); 445 | } 446 | 447 | int CTTS4::GetVolume() 448 | { 449 | DWORD volume; 450 | if (m_pITTSAttributes) 451 | m_pITTSAttributes->VolumeGet(&volume); 452 | volume &= 0xffff; 453 | volume /= 655; 454 | return volume; 455 | } 456 | 457 | bool CTTS4::Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML) 458 | { 459 | HRESULT hRes; 460 | 461 | hRes = CoCreateInstance(CLSID_AudioDestFile, NULL, CLSCTX_ALL, IID_IAudioFile, (void**)&m_pIAF); 462 | 463 | VoiceChange(NULL, m_pIAF); 464 | 465 | m_pIAF->RealTimeSet(0xFFFFFFFF); 466 | 467 | m_pIAF->Set(path.c_str(), 1); 468 | 469 | bool bRet = Speak(str, ProcessXML); 470 | 471 | BOOL fGotMessage; 472 | MSG msg; 473 | while ((fGotMessage = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0 && fGotMessage != -1 && !m_bStop) { 474 | TranslateMessage(&msg); 475 | DispatchMessage(&msg); 476 | } 477 | 478 | m_pIAF->Flush(); 479 | 480 | m_pIAF->Release(); 481 | m_pIAF = NULL; 482 | 483 | // reset to default outpit 484 | VoiceChange(NULL, NULL); 485 | 486 | return bRet; 487 | } 488 | 489 | /************************************************************************* 490 | CTestNotify - Notification object. 491 | */ 492 | CTestNotify::CTestNotify(CTTS4 *pImpl) 493 | { 494 | m_pImpl = pImpl; 495 | } 496 | 497 | CTestNotify::~CTestNotify(void) 498 | { 499 | // this space intentionally left blank 500 | } 501 | 502 | STDMETHODIMP CTestNotify::QueryInterface(REFIID riid, LPVOID *ppv) 503 | { 504 | *ppv = NULL; 505 | 506 | /* always return our IUnknown for IID_IUnknown */ 507 | if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITTSNotifySink)) 508 | { 509 | *ppv = (LPVOID)this; 510 | return S_OK; 511 | } 512 | 513 | // otherwise, cant find 514 | return ResultFromScode(E_NOINTERFACE); 515 | } 516 | 517 | STDMETHODIMP_(ULONG) CTestNotify::AddRef(void) 518 | { 519 | // normally this increases a reference count, but this object 520 | // is going to be freed as soon as the app is freed, so it doesn't 521 | // matter 522 | return 1; 523 | } 524 | 525 | STDMETHODIMP_(ULONG) CTestNotify::Release(void) 526 | { 527 | // normally this releases a reference count, but this object 528 | // is going to be freed when the application is freed so it doesnt 529 | // matter 530 | return 1; 531 | } 532 | 533 | STDMETHODIMP CTestNotify::AttribChanged(DWORD dwAttribID) 534 | { 535 | //m_pImpl->UpdateSliders(); // todo 536 | return NOERROR; 537 | } 538 | 539 | STDMETHODIMP CTestNotify::AudioStart(QWORD qTimeStamp) 540 | { 541 | return NOERROR; 542 | } 543 | 544 | STDMETHODIMP CTestNotify::AudioStop(QWORD qTimeStamp) 545 | { 546 | if (!m_pImpl->m_bPause) { 547 | m_pImpl->m_bStop = true; 548 | m_pImpl->OnStop(); 549 | } 550 | return NOERROR; 551 | } 552 | 553 | STDMETHODIMP CTestNotify::Visual(QWORD qTimeStamp, WCHAR cIPAPhoneme, WCHAR cEnginePhoneme, DWORD dwHints, PTTSMOUTH pTTSMouth) 554 | { 555 | if (!pTTSMouth) 556 | return NOERROR; 557 | 558 | /*HRESULT ret = m_pImpl->m_pITTSCentral->PosnGet(&qTimeStamp); 559 | qDebug() << ret;*/ 560 | 561 | /*RECT r; 562 | HWND hWndMouth; 563 | hWndMouth = ::GetDlgItem(m_pCTTSAPPDlg->m_hWnd, IDC_MOUTHBOX); 564 | HDC hdc = GetDC(hWndMouth); 565 | ::GetClientRect(hWndMouth, &r); 566 | PaintToDC(hdc, &r, pTTSMouth); 567 | 568 | ReleaseDC(hWndMouth, hdc);*/ 569 | 570 | return NOERROR; 571 | } 572 | 573 | /************************************************************************* 574 | CTestBufNotify - Notification object. 575 | */ 576 | CTestBufNotify::CTestBufNotify(CTTS4 *pImpl) 577 | { 578 | m_pImpl = pImpl; 579 | } 580 | 581 | CTestBufNotify::~CTestBufNotify(void) 582 | { 583 | // this space intentionally left blank 584 | } 585 | 586 | STDMETHODIMP CTestBufNotify::QueryInterface(REFIID riid, LPVOID *ppv) 587 | { 588 | *ppv = NULL; 589 | 590 | /* always return our IUnknown for IID_IUnknown */ 591 | if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_ITTSBufNotifySink)) 592 | { 593 | *ppv = (LPVOID)this; 594 | return S_OK; 595 | } 596 | 597 | // otherwise, cant find 598 | return ResultFromScode(E_NOINTERFACE); 599 | } 600 | 601 | STDMETHODIMP_(ULONG) CTestBufNotify::AddRef(void) 602 | { 603 | // normally this increases a reference count, but this object 604 | // is going to be freed as soon as the app is freed, so it doesn't 605 | // matter 606 | return 1; 607 | } 608 | 609 | STDMETHODIMP_(ULONG) CTestBufNotify::Release(void) 610 | { 611 | // normally this releases a reference count, but this object 612 | // is going to be freed when the application is freed so it doesnt 613 | // matter 614 | return 1; 615 | } 616 | 617 | STDMETHODIMP CTestBufNotify::BookMark(QWORD qTimeStamp, DWORD dwMarkNum) 618 | { 619 | return NOERROR; 620 | } 621 | 622 | STDMETHODIMP CTestBufNotify::TextDataDone(QWORD qTimeStamp, DWORD dwFlags) 623 | { 624 | return NOERROR; 625 | } 626 | 627 | STDMETHODIMP CTestBufNotify::TextDataStarted(QWORD qTimeStamp) 628 | { 629 | return NOERROR; 630 | } 631 | 632 | STDMETHODIMP CTestBufNotify::WordPosition(QWORD qTimeStamp, DWORD dwByteOffset) 633 | { 634 | m_pImpl->OnProgress(dwByteOffset / sizeof(wchar_t), 0, m_pImpl->m_BufferLength); 635 | return NOERROR; 636 | } 637 | 638 | -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS4.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TTS.h" 4 | 5 | #include 6 | //#include 7 | #include "../Sapi4/Include/speech.h" 8 | 9 | class CTestNotify; 10 | class CTestBufNotify; 11 | 12 | class CTTS4: public CTTS_Impl 13 | { 14 | public: 15 | CTTS4(); 16 | virtual ~CTTS4(); 17 | 18 | bool Speak(const std::wstring& str, bool ProcessXML = false); 19 | bool Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML = false); 20 | void Pause(); 21 | void Skip(int SkipNum) {} 22 | void Inject(const std::wstring& str); 23 | void Stop(); 24 | 25 | void SetRate(int Rate); 26 | int GetRate(); 27 | void SetPitch(int Pitch); 28 | int GetPitch(); 29 | void SetVolume(int Volume); 30 | int GetVolume(); 31 | 32 | virtual std::vector GetVoices(); 33 | bool SelectVoice(const std::wstring& name); 34 | 35 | void ShowGeneralWnd(HWND wnd); 36 | 37 | bool EnumVoices(const std::wstring& regKey = L""); 38 | void ClearVoices(); 39 | 40 | protected: 41 | friend class CTestNotify; 42 | friend class CTestBufNotify; 43 | 44 | BOOL InitTTS(void); 45 | BOOL TerminateTTS(void); 46 | 47 | struct SVoice4 : SVoice { 48 | GUID guid; 49 | }; 50 | 51 | bool VoiceChange(SVoice4* pVoice, PIAUDIOFILE dev = NULL); 52 | 53 | std::map m_Voices; 54 | 55 | PITTSENUM m_pITTSEnum; 56 | PITTSCENTRAL m_pITTSCentral; 57 | PITTSATTRIBUTES m_pITTSAttributes; 58 | PITTSDIALOGS m_pITTSDialogs; 59 | PILEXPRONOUNCE m_pILexPronounce; 60 | CTestNotify* m_pTestNotify; 61 | CTestBufNotify* m_pTestBufNotify; 62 | #ifdef DIRECTSOUND 63 | PIAUDIODIRECT m_pIAD; 64 | #else 65 | PIAUDIOMULTIMEDIADEVICE m_pIMMD; 66 | #endif 67 | PIAUDIOFILE m_pIAF; 68 | DWORD m_dwRegKey; 69 | 70 | GUID m_guid; 71 | 72 | int m_BufferLength; 73 | }; 74 | 75 | 76 | class CTestNotify : public ITTSNotifySink { 77 | private: 78 | CTTS4 *m_pImpl; 79 | public: 80 | CTestNotify(CTTS4 *pImpl); 81 | ~CTestNotify(void); 82 | 83 | // IUnkown members that delegate to m_punkOuter 84 | // Non-delegating object IUnknown 85 | STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); 86 | STDMETHODIMP_(ULONG) AddRef(void); 87 | STDMETHODIMP_(ULONG) Release(void); 88 | 89 | // ITTSNotifySink 90 | STDMETHOD(AttribChanged) (DWORD); 91 | STDMETHOD(AudioStart) (QWORD); 92 | STDMETHOD(AudioStop) (QWORD); 93 | STDMETHOD(Visual) (QWORD, WCHAR, WCHAR, DWORD, PTTSMOUTH); 94 | }; 95 | 96 | class CTestBufNotify : public ITTSBufNotifySink { 97 | private: 98 | CTTS4 *m_pImpl; 99 | public: 100 | CTestBufNotify(CTTS4 *pImpl); 101 | ~CTestBufNotify(void); 102 | 103 | // IUnkown members that delegate to m_punkOuter 104 | // Non-delegating object IUnknown 105 | STDMETHODIMP QueryInterface(REFIID, LPVOID FAR *); 106 | STDMETHODIMP_(ULONG) AddRef(void); 107 | STDMETHODIMP_(ULONG) Release(void); 108 | 109 | // ITTSNotifySink 110 | STDMETHOD(BookMark) (QWORD, DWORD); 111 | STDMETHOD(TextDataDone) (QWORD, DWORD); 112 | STDMETHOD(TextDataStarted) (QWORD); 113 | STDMETHOD(WordPosition) (QWORD, DWORD); 114 | }; 115 | 116 | -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS5.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TTS5.h" 3 | 4 | const SPSTREAMFORMAT g_aOutputFormat[NUM_OUTPUTFORMATS] = { 5 | SPSF_8kHz8BitMono, SPSF_8kHz8BitStereo, SPSF_8kHz16BitMono, SPSF_8kHz16BitStereo, 6 | SPSF_11kHz8BitMono, SPSF_11kHz8BitStereo, SPSF_11kHz16BitMono, SPSF_11kHz16BitStereo, 7 | SPSF_12kHz8BitMono, SPSF_12kHz8BitStereo, SPSF_12kHz16BitMono, SPSF_12kHz16BitStereo, 8 | SPSF_16kHz8BitMono, SPSF_16kHz8BitStereo, SPSF_16kHz16BitMono, SPSF_16kHz16BitStereo, 9 | SPSF_22kHz8BitMono, SPSF_22kHz8BitStereo, SPSF_22kHz16BitMono, SPSF_22kHz16BitStereo, 10 | SPSF_24kHz8BitMono, SPSF_24kHz8BitStereo, SPSF_24kHz16BitMono, SPSF_24kHz16BitStereo, 11 | SPSF_32kHz8BitMono, SPSF_32kHz8BitStereo, SPSF_32kHz16BitMono, SPSF_32kHz16BitStereo, 12 | SPSF_44kHz8BitMono, SPSF_44kHz8BitStereo, SPSF_44kHz16BitMono, SPSF_44kHz16BitStereo, 13 | SPSF_48kHz8BitMono, SPSF_48kHz8BitStereo, SPSF_48kHz16BitMono, SPSF_48kHz16BitStereo }; 14 | 15 | TCHAR* g_aszOutputFormat[NUM_OUTPUTFORMATS] = { 16 | _T("8kHz 8 Bit Mono"), _T("8kHz 8 Bit Stereo"), _T("8kHz 16 Bit Mono"), _T("8kHz 16 Bit Stereo"), 17 | _T("11kHz 8 Bit Mono"), _T("11kHz 8 Bit Stereo"), _T("11kHz 16 Bit Mono"), _T("11kHz 16 Bit Stereo"), 18 | _T("12kHz 8 Bit Mono"), _T("12kHz 8 Bit Stereo"), _T("12kHz 16 Bit Mono"), _T("12kHz 16 Bit Stereo"), 19 | _T("16kHz 8 Bit Mono"), _T("16kHz 8 Bit Stereo"), _T("16kHz 16 Bit Mono"), _T("16kHz 16 Bit Stereo"), 20 | _T("22kHz 8 Bit Mono"), _T("22kHz 8 Bit Stereo"), _T("22kHz 16 Bit Mono"), _T("22kHz 16 Bit Stereo"), 21 | _T("24kHz 8 Bit Mono"), _T("24kHz 8 Bit Stereo"), _T("24kHz 16 Bit Mono"), _T("24kHz 16 Bit Stereo"), 22 | _T("32kHz 8 Bit Mono"), _T("32kHz 8 Bit Stereo"), _T("32kHz 16 Bit Mono"), _T("32kHz 16 Bit Stereo"), 23 | _T("44kHz 8 Bit Mono"), _T("44kHz 8 Bit Stereo"), _T("44kHz 16 Bit Mono"), _T("44kHz 16 Bit Stereo"), 24 | _T("48kHz 8 Bit Mono"), _T("48kHz 8 Bit Stereo"), _T("48kHz 16 Bit Mono"), _T("48kHz 16 Bit Stereo") }; 25 | 26 | CTTS5::CTTS5() 27 | { 28 | m_DefaultFormatIndex = 0; 29 | 30 | m_BufferLength = 0; 31 | 32 | m_pTocken = NULL; 33 | 34 | HRESULT hr; 35 | 36 | hr = m_cpVoice.CoCreateInstance(CLSID_SpVoice); 37 | 38 | if (SUCCEEDED(hr)) 39 | { 40 | CreateWnd(); 41 | 42 | SetupSapi(); 43 | 44 | //EnumVoices(); 45 | } 46 | } 47 | 48 | LRESULT CALLBACK CTTS5::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 49 | { 50 | CTTS5* pThis = (CTTS5 *)::GetWindowLong(hwnd, GWL_USERDATA); 51 | switch (uMsg) 52 | { 53 | case WM_TTSAPPCUSTOMEVENT: 54 | pThis->MainHandleSynthEvent(); 55 | return TRUE; 56 | } 57 | return TRUE; 58 | } 59 | 60 | void CTTS5::CreateWnd() 61 | { 62 | //Create window 63 | WNDCLASSEX wndclass; 64 | wndclass.cbSize = sizeof wndclass; 65 | wndclass.style = 0; 66 | wndclass.lpfnWndProc = WindowProc; 67 | wndclass.cbClsExtra = 0; 68 | wndclass.cbWndExtra = 0; 69 | wndclass.hInstance = GetModuleHandle(0); 70 | wndclass.hIcon = 0; 71 | wndclass.hCursor = 0; 72 | wndclass.hbrBackground = 0; 73 | wndclass.lpszMenuName = 0; 74 | wndclass.lpszClassName = WND_SAPI_HELPER; 75 | wndclass.hIconSm = 0; 76 | RegisterClassEx(&wndclass); 77 | 78 | m_hWnd = CreateWindow(WND_SAPI_HELPER, WND_SAPI_HELPER, 0, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(0)); 79 | SetWindowLong(m_hWnd, GWL_USERDATA, (LONG)this); 80 | } 81 | 82 | CTTS5::~CTTS5() 83 | { 84 | DestroyWindow(m_hWnd); 85 | 86 | ClearVoices(); 87 | } 88 | 89 | void CTTS5::MainHandleSynthEvent() 90 | { 91 | CSpEvent event; 92 | HRESULT hr = S_OK; 93 | 94 | while (event.GetFrom(m_cpVoice) == S_OK) 95 | { 96 | switch (event.eEventId) 97 | { 98 | case SPEI_START_INPUT_STREAM: 99 | 100 | break; 101 | 102 | case SPEI_END_INPUT_STREAM: 103 | // Set global boolean stop to TRUE when finished speaking 104 | m_bStop = TRUE; 105 | OnStop(); 106 | 107 | break; 108 | 109 | case SPEI_VOICE_CHANGE: 110 | 111 | break; 112 | 113 | case SPEI_TTS_BOOKMARK: 114 | // event.String() 115 | break; 116 | 117 | case SPEI_WORD_BOUNDARY: 118 | { 119 | if (m_bStop) 120 | break; 121 | 122 | SPVOICESTATUS Stat; 123 | 124 | hr = m_cpVoice->GetStatus(&Stat, NULL); 125 | 126 | OnProgress(Stat.ulInputWordPos, Stat.ulInputWordLen, m_BufferLength); 127 | 128 | break; 129 | } 130 | case SPEI_PHONEME: 131 | 132 | break; 133 | 134 | case SPEI_VISEME: 135 | // Get the current mouth viseme position and map it to one of the 136 | // 7 mouth bitmaps. 137 | /*g_iBmp = g_aMapVisemeToImage[event.Viseme()]; // current viseme 138 | 139 | InvalidateRect(m_hChildWnd, NULL, FALSE); 140 | */ 141 | break; 142 | 143 | case SPEI_SENTENCE_BOUNDARY: 144 | 145 | break; 146 | 147 | case SPEI_TTS_AUDIO_LEVEL: 148 | //printf(L"Audio level: %d\r\n", (ULONG)event.wParam); 149 | break; 150 | 151 | case SPEI_TTS_PRIVATE: 152 | 153 | break; 154 | 155 | default: 156 | break; 157 | } 158 | } 159 | } 160 | 161 | BOOL CTTS5::SetupSapi() 162 | { 163 | HRESULT hr = S_OK; 164 | 165 | if (!m_cpVoice) 166 | { 167 | hr = E_FAIL; 168 | } 169 | 170 | // Set the default output format as the current selection. 171 | if (SUCCEEDED(hr)) 172 | { 173 | CComPtr cpStream; 174 | HRESULT hrOutputStream = m_cpVoice->GetOutputStream(&cpStream); 175 | 176 | if (hrOutputStream == S_OK) 177 | { 178 | CSpStreamFormat Fmt; 179 | hr = Fmt.AssignFormat(cpStream); 180 | if (SUCCEEDED(hr)) 181 | { 182 | SPSTREAMFORMAT eFmt = Fmt.ComputeFormatEnum(); 183 | for (int i = 0; i < NUM_OUTPUTFORMATS; i++) 184 | { 185 | if (g_aOutputFormat[i] == eFmt) 186 | m_DefaultFormatIndex = i; 187 | } 188 | } 189 | } 190 | } 191 | 192 | // Use the SAPI5 helper function in sphelper.h to initialize the Voice combo box. 193 | /*if (SUCCEEDED(hr)) 194 | { 195 | EnumVoices(); 196 | }*/ 197 | 198 | if (SUCCEEDED(hr)) 199 | { 200 | SpCreateDefaultObjectFromCategoryId(SPCAT_AUDIOOUT, &m_cpOutAudio); 201 | } 202 | 203 | // Set default voice data 204 | //VoiceChange(); 205 | 206 | // Set the notification message for the voice 207 | if (SUCCEEDED(hr)) 208 | { 209 | m_cpVoice->SetNotifyWindowMessage(m_hWnd, WM_TTSAPPCUSTOMEVENT, 0, 0); 210 | } 211 | 212 | // We're interested in all TTS events 213 | if (SUCCEEDED(hr)) 214 | { 215 | hr = m_cpVoice->SetInterest(SPFEI_ALL_TTS_EVENTS, SPFEI_ALL_TTS_EVENTS); 216 | } 217 | 218 | return SUCCEEDED(hr); 219 | } 220 | 221 | bool CTTS5::EnumVoices(const std::wstring& regKey) 222 | { 223 | HRESULT hr; 224 | ISpObjectToken * pToken; // NOTE: Not a CComPtr! Be Careful. 225 | CComPtr cpEnum; 226 | hr = SpEnumTokens(regKey.empty() ? SPCAT_VOICES : regKey.c_str(), NULL /*pszRequiredAttrib*/, NULL /*pszOptionalAttrib*/, &cpEnum); 227 | if (hr != S_OK) 228 | return false; 229 | 230 | while (cpEnum->Next(1, &pToken, NULL) == S_OK) 231 | { 232 | CSpDynamicString dstrDesc; 233 | hr = SpGetDescription(pToken, &dstrDesc); 234 | if (SUCCEEDED(hr)) 235 | { 236 | LANGID langID; 237 | hr = SpGetLanguageFromToken(pToken, &langID); 238 | 239 | std::wstring name(dstrDesc.m_psz); 240 | 241 | if (m_Voices.find(name) == m_Voices.end()) 242 | { 243 | CComPtr cpDataKeyAttribs; 244 | hr = pToken->OpenKey(SPTOKENKEY_ATTRIBUTES, &cpDataKeyAttribs); 245 | 246 | CSpDynamicString Vendor, Gender, Age; 247 | //cpDataKeyAttribs->GetStringValue(L"Language", &langId); 248 | cpDataKeyAttribs->GetStringValue(L"Vendor", &Vendor); 249 | cpDataKeyAttribs->GetStringValue(L"Gender", &Gender); 250 | cpDataKeyAttribs->GetStringValue(L"Age", &Age); 251 | 252 | SVoice5* pVoice = new SVoice5(); 253 | pVoice->Name = name; 254 | pVoice->Vendor = std::wstring(Vendor); 255 | if (wcscmp(Gender, L"Elderly") == 0) 256 | pVoice->Age = SVoice5::eElderly; 257 | else if (wcscmp(Gender, L"Child") == 0) 258 | pVoice->Age = SVoice5::eChild; 259 | else 260 | pVoice->Age = SVoice5::eAdult; 261 | if (wcscmp(Gender, L"Male") == 0) 262 | pVoice->Gender = SVoice5::eMale; 263 | else if (wcscmp(Gender, L"Female") == 0) 264 | pVoice->Gender = SVoice5::eFemale; 265 | else 266 | pVoice->Gender = SVoice5::eNeutral; 267 | pVoice->LangID = langID; 268 | WCHAR strNameBuffer[LOCALE_NAME_MAX_LENGTH+1]; 269 | //LCIDToLocaleName(pVoice->LangID, strNameBuffer, LOCALE_NAME_MAX_LENGTH, 0); 270 | GetLocaleInfoW(MAKELCID(pVoice->LangID, SORT_DEFAULT), LOCALE_SENGLANGUAGE, strNameBuffer, LOCALE_NAME_MAX_LENGTH); 271 | pVoice->Lang = strNameBuffer; 272 | pVoice->Sapi4 = false; 273 | pVoice->pToken = pToken; 274 | m_Voices[name] = pVoice; 275 | } 276 | else 277 | hr = E_FAIL; 278 | } 279 | if (FAILED(hr)) 280 | { 281 | pToken->Release(); 282 | } 283 | } 284 | 285 | return true; 286 | } 287 | 288 | void CTTS5::ClearVoices() 289 | { 290 | for(std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 291 | { 292 | I->second->pToken->Release(); 293 | delete I->second; 294 | } 295 | m_Voices.clear(); 296 | } 297 | 298 | HRESULT CTTS5::VoiceChange(SVoice5* pVoice) 299 | { 300 | if (m_pTocken == pVoice->pToken) 301 | return S_OK; 302 | m_pTocken = pVoice->pToken; 303 | 304 | HRESULT hr = S_OK; 305 | GUID* pguidAudioFormat = NULL; 306 | int iFormat = 0; 307 | 308 | // Get the token associated with the selected voice 309 | ISpObjectToken* pToken = pVoice->pToken; 310 | 311 | //Determine if it is the current voice 312 | CComPtr pOldToken; 313 | hr = m_cpVoice->GetVoice(&pOldToken); 314 | 315 | if (SUCCEEDED(hr)) 316 | { 317 | if (pOldToken != pToken) 318 | { 319 | // Stop speaking. This is not necesary, for the next call to work, 320 | // but just to show that we are changing voices. 321 | hr = m_cpVoice->Speak(NULL, SPF_PURGEBEFORESPEAK, 0); 322 | // And set the new voice on the global voice object 323 | if (SUCCEEDED(hr)) 324 | { 325 | hr = m_cpVoice->SetVoice(pToken); 326 | } 327 | } 328 | } 329 | 330 | if (SUCCEEDED(hr)) 331 | { 332 | long DefaultRate; 333 | hr = m_cpVoice->GetRate(&DefaultRate); 334 | m_DefaultRate = DefaultRate; 335 | m_MinRate = SPMIN_RATE; 336 | m_MaxRate = SPMAX_RATE; 337 | } 338 | 339 | m_MinPitch = 0; 340 | m_MaxPitch = 0; 341 | 342 | if (SUCCEEDED(hr)) 343 | { 344 | USHORT DefaultVolume; 345 | hr = m_cpVoice->GetVolume(&DefaultVolume); 346 | m_DefaultVolume = DefaultVolume; 347 | m_MinVolume = SPMIN_VOLUME; 348 | m_MaxVolume = SPMAX_VOLUME; 349 | } 350 | 351 | return hr; 352 | } 353 | 354 | std::vector CTTS5::GetVoices() 355 | { 356 | std::vector list; 357 | for (std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 358 | list.push_back(I->second); 359 | return list; 360 | } 361 | 362 | bool CTTS5::SelectVoice(const std::wstring& name) 363 | { 364 | for (std::map::iterator I = m_Voices.begin(); I != m_Voices.end(); ++I) 365 | { 366 | if (I->second->Name == name) 367 | return VoiceChange(I->second) == S_OK; 368 | } 369 | return false; 370 | } 371 | 372 | bool CTTS5::Speak(const std::wstring& str, bool ProcessXML) 373 | { 374 | HRESULT hr = S_OK; 375 | 376 | if (m_bPause) 377 | Stop(); 378 | 379 | m_bStop = FALSE; 380 | 381 | m_BufferLength = str.length(); 382 | 383 | hr = m_cpVoice->Speak(str.c_str(), SPF_ASYNC | (ProcessXML ? SPF_IS_XML : SPF_IS_NOT_XML), 0); 384 | 385 | if (SUCCEEDED(hr)) 386 | { 387 | m_bPause = FALSE; 388 | hr = m_cpVoice->Resume(); 389 | } 390 | 391 | return SUCCEEDED(hr); 392 | } 393 | 394 | void CTTS5::Pause() 395 | { 396 | if (m_bStop) 397 | return; 398 | 399 | if (!m_bPause) 400 | { 401 | m_cpVoice->Pause(); 402 | m_bPause = TRUE; 403 | } 404 | else 405 | { 406 | m_cpVoice->Resume(); 407 | m_bPause = FALSE; 408 | } 409 | } 410 | 411 | void CTTS5::Skip(int SkipNum) 412 | { 413 | ULONG ulGarbage = 0; 414 | WCHAR szGarbage[] = L"Sentence"; // only supported type 415 | m_cpVoice->Skip(szGarbage, SkipNum, &ulGarbage); 416 | } 417 | 418 | void CTTS5::Stop() 419 | { 420 | bool bWasPaused = m_bPause; 421 | 422 | m_bPause = false; 423 | m_bStop = true; 424 | 425 | // Stop current rendering with a PURGEBEFORESPEAK... 426 | HRESULT hr = m_cpVoice->Speak(NULL, SPF_PURGEBEFORESPEAK, 0); 427 | 428 | if (bWasPaused) 429 | OnStop(); 430 | } 431 | 432 | void CTTS5::SetRate(int Rate) 433 | { 434 | m_cpVoice->SetRate(Rate); 435 | } 436 | 437 | int CTTS5::GetRate() 438 | { 439 | long DefaultRate; 440 | m_cpVoice->GetRate(&DefaultRate); 441 | return DefaultRate; 442 | } 443 | 444 | void CTTS5::SetVolume(int Volume) 445 | { 446 | m_cpVoice->SetVolume(Volume); 447 | } 448 | 449 | int CTTS5::GetVolume() 450 | { 451 | USHORT DefaultVolume; 452 | m_cpVoice->GetVolume(&DefaultVolume); 453 | return DefaultVolume; 454 | } 455 | 456 | void CTTS5::SetFormat(SPSTREAMFORMAT eFmt) 457 | { 458 | HRESULT hr = S_OK; 459 | 460 | CSpStreamFormat Fmt; 461 | Fmt.AssignFormat(eFmt); 462 | if (m_cpOutAudio) 463 | { 464 | hr = m_cpOutAudio->SetFormat(Fmt.FormatId(), Fmt.WaveFormatExPtr()); 465 | } 466 | else 467 | { 468 | hr = E_FAIL; 469 | } 470 | 471 | if (SUCCEEDED(hr)) 472 | { 473 | hr = m_cpVoice->SetOutput(m_cpOutAudio, FALSE); 474 | } 475 | } 476 | 477 | bool CTTS5::Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML) 478 | { 479 | CComPtr cpWavStream; 480 | CComPtr cpOldStream; 481 | HRESULT hr = S_OK; 482 | bool Ret = false; 483 | 484 | CSpStreamFormat OriginalFmt; 485 | hr = m_cpVoice->GetOutputStream(&cpOldStream); 486 | if (hr == S_OK) 487 | { 488 | hr = OriginalFmt.AssignFormat(cpOldStream); 489 | } 490 | else 491 | { 492 | hr = E_FAIL; 493 | } 494 | // User SAPI helper function in sphelper.h to create a wav file 495 | if (SUCCEEDED(hr)) 496 | { 497 | hr = SPBindToFile(path.c_str(), SPFM_CREATE_ALWAYS, &cpWavStream, &OriginalFmt.FormatId(), OriginalFmt.WaveFormatExPtr()); 498 | } 499 | if (SUCCEEDED(hr)) 500 | { 501 | // Set the voice's output to the wav file instead of the speakers 502 | hr = m_cpVoice->SetOutput(cpWavStream, TRUE); 503 | } 504 | 505 | if (SUCCEEDED(hr)) 506 | { 507 | // Do the Speak 508 | Ret = Speak(str, ProcessXML); 509 | } 510 | 511 | // Set output back to original stream 512 | // Wait until the speak is finished if saving to a wav file so that 513 | // the smart pointer cpWavStream doesn't get released before its 514 | // finished writing to the wav. 515 | m_cpVoice->WaitUntilDone(INFINITE); 516 | cpWavStream.Release(); 517 | 518 | // Reset output 519 | m_cpVoice->SetOutput(cpOldStream, FALSE); 520 | 521 | return Ret; 522 | } 523 | 524 | 525 | /* 526 | CComPtr cpWavStream; 527 | WCHAR szwWavFileName[NORM_SIZE] = L"";; 528 | 529 | USES_CONVERSION; 530 | wcscpy( szwWavFileName, T2W( szAFileName ) ); 531 | 532 | // User helper function found in sphelper.h to open the wav file and 533 | // get back an IStream pointer to pass to SpeakStream 534 | hr = SPBindToFile( szwWavFileName, SPFM_OPEN_READONLY, &cpWavStream ); 535 | 536 | if( SUCCEEDED( hr ) ) 537 | { 538 | hr = m_cpVoice->SpeakStream( cpWavStream, SPF_ASYNC, NULL ); 539 | } 540 | 541 | if( FAILED( hr ) ) 542 | { 543 | TTSAppStatusMessage( m_hWnd, _T("Speak error\r\n") ); 544 | } 545 | */ -------------------------------------------------------------------------------- /UltraTTS/Sapi/TTS5.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TTS.h" 4 | 5 | #include // Required for showing property page 6 | #include // SAPI includes 7 | #include 8 | #include 9 | 10 | #define WM_TTSAPPCUSTOMEVENT WM_APP // Window message used for systhesis events 11 | #define WND_SAPI_HELPER _T("CTTS5 Helper Window") 12 | #define NUM_OUTPUTFORMATS 36 13 | 14 | class CTTS5: public CTTS_Impl 15 | { 16 | public: 17 | CTTS5(); 18 | virtual ~CTTS5(); 19 | 20 | bool Speak(const std::wstring& str, bool ProcessXML = false); 21 | bool Speak2Wave(const std::wstring& path, const std::wstring& str, bool ProcessXML = false); 22 | void Pause(); 23 | void Skip(int SkipNum); 24 | void Inject(const std::wstring& str) {} 25 | void Stop(); 26 | 27 | void SetRate(int Rate); 28 | int GetRate(); 29 | void SetPitch(int Pitch) {} 30 | int GetPitch() { return 0; } 31 | void SetVolume(int Volume); 32 | int GetVolume(); 33 | void SetFormat(SPSTREAMFORMAT Format); 34 | 35 | virtual std::vector GetVoices(); 36 | bool SelectVoice(const std::wstring& name); 37 | 38 | bool EnumVoices(const std::wstring& regKey = L""); 39 | void ClearVoices(); 40 | 41 | protected: 42 | static LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 43 | void MainHandleSynthEvent(); 44 | 45 | void CreateWnd(); 46 | BOOL SetupSapi(); 47 | 48 | struct SVoice5: SVoice { 49 | ISpObjectToken* pToken; 50 | }; 51 | 52 | HRESULT VoiceChange(SVoice5* pVoice); 53 | 54 | CComPtr m_cpVoice; 55 | CComPtr m_cpOutAudio; 56 | 57 | HWND m_hWnd; 58 | 59 | int m_DefaultFormatIndex; 60 | 61 | std::map m_Voices; 62 | 63 | int m_BufferLength; 64 | 65 | ISpObjectToken* m_pTocken; 66 | }; -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #if defined(QT_PRINTSUPPORT_LIB) 8 | #include 9 | #if QT_CONFIG(printer) 10 | #if QT_CONFIG(printdialog) 11 | #include 12 | #endif // QT_CONFIG(printdialog) 13 | #include 14 | #endif // QT_CONFIG(printer) 15 | #endif // QT_PRINTSUPPORT_LIB 16 | #include 17 | #include 18 | #include 19 | #include "UltraTTS.h" 20 | #include "OptionsDlg.h" 21 | 22 | #include "Sapi/TTS.h" 23 | 24 | 25 | #include "Utils/LangDetect.h" 26 | #include "Utils/Functions.h" 27 | 28 | #include "../UGlobalHotkey/uglobalhotkeys.h" 29 | 30 | 31 | #define HK_READ 1 32 | #define HK_READ_NOW 2 33 | #define HK_PAUSE 3 34 | #define HK_NEXT 4 35 | #define HK_PREV 5 36 | #define HK_STOP 6 37 | #define HK_COPY 7 38 | 39 | QString CUltraTTS::STab::name() 40 | { 41 | if (bReader) 42 | return CUltraTTS::tr("Clipboard Reader"); 43 | QString Name = QFileInfo(fileName).fileName(); 44 | if (Name.isEmpty()) 45 | return CUltraTTS::tr("NewFile.txt"); 46 | return Name; 47 | } 48 | 49 | CUltraTTS::CUltraTTS(QWidget *parent) 50 | : QMainWindow(parent) 51 | { 52 | ui.setupUi(this); 53 | // Disable menu actions for unavailable features 54 | #if !QT_CONFIG(printer) 55 | ui.actionPrint->setEnabled(false); 56 | #endif 57 | 58 | #if !QT_CONFIG(clipboard) 59 | ui.actionCut->setEnabled(false); 60 | ui.actionCopy->setEnabled(false); 61 | ui.actionPaste->setEnabled(false); 62 | #endif 63 | 64 | ui.actionPause->setCheckable(true); 65 | ui.actionPause->setEnabled(false); 66 | ui.actionStop->setEnabled(false); 67 | 68 | ui.textEdit->deleteLater(); 69 | 70 | m_pTabs = new QTabWidget(); 71 | 72 | ui.verticalLayout->addWidget(m_pTabs); 73 | 74 | m_pReadEdit = NULL; 75 | m_pTab = NULL; 76 | 77 | on_actionNew_triggered(); 78 | 79 | m_pTabs->setTabsClosable(true); 80 | QTabBar* pTabBar = m_pTabs->tabBar(); 81 | /*m_TabOffset = m_pTabs->count(); 82 | for (int i = 0; i < m_TabOffset; i++) 83 | pTabBar->setTabButton(i, static_cast(pTabBar->style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, pTabBar)), 0);*/ 84 | connect(pTabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(on_close_tab(int))); 85 | connect(m_pTabs, SIGNAL(currentChanged(int)), this, SLOT(on_tab(int))); 86 | 87 | m_pProgress = new QLabel(); 88 | m_pProgress->setMinimumWidth(50); 89 | ui.statusBar->addPermanentWidget(m_pProgress); 90 | 91 | /*ui.voiceList->deleteLater(); 92 | ui.voiceList = new CComboBoxEx(); 93 | ui.horizontalLayout->insertWidget(1, ui.voiceList);*/ 94 | 95 | 96 | ui.voiceList->setItemDelegate(new QItemDelegateEx()); 97 | //QAbstractItemDelegate* x = ui.voiceList->itemDelegate(); 98 | 99 | m_pVoices = new QStandardItemModelEx(); 100 | ui.voiceList->setModel(m_pVoices); 101 | 102 | connect(ui.voiceList, SIGNAL(currentIndexChanged(int)), SLOT(on_voice_selected(int))); 103 | 104 | connect(ui.sliderRate, SIGNAL(valueChanged(int)), SLOT(on_rate(int))); 105 | connect(ui.sliderPitch, SIGNAL(valueChanged(int)), SLOT(on_pitch(int))); 106 | connect(ui.sliderVolume, SIGNAL(valueChanged(int)), SLOT(on_volume(int))); 107 | 108 | connect(ui.btnReloadSAPI, SIGNAL(clicked()), SLOT(on_reload_sapi())); 109 | 110 | connect(ui.chkFilter, SIGNAL(stateChanged(int)), SLOT(on_filter(int))); 111 | connect(m_pVoices, SIGNAL(itemChanged(QStandardItem*)), SLOT(on_filter_change(QStandardItem*))); 112 | 113 | m_pCfg = new QSettings(QApplication::applicationDirPath() + "/UltraTTS.ini", QSettings::IniFormat, this); 114 | 115 | m_SelectedVoices = m_pCfg->value("TTS_Selection").toStringList(); 116 | 117 | m_bHold = false; 118 | 119 | m_bAuto = true; 120 | m_SectionIndex = -1; 121 | m_TotalLength = 0; 122 | m_PassedLength = 0; 123 | 124 | m_bGrabAndRead = false; 125 | 126 | m_pTTS = CTTS::NewTTS(); 127 | 128 | CUltraTTS* that = this; 129 | m_pTTS->SetCallBacks([that]() { 130 | that->OnStop(); 131 | }, [that](int pos, int len, int total) { 132 | that->OnProgress(pos, len, total); 133 | }); 134 | 135 | ui.chkFilter->setCheckState((Qt::CheckState)(m_pCfg->value("TTS_Filter").toInt())); 136 | 137 | m_pTTS->SetRate(m_pCfg->value("TTS_Rate", 0).toInt()); 138 | m_pTTS->SetVolume(m_pCfg->value("TTS_Volume", 100).toInt()); 139 | 140 | ReloadVoices(); 141 | 142 | if (m_bAuto) 143 | { 144 | QString Lang; 145 | const LANGID langId = GetUserDefaultUILanguage(); 146 | WCHAR langName[1000] = { 0 }; 147 | GetLocaleInfoW(MAKELCID(langId, SORT_DEFAULT), LOCALE_SENGLANGUAGE, langName, sizeof langName / sizeof langName[0] - 1); 148 | Lang = QString::fromWCharArray(langName); 149 | 150 | QString Speaker = m_pCfg->value(Lang + "_Speaker", "").toString(); 151 | if (!Speaker.isEmpty()) 152 | SelectSpeaker(Speaker); 153 | } 154 | 155 | m_pHotkeyManager = new UGlobalHotkeys(this); 156 | connect(m_pHotkeyManager, SIGNAL(activated(size_t)), SLOT(on_hot_key(size_t))); 157 | 158 | m_CbAction = eNone; 159 | m_CbTimeOut = 0; 160 | 161 | //connect(QApplication::clipboard(), SIGNAL(dataChanged()), SLOT(on_clipboard())); // this fails when vnc window is open 162 | 163 | SetupHKs(); 164 | 165 | QIcon Icon; 166 | Icon.addFile(":/images/font.png"); 167 | m_pTrayIcon = new QSystemTrayIcon(Icon, this); 168 | m_pTrayIcon->setToolTip(this->windowTitle()); 169 | connect(m_pTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(on_sys_tray(QSystemTrayIcon::ActivationReason))); 170 | 171 | m_pTrayMenu = new QMenu(); 172 | 173 | QAction* pRead = new QAction(tr("&Read Clipboard"), this); 174 | connect(pRead, SIGNAL(triggered()), this, SLOT(on_actionRead_Clipboard_triggered())); 175 | m_pTrayMenu->addAction(pRead); 176 | 177 | m_pTrayMenu->addSeparator(); 178 | 179 | QAction* pExit = new QAction(tr("E&xit"), m_pTrayMenu); 180 | connect(pExit, SIGNAL(triggered()), this, SLOT(on_actionExit_triggered())); 181 | m_pTrayMenu->addAction(pExit); 182 | 183 | if(m_pCfg->value("SysTray", true).toBool()) 184 | m_pTrayIcon->show(); 185 | else 186 | m_pTrayIcon->hide(); 187 | 188 | m_uTimerID = startTimer(250); 189 | } 190 | 191 | CUltraTTS::~CUltraTTS() 192 | { 193 | if(m_pTrayIcon->isVisible()) 194 | m_pTrayIcon->hide(); 195 | 196 | killTimer(m_uTimerID); 197 | 198 | delete m_pTTS; 199 | } 200 | 201 | void CUltraTTS::on_sys_tray(QSystemTrayIcon::ActivationReason Reason) 202 | { 203 | switch (Reason) 204 | { 205 | case QSystemTrayIcon::Context: 206 | m_pTrayMenu->popup(QCursor::pos()); 207 | break; 208 | case QSystemTrayIcon::DoubleClick: 209 | this->show(); 210 | this->setWindowState(this->windowState() & ~Qt::WindowMinimized | Qt::WindowActive); 211 | break; 212 | } 213 | } 214 | 215 | void CUltraTTS::changeEvent(QEvent *event) 216 | { 217 | if (event->type() == QEvent::WindowStateChange) 218 | { 219 | if (m_pCfg->value("SysTray", true).toBool()) { 220 | if(!m_pTrayIcon->isVisible()) // just in case 221 | m_pTrayIcon->show(); 222 | 223 | if (isMinimized() == true) 224 | this->hide(); 225 | } 226 | } 227 | 228 | return QMainWindow::changeEvent(event); 229 | } 230 | 231 | void CUltraTTS::SetupHKs() 232 | { 233 | m_pHotkeyManager->unregisterAllHotkeys(); 234 | 235 | SetupHK("CopyAndRead", HK_READ, "F1"); 236 | SetupHK("CopyAndReadNow", HK_READ_NOW, "Alt+F1"); 237 | SetupHK("PauseRead", HK_PAUSE, "Ctrl+F1"); 238 | SetupHK("ReadNext", HK_NEXT, "Shift+Ctrl+F1"); 239 | SetupHK("ReadPreviouse", HK_PREV, "Shift+Alt+F1"); 240 | SetupHK("StopReading", HK_STOP, "Ctrl+Alt+F1"); 241 | SetupHK("CopyAndAdd", HK_COPY, "Shift+F1"); 242 | //SetupHK("", HK_, "Shift+Alt+Ctrl+F1"); 243 | } 244 | 245 | void CUltraTTS::SetupHK(const QString& name, size_t id, const QString& seq) 246 | { 247 | if (m_pCfg->value("UseHotKey_" + name, true).toBool()) 248 | { 249 | QString HK = m_pCfg->value("HotKey_" + name, seq).toString(); 250 | if(!HK.isEmpty()) 251 | m_pHotkeyManager->registerHotkey(HK, id); 252 | } 253 | } 254 | 255 | void CUltraTTS::on_hot_key(size_t id) 256 | { 257 | switch (id) 258 | { 259 | case HK_READ: GrabAndRead(false); break; 260 | case HK_READ_NOW: GrabAndRead(true); break; 261 | case HK_PAUSE: on_actionPause_triggered(); break; 262 | case HK_NEXT: PlayNext(); break; 263 | case HK_PREV: PlayPrev(); break; 264 | case HK_STOP: on_actionStop_triggered(); break; 265 | case HK_COPY: GrabAndInsert(); break; 266 | } 267 | } 268 | 269 | void CUltraTTS::on_close_tab(int Index) 270 | { 271 | STab* pTab = m_Tabs.takeAt(Index); 272 | m_pTabs->removeTab(Index); 273 | if (m_pReadEdit == pTab->pEdit); 274 | m_pReadEdit = NULL; 275 | pTab->pEdit->deleteLater(); 276 | delete pTab; 277 | if (m_Tabs.isEmpty()) 278 | on_actionNew_triggered(); 279 | } 280 | 281 | void CUltraTTS::on_tab(int Index) 282 | { 283 | m_pTab = Index < 0 ? NULL : m_Tabs[Index]; 284 | } 285 | 286 | void CUltraTTS::on_reload_sapi() 287 | { 288 | ReloadVoices(); 289 | } 290 | 291 | void CUltraTTS::ReloadVoices() 292 | { 293 | QStringList Stores = m_pCfg->value("TTS_Stores").toStringList(); 294 | if (Stores.isEmpty()) 295 | { 296 | Stores.append(QString::fromWCharArray(CTTSApi::Voices_Cortana)); 297 | Stores.append(QString::fromWCharArray(CTTSApi::Voices_OneCore)); 298 | Stores.append(QString::fromWCharArray(CTTSApi::Voices_Platform)); 299 | Stores.append(QString::fromWCharArray(CTTSApi::Voices_Speech)); 300 | 301 | m_pCfg->setValue("TTS_Stores", Stores); 302 | } 303 | m_pCfg->sync(); 304 | 305 | 306 | m_pTTS->ClearVoices(); 307 | foreach(const QString& Store, Stores) 308 | m_pTTS->EnumVoices(Store.toStdWString()); 309 | 310 | if(m_pCfg->value("TTS_Sapi4", true).toBool()) 311 | m_pTTS->EnumVoices(); 312 | 313 | m_Voices = m_pTTS->GetVoices(); 314 | 315 | on_filter(ui.chkFilter->checkState()); 316 | } 317 | 318 | void CUltraTTS::on_voice_selected(int index) 319 | { 320 | if (index == -1 || m_bHold) 321 | return; 322 | 323 | QStandardItem* item = m_pVoices->item(index); 324 | if (!item) 325 | return; 326 | 327 | index = item->data(Qt::UserRole).toInt(); 328 | 329 | if (index == -1) { 330 | m_bAuto = true; 331 | return; 332 | } 333 | m_bAuto = false; 334 | 335 | SVoice* voice = m_Voices[index]; 336 | 337 | m_pCfg->setValue(QString::fromStdWString(voice->Lang) + "_Speaker", QString::fromStdWString(voice->Name)); 338 | 339 | SelectSpeaker(QString::fromStdWString(voice->Name)); 340 | } 341 | 342 | bool CUltraTTS::SelectSpeaker(const QString& Speaker) 343 | { 344 | if (!m_pTTS->SelectVoice(Speaker.toStdWString())) 345 | return false; 346 | 347 | m_bHold = true; 348 | 349 | ui.statusBar->showMessage(Speaker); 350 | 351 | ui.sliderRate->setRange(m_pTTS->GetMinRate(), m_pTTS->GetMaxRate()); 352 | ui.sliderRate->setValue(m_pTTS->GetRate()); 353 | ui.minRate->setText(QString::number(m_pTTS->GetMinRate())); 354 | ui.curRate->setText(QString::number(m_pTTS->GetRate())); 355 | ui.maxRate->setText(QString::number(m_pTTS->GetMaxRate())); 356 | 357 | ui.sliderPitch->setRange(m_pTTS->GetMinPitch(), m_pTTS->GetMaxPitch()); 358 | ui.sliderPitch->setValue(m_pTTS->GetPitch()); 359 | ui.minPitch->setText(QString::number(m_pTTS->GetMinPitch())); 360 | ui.curPitch->setText(QString::number(m_pTTS->GetPitch())); 361 | ui.maxPitch->setText(QString::number(m_pTTS->GetMaxPitch())); 362 | ui.sliderPitch->setEnabled(m_pTTS->GetMinPitch() != m_pTTS->GetMaxPitch()); 363 | 364 | ui.sliderVolume->setRange(m_pTTS->GetMinVolume(), m_pTTS->GetMaxVolume()); 365 | ui.sliderVolume->setValue(m_pTTS->GetVolume()); 366 | 367 | m_bHold = false; 368 | 369 | return true; 370 | } 371 | 372 | void CUltraTTS::on_rate(int index) 373 | { 374 | if (m_bHold) 375 | return; 376 | m_pCfg->setValue("TTS_Rate", index); 377 | m_pTTS->SetRate(index); 378 | ui.curRate->setText(QString::number(m_pTTS->GetRate())); 379 | } 380 | 381 | void CUltraTTS::on_pitch(int index) 382 | { 383 | if (m_bHold) 384 | return; 385 | m_pTTS->SetPitch(index); 386 | ui.curPitch->setText(QString::number(m_pTTS->GetPitch())); 387 | } 388 | 389 | void CUltraTTS::on_volume(int index) 390 | { 391 | if (m_bHold) 392 | return; 393 | m_pCfg->setValue("TTS_Volume", index); 394 | m_pTTS->SetVolume(index); 395 | //ui.curVolume->setText(QString::number(m_pTTS->GetVolume())); 396 | } 397 | 398 | void CUltraTTS::on_filter(int state) 399 | { 400 | m_bHold = true; 401 | 402 | m_pCfg->setValue("TTS_Filter", state); 403 | 404 | QMap > LangMap; 405 | for (int i = 0; i < m_Voices.size(); i++) { 406 | SVoice* pVoice = m_Voices[i]; 407 | 408 | if (state == Qt::Checked) 409 | { 410 | if (!m_SelectedVoices.contains(QString::fromStdWString(m_Voices[i]->Name))) 411 | continue; 412 | } 413 | 414 | LangMap[QString::fromStdWString(pVoice->Lang)].append(i); 415 | } 416 | 417 | m_pVoices->clear(); 418 | 419 | QStandardItem* item = new QStandardItem(tr("Auto")); 420 | item->setData(-1, Qt::UserRole); 421 | m_pVoices->appendRow(item); 422 | 423 | foreach(const QString& Lang, LangMap.keys()) 424 | { 425 | m_pVoices->addParentItem(Lang); 426 | foreach(int i, LangMap[Lang]) 427 | { 428 | SVoice* pVoice = m_Voices[i]; 429 | 430 | QString name = QString::fromStdWString(m_Voices[i]->Name); 431 | if (state == Qt::PartiallyChecked) 432 | m_pVoices->addChildItem(name, m_SelectedVoices.contains(name) ? Qt::Checked : Qt::Unchecked, i); 433 | else 434 | m_pVoices->addChildItem(name, i); 435 | } 436 | } 437 | 438 | /*switch(state) 439 | { 440 | case Qt::Unchecked: 441 | for(int i=0; i < m_Voices.size(); i++){ 442 | QStandardItem* item = new QStandardItem(QString::fromStdWString(m_Voices[i]->Name)); 443 | item->setData(i, Qt::UserRole); 444 | m_pVoices->setItem(m_pVoices->rowCount(), 0, item); 445 | } 446 | break; 447 | case Qt::PartiallyChecked: 448 | for (int i = 0; i < m_Voices.size(); i++) { 449 | QString name = QString::fromStdWString(m_Voices[i]->Name); 450 | QStandardItem* item = new QStandardItem(name); 451 | item->setData(i, Qt::UserRole); 452 | item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); 453 | item->setData(m_SelectedVoices.contains(name) ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); 454 | m_pVoices->setItem(m_pVoices->rowCount(), 0, item); 455 | } 456 | break; 457 | case Qt::Checked: 458 | for (int i = 0; i < m_Voices.size(); i++) { 459 | QString name = QString::fromStdWString(m_Voices[i]->Name); 460 | if (m_SelectedVoices.contains(name)) 461 | { 462 | QStandardItem* item = new QStandardItem(name); 463 | item->setData(i, Qt::UserRole); 464 | m_pVoices->setItem(m_pVoices->rowCount(), 0, item); 465 | } 466 | } 467 | break; 468 | }*/ 469 | 470 | m_bHold = false; 471 | } 472 | 473 | void CUltraTTS::on_filter_change(QStandardItem* item) 474 | { 475 | if (m_bHold) 476 | return; 477 | 478 | int index = item->data(Qt::UserRole).toInt(); 479 | int state = item->data(Qt::CheckStateRole).toInt(); 480 | 481 | SVoice* voice = m_Voices[index]; 482 | 483 | QString name = QString::fromStdWString(voice->Name); 484 | if(state == Qt::Unchecked) 485 | m_SelectedVoices.removeAll(name); 486 | else if (!m_SelectedVoices.contains(name)) 487 | m_SelectedVoices.append(name); 488 | 489 | m_pCfg->setValue("TTS_Selection", m_SelectedVoices); 490 | } 491 | 492 | void CUltraTTS::OnStop() 493 | { 494 | if (m_SectionIndex != -1) { 495 | if (SpeakNext()) 496 | return; 497 | } 498 | 499 | m_Sections.clear(); 500 | 501 | m_pProgress->setText("100%"); 502 | m_pTrayIcon->setToolTip(this->windowTitle()); 503 | 504 | if (m_pReadEdit != NULL) 505 | { 506 | /*QTextCursor tmpCursor = m_pReadEdit->textCursor(); 507 | tmpCursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor); 508 | m_pReadEdit->setTextCursor(tmpCursor);*/ 509 | m_pReadEdit->setReadOnly(false); 510 | m_pReadEdit = NULL; 511 | } 512 | 513 | ui.actionReadAll->setEnabled(true); 514 | ui.actionRead->setEnabled(true); 515 | ui.actionPause->setEnabled(false); 516 | ui.actionStop->setEnabled(false); 517 | 518 | if (m_bGrabAndRead) 519 | { 520 | m_bGrabAndRead = false; 521 | GrabAndRead(true); 522 | } 523 | } 524 | 525 | void CUltraTTS::OnProgress(int pos, int len, int total) 526 | { 527 | QString temp = QString::number(m_TotalLength ? 100 * (m_PassedLength + pos) / m_TotalLength : 0) + "%"; 528 | m_pProgress->setText(temp); 529 | m_pTrayIcon->setToolTip(this->windowTitle() + " " + temp); 530 | 531 | if (m_pReadEdit == edit()) 532 | { 533 | m_pReadEdit->setFocus(); 534 | 535 | pos = m_PassedLength + pos + m_SelectionOffset; 536 | QTextCursor tmpCursor = edit()->textCursor(); 537 | //tmpCursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, pos); 538 | tmpCursor.setPosition(pos); 539 | if (len == 0) // sapi 4 540 | { 541 | QString text = edit()->toPlainText().mid(pos); 542 | int tmp = text.indexOf(QRegExp("[\\s.,:;-_+*#/?\"'§$%&{}()\\[\\]=]")); 543 | if(tmp != -1) 544 | len = tmp; 545 | } 546 | tmpCursor.setPosition(pos + len, QTextCursor::KeepAnchor); 547 | m_pReadEdit->setTextCursor(tmpCursor); 548 | } 549 | } 550 | 551 | void CUltraTTS::on_actionNew_triggered() 552 | { 553 | STab* pTab = new STab(); 554 | pTab->pEdit = new QTextEdit(); 555 | connect(pTab->pEdit, SIGNAL(textChanged()), SLOT(on_text_changed())); 556 | 557 | m_Tabs.append(pTab); 558 | m_pTabs->addTab(pTab->pEdit, pTab->name()); 559 | if (m_pTab == NULL) 560 | m_pTab = pTab; // thats teh first tab 561 | else 562 | m_pTabs->setCurrentIndex(m_pTabs->count() - 1); 563 | } 564 | 565 | void CUltraTTS::on_text_changed() 566 | { 567 | if (m_bHold) 568 | return; 569 | 570 | if (m_pTab->bChanged == false) { 571 | m_pTab->bChanged = true; 572 | m_pTabs->setTabText(m_pTabs->currentIndex(), m_pTab->name() + " *"); 573 | } 574 | } 575 | 576 | void CUltraTTS::on_actionOpen_triggered() 577 | { 578 | QString fileName = QFileDialog::getOpenFileName(this, "Open the file"); 579 | QFile file(fileName); 580 | if (!file.open(QIODevice::ReadOnly | QFile::Text)) { 581 | QMessageBox::warning(this, "Warning", "Cannot open file: " + file.errorString()); 582 | return; 583 | } 584 | m_pTab->setFileName(fileName); 585 | m_pTabs->setTabText(m_pTabs->currentIndex(), m_pTab->name()); 586 | //setWindowTitle(fileName); 587 | QTextStream in(&file); 588 | QString text = in.readAll(); 589 | m_bHold = true; 590 | edit()->setText(text); 591 | m_bHold = false; 592 | file.close(); 593 | m_pTab->bChanged = false; 594 | } 595 | 596 | void CUltraTTS::on_actionSave_triggered() 597 | { 598 | QString fileName; 599 | // If we don't have a filename from before, get one. 600 | if (m_pTab->fileName.isEmpty()) { 601 | fileName = QFileDialog::getSaveFileName(this, "Save"); 602 | m_pTab->setFileName(fileName); 603 | } 604 | else 605 | fileName = m_pTab->fileName; 606 | QFile file(fileName); 607 | if (!file.open(QIODevice::WriteOnly | QFile::Text)) { 608 | QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); 609 | return; 610 | } 611 | m_pTabs->setTabText(m_pTabs->currentIndex(), m_pTab->name()); 612 | //setWindowTitle(fileName); 613 | QTextStream out(&file); 614 | QString text = edit()->toPlainText(); 615 | out << text; 616 | file.close(); 617 | m_pTab->bChanged = false; 618 | } 619 | 620 | void CUltraTTS::on_actionSave_as_triggered() 621 | { 622 | QString fileName = QFileDialog::getSaveFileName(this, "Save as"); 623 | QFile file(fileName); 624 | 625 | if (!file.open(QFile::WriteOnly | QFile::Text)) { 626 | QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); 627 | return; 628 | } 629 | m_pTab->setFileName(fileName); 630 | m_pTabs->setTabText(m_pTabs->currentIndex(), m_pTab->name()); 631 | //setWindowTitle(fileName); 632 | QTextStream out(&file); 633 | QString text = edit()->toPlainText(); 634 | out << text; 635 | file.close(); 636 | m_pTab->bChanged = false; 637 | } 638 | 639 | void CUltraTTS::on_actionPrint_triggered() 640 | { 641 | #if QT_CONFIG(printer) 642 | QPrinter printDev; 643 | #if QT_CONFIG(printdialog) 644 | QPrintDialog dialog(&printDev, this); 645 | if (dialog.exec() == QDialog::Rejected) 646 | return; 647 | #endif // QT_CONFIG(printdialog) 648 | edit()->print(&printDev); 649 | #endif // QT_CONFIG(printer) 650 | } 651 | 652 | void CUltraTTS::on_actionExit_triggered() 653 | { 654 | QCoreApplication::quit(); 655 | } 656 | 657 | void CUltraTTS::on_actionCopy_triggered() 658 | { 659 | edit()->copy(); 660 | } 661 | 662 | void CUltraTTS::on_actionCut_triggered() 663 | { 664 | edit()->cut(); 665 | } 666 | 667 | void CUltraTTS::on_actionPaste_triggered() 668 | { 669 | edit()->paste(); 670 | } 671 | 672 | void CUltraTTS::on_actionUndo_triggered() 673 | { 674 | edit()->undo(); 675 | } 676 | 677 | void CUltraTTS::on_actionRedo_triggered() 678 | { 679 | edit()->redo(); 680 | } 681 | 682 | void CUltraTTS::on_actionFont_triggered() 683 | { 684 | bool fontSelected; 685 | QFont font = QFontDialog::getFont(&fontSelected, this); 686 | if (fontSelected) 687 | edit()->setFont(font); 688 | } 689 | 690 | void CUltraTTS::on_actionUnderline_triggered() 691 | { 692 | edit()->setFontUnderline(ui.actionUnderline->isChecked()); 693 | } 694 | 695 | void CUltraTTS::on_actionItalic_triggered() 696 | { 697 | edit()->setFontItalic(ui.actionItalic->isChecked()); 698 | } 699 | 700 | void CUltraTTS::on_actionBold_triggered() 701 | { 702 | ui.actionBold->isChecked() ? edit()->setFontWeight(QFont::Bold) : edit()->setFontWeight(QFont::Normal); 703 | } 704 | 705 | void CUltraTTS::on_actionAbout_triggered() 706 | { 707 | QMessageBox::about(this, tr("About UltraTTS"), tr("UltraTTS Copyright (c) 2019")); 708 | } 709 | 710 | void CUltraTTS::on_actionReadAll_triggered() 711 | { 712 | QString text = edit()->toPlainText(); 713 | m_SelectionOffset = 0; 714 | m_pReadEdit = edit(); 715 | m_pReadEdit->setReadOnly(true); 716 | Speak(text, false); 717 | } 718 | 719 | void CUltraTTS::on_actionRead_triggered() 720 | { 721 | QTextCursor cursor = edit()->textCursor(); 722 | int start = cursor.selectionStart(); 723 | int end = cursor.selectionEnd(); 724 | 725 | QString text = edit()->toPlainText(); 726 | m_SelectionOffset = start; 727 | if (end > start) 728 | text = text.mid(start, end - start); 729 | else 730 | text = text.mid(start); 731 | m_pReadEdit = edit(); 732 | m_pReadEdit->setReadOnly(true); 733 | Speak(text, false); 734 | } 735 | 736 | void CUltraTTS::on_actionPause_triggered() 737 | { 738 | m_pTTS->Pause(); 739 | ui.actionPause->setChecked(m_pTTS->IsPaused()); 740 | } 741 | 742 | void CUltraTTS::on_actionStop_triggered() 743 | { 744 | Stop(); 745 | } 746 | 747 | void CUltraTTS::on_actionRead_Clipboard_triggered() 748 | { 749 | GrabAndRead(false); 750 | } 751 | 752 | void CUltraTTS::GrabCB(ECbAction CbAction) 753 | { 754 | m_CbTimeOut = QDateTime::currentDateTime().toTime_t() + 3; 755 | 756 | m_old_text = QApplication::clipboard()->text(); 757 | QApplication::clipboard()->clear(); 758 | 759 | m_CbAction = CbAction; 760 | 761 | //QTimer::singleShot(500, this, SLOT(on_send_ctrl())); 762 | } 763 | 764 | void CUltraTTS::on_send_ctrl() 765 | { 766 | //SendCtrlC(); 767 | } 768 | 769 | void CUltraTTS::on_clipboard() 770 | { 771 | if (m_CbAction == eNone) 772 | return; 773 | 774 | QString text = QApplication::clipboard()->text(); 775 | if (text.isEmpty()) 776 | return; 777 | 778 | m_CbTimeOut = 0; 779 | 780 | if(m_pCfg->value("PlaySound", true).toBool()) 781 | QApplication::beep(); 782 | 783 | switch (m_CbAction) 784 | { 785 | case eReadNow: 786 | case eRead: 787 | ReadCB(text, m_CbAction == eReadNow); 788 | break; 789 | case eInsert: 790 | InsertCB(text); 791 | break; 792 | } 793 | m_CbAction = eNone; 794 | 795 | QApplication::clipboard()->setText(m_old_text); 796 | } 797 | 798 | void CUltraTTS::GrabAndInsert() 799 | { 800 | GrabCB(eInsert); 801 | } 802 | 803 | QString CUltraTTS::InsertCB(QString& text, bool bClear) 804 | { 805 | m_bHold = true; 806 | //edit()->setText(text); 807 | 808 | QTextDocument *doc = edit()->document(); 809 | QTextCursor curs(doc); 810 | if (bClear) 811 | curs.select(QTextCursor::Document); 812 | else 813 | { 814 | text = "\n\n" + text; 815 | curs.movePosition(QTextCursor::End); 816 | } 817 | //curs.removeSelectedText(); 818 | curs.insertText(text); 819 | 820 | m_bHold = false; 821 | m_pTab->bChanged = false; 822 | 823 | return text; 824 | } 825 | 826 | void CUltraTTS::ReadCB(QString& text, bool bNow) 827 | { 828 | // Get CB reader tab 829 | if (!m_pTab->bReader) { 830 | int FoundIndex = -1; 831 | for(int i = 0; i < m_Tabs.size(); i++) 832 | { 833 | if (m_Tabs[i]->bReader) 834 | { 835 | FoundIndex = i; 836 | break; 837 | } 838 | } 839 | 840 | if (FoundIndex != -1) 841 | m_pTabs->setCurrentIndex(FoundIndex); 842 | else 843 | { 844 | if (!m_pTab->fileName.isEmpty() || !m_pTab->pEdit->toPlainText().isEmpty()) 845 | on_actionNew_triggered(); 846 | 847 | m_pTab->bReader = true; 848 | m_pTabs->setTabText(m_pTabs->currentIndex(), m_pTab->name()); 849 | } 850 | } 851 | // 852 | 853 | if (m_Sections.isEmpty()) 854 | bNow = true; 855 | 856 | InsertCB(text, bNow); 857 | 858 | m_SelectionOffset = 0; 859 | m_pReadEdit = edit(); 860 | m_pReadEdit->setReadOnly(true); 861 | Speak(text, !bNow); 862 | } 863 | 864 | void CUltraTTS::Speak(const QString& String, bool bAdd) 865 | { 866 | ui.actionReadAll->setEnabled(false); 867 | ui.actionRead->setEnabled(false); 868 | ui.actionPause->setEnabled(true); 869 | ui.actionStop->setEnabled(true); 870 | 871 | if (!bAdd) 872 | m_Sections.clear(); 873 | 874 | STextSection Section; 875 | Section.Delay = bAdd ? m_pCfg->value("SectionDelay", 750).toInt() : 0; 876 | 877 | if (!m_bAuto) 878 | { 879 | Section.Text = String; 880 | Section.Lang = "Unknown"; 881 | m_Sections.append(Section); 882 | } 883 | else 884 | { 885 | QStringList StringList; 886 | for (int Pos = 0;;) 887 | { 888 | int Sep = String.indexOf(QRegExp("[.!?\\r\\n]{1}"), Pos); 889 | if (Sep != -1) 890 | { 891 | Sep++; 892 | StringList.append(String.mid(Pos, Sep - Pos)); 893 | Pos = Sep; 894 | } 895 | else 896 | { 897 | StringList.append(String.mid(Pos)); 898 | break; 899 | } 900 | } 901 | 902 | Section.Text = ""; 903 | Section.Lang = "Unknown"; 904 | m_Sections.append(Section); 905 | 906 | int LangHint = 0; 907 | 908 | foreach(QString Text, StringList) 909 | { 910 | QPair Lang = DetectLanguage(Text, &LangHint); 911 | if (Lang.first != "Unknown" && Lang.first != m_Sections.last().Lang) 912 | { 913 | if (m_Sections.last().Lang == "Unknown") 914 | m_Sections.last().Lang = Lang.first; 915 | else if (Text.length() > 50) { 916 | Section.Text = ""; 917 | Section.Lang = Lang.first; 918 | Section.Delay = 0; 919 | m_Sections.append(Section); 920 | } 921 | } 922 | m_Sections.last().Text += Text; 923 | } 924 | } 925 | 926 | if (bAdd) 927 | { 928 | m_TotalLength += String.length(); 929 | } 930 | else 931 | { 932 | m_SectionIndex = -1; 933 | 934 | m_TotalLength = String.length(); 935 | m_PassedLength = 0; 936 | 937 | SpeakNext(); 938 | } 939 | } 940 | 941 | bool CUltraTTS::SpeakNext() 942 | { 943 | if(m_SectionIndex >= 0 && m_SectionIndex < m_Sections.length()) 944 | m_PassedLength += m_Sections[m_SectionIndex].Text.length(); 945 | 946 | if (++m_SectionIndex >= m_Sections.size()) 947 | return false; 948 | 949 | QTimer::singleShot(m_Sections[m_SectionIndex].Delay, this, SLOT(on_speak_next())); 950 | 951 | return true; 952 | } 953 | 954 | void CUltraTTS::on_speak_next() 955 | { 956 | if (m_Sections.isEmpty()) 957 | return; 958 | 959 | QString Speaker = m_pCfg->value(m_Sections[m_SectionIndex].Lang + "_Speaker", "").toString(); 960 | if (!Speaker.isEmpty()) 961 | SelectSpeaker(Speaker); 962 | 963 | m_pTTS->Speak(m_Sections[m_SectionIndex].Text.toStdWString()); 964 | } 965 | 966 | void CUltraTTS::PlayNext() 967 | { 968 | m_pTTS->Stop(); 969 | } 970 | 971 | void CUltraTTS::PlayPrev() 972 | { 973 | if (m_SectionIndex > 0) 974 | m_SectionIndex--; 975 | m_pTTS->Stop(); 976 | } 977 | 978 | void CUltraTTS::Stop() 979 | { 980 | m_SectionIndex = -1; 981 | m_pTTS->Stop(); 982 | } 983 | 984 | void CUltraTTS::GrabAndRead(bool bNow) 985 | { 986 | if (bNow && m_pTTS->IsSpeaking()) 987 | { 988 | m_bGrabAndRead = true; 989 | Stop(); 990 | return; 991 | } 992 | 993 | GrabCB(bNow ? eReadNow : eRead); 994 | } 995 | 996 | void CUltraTTS::on_actionConfiguration_triggered() 997 | { 998 | COptionsDlg dlg(m_pCfg); 999 | if (dlg.exec() == QDialog::Accepted) { 1000 | SetupHKs(); 1001 | 1002 | if (m_pCfg->value("SysTray", true).toBool()) { 1003 | if (!m_pTrayIcon->isVisible()) 1004 | m_pTrayIcon->show(); 1005 | } 1006 | else { 1007 | if (m_pTrayIcon->isVisible()) 1008 | m_pTrayIcon->hide(); 1009 | } 1010 | } 1011 | } 1012 | 1013 | void CUltraTTS::Process() 1014 | { 1015 | if (m_CbAction != eNone) 1016 | { 1017 | if (m_CbTimeOut >= QDateTime::currentDateTime().toTime_t()) 1018 | { 1019 | SendCtrlC(); 1020 | 1021 | on_clipboard(); 1022 | } 1023 | else 1024 | { 1025 | m_CbTimeOut = 0; 1026 | 1027 | QApplication::clipboard()->setText(m_old_text); 1028 | } 1029 | } 1030 | } -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ui_UltraTTS.h" 5 | 6 | class QItemDelegateEx : public QItemDelegate 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | QItemDelegateEx(QObject *parent = nullptr) : QItemDelegate(parent) 12 | { 13 | } 14 | 15 | QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const 16 | { 17 | QString type = index.data(Qt::AccessibleDescriptionRole).toString(); 18 | if (type == QLatin1String("separator")) 19 | return QSize(5, 5); 20 | return QItemDelegate::sizeHint(option, index); 21 | } 22 | 23 | void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const 24 | { 25 | QString type = index.data(Qt::AccessibleDescriptionRole).toString(); 26 | if (type == QLatin1String("separator")) { 27 | QItemDelegate::paint(painter, option, index); 28 | int y = (option.rect.top() + option.rect.bottom()) / 2; 29 | painter->setPen(option.palette.color(QPalette::Active, QPalette::Dark)); 30 | painter->drawLine(option.rect.left(), y, option.rect.right(), y); 31 | } 32 | else if (type == QLatin1String("parent")) { 33 | QStyleOptionViewItem parentOption = option; 34 | parentOption.state |= QStyle::State_Enabled; 35 | QItemDelegate::paint(painter, parentOption, index); 36 | } 37 | else if (type == QLatin1String("child")) { 38 | QStyleOptionViewItem childOption = option; 39 | int indent = 0; 40 | if((index.flags() & Qt::ItemIsUserCheckable) == 0) 41 | indent = option.fontMetrics.width(QString(4, QChar(' '))); 42 | childOption.rect.adjust(indent, 0, 0, 0); 43 | childOption.textElideMode = Qt::ElideNone; 44 | QItemDelegate::paint(painter, childOption, index); 45 | } 46 | else { 47 | QItemDelegate::paint(painter, option, index); 48 | } 49 | } 50 | }; 51 | 52 | class QStandardItemModelEx: public QStandardItemModel 53 | { 54 | Q_OBJECT 55 | public: 56 | 57 | void addParentItem(const QString& text, const QVariant& data = QVariant()) 58 | { 59 | QStandardItem* item = new QStandardItem(text); 60 | item->setData(data, Qt::UserRole); 61 | item->setFlags(item->flags() & ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable)); 62 | item->setData("parent", Qt::AccessibleDescriptionRole); 63 | 64 | QFont font = item->font(); 65 | font.setBold(true); 66 | item->setFont(font); 67 | 68 | //QStandardItemModel* itemModel = (QStandardItemModel*)model(); 69 | this->appendRow(item); 70 | } 71 | 72 | void addChildItem(const QString& text, const QVariant& data = QVariant()) 73 | { 74 | QStandardItem* item = new QStandardItem(text + QString(4, QChar(' '))); 75 | item->setData(data, Qt::UserRole); 76 | item->setData("child", Qt::AccessibleDescriptionRole); 77 | 78 | //QStandardItemModel* itemModel = (QStandardItemModel*)model(); 79 | this->appendRow(item); 80 | } 81 | 82 | void addChildItem(const QString& text, Qt::CheckState state, const QVariant& data = QVariant()) 83 | { 84 | QStandardItem* item = new QStandardItem(text + QString(4, QChar(' '))); 85 | item->setData(data, Qt::UserRole); 86 | item->setData("child", Qt::AccessibleDescriptionRole); 87 | 88 | item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled); 89 | item->setData(state, Qt::CheckStateRole); 90 | 91 | //QStandardItemModel* itemModel = (QStandardItemModel*)model(); 92 | this->appendRow(item); 93 | } 94 | }; 95 | 96 | class CUltraTTS : public QMainWindow 97 | { 98 | Q_OBJECT 99 | 100 | public: 101 | CUltraTTS(QWidget *parent = Q_NULLPTR); 102 | ~CUltraTTS(); 103 | 104 | void GrabAndRead(bool bNow); 105 | void GrabAndInsert(); 106 | 107 | void OnStop(); 108 | void OnProgress(int pos, int len, int total); 109 | 110 | private slots: 111 | void on_actionNew_triggered(); 112 | void on_actionOpen_triggered(); 113 | void on_actionSave_triggered(); 114 | void on_actionSave_as_triggered(); 115 | void on_actionPrint_triggered(); 116 | void on_actionExit_triggered(); 117 | void on_actionCopy_triggered(); 118 | void on_actionCut_triggered(); 119 | void on_actionPaste_triggered(); 120 | void on_actionUndo_triggered(); 121 | void on_actionRedo_triggered(); 122 | void on_actionFont_triggered(); 123 | void on_actionBold_triggered(); 124 | void on_actionUnderline_triggered(); 125 | void on_actionItalic_triggered(); 126 | void on_actionAbout_triggered(); 127 | void on_actionConfiguration_triggered(); 128 | 129 | void on_actionReadAll_triggered(); 130 | void on_actionRead_triggered(); 131 | void on_actionPause_triggered(); 132 | void on_actionStop_triggered(); 133 | void on_actionRead_Clipboard_triggered(); 134 | 135 | void on_voice_selected(int index); 136 | void on_rate(int index); 137 | void on_pitch(int index); 138 | void on_volume(int index); 139 | 140 | void on_reload_sapi(); 141 | void on_filter(int state); 142 | void on_filter_change(QStandardItem *item); 143 | 144 | void on_close_tab(int); 145 | void on_tab(int); 146 | 147 | void on_text_changed(); 148 | 149 | void on_hot_key(size_t id); 150 | 151 | void on_clipboard(); 152 | 153 | void on_send_ctrl(); 154 | 155 | void on_speak_next(); 156 | 157 | void on_sys_tray(QSystemTrayIcon::ActivationReason Reason); 158 | 159 | private: 160 | QTextEdit* edit() { return m_pTab->pEdit; } 161 | 162 | Ui::UltraTTSClass ui; 163 | 164 | QStandardItemModelEx* m_pVoices; 165 | 166 | QTabWidget* m_pTabs; 167 | 168 | QLabel* m_pProgress; 169 | 170 | struct STab 171 | { 172 | STab():bReader(false), bChanged(false) {} 173 | QTextEdit* pEdit; 174 | QString fileName; 175 | bool bReader; 176 | bool bChanged; 177 | QString name(); 178 | void setFileName(const QString& fileName) { 179 | this->fileName = fileName; 180 | bReader = false; 181 | } 182 | }; 183 | 184 | QList m_Tabs; 185 | STab* m_pTab; 186 | 187 | QTextEdit* m_pReadEdit; 188 | 189 | class UGlobalHotkeys* m_pHotkeyManager; 190 | 191 | QSystemTrayIcon* m_pTrayIcon; 192 | QMenu* m_pTrayMenu; 193 | 194 | protected: 195 | void Process(); 196 | 197 | void timerEvent(QTimerEvent* pEvent) 198 | { 199 | if (pEvent->timerId() == m_uTimerID) 200 | Process(); 201 | } 202 | 203 | int m_uTimerID; 204 | 205 | void changeEvent(QEvent *event); 206 | 207 | void SetupHKs(); 208 | void SetupHK(const QString& name, size_t id, const QString& seq = ""); 209 | void ReloadVoices(); 210 | void ReadCB(QString& text, bool bNow); 211 | void Speak(const QString& Text, bool bAdd); 212 | bool SpeakNext(); 213 | bool SelectSpeaker(const QString& Speaker); 214 | void Stop(); 215 | void PlayNext(); 216 | void PlayPrev(); 217 | QString InsertCB(QString& text, bool bClear = false); 218 | 219 | class CTTS* m_pTTS; 220 | 221 | std::vector m_Voices; 222 | QStringList m_SelectedVoices; 223 | 224 | QSettings* m_pCfg; 225 | 226 | bool m_bHold; 227 | 228 | bool m_bAuto; 229 | struct STextSection 230 | { 231 | QString Text; 232 | QString Lang; 233 | int Delay; 234 | }; 235 | QList m_Sections; 236 | int m_SectionIndex; 237 | int m_TotalLength; 238 | int m_PassedLength; 239 | int m_SelectionOffset; 240 | 241 | bool m_bGrabAndRead; 242 | 243 | enum ECbAction 244 | { 245 | eNone = 0, 246 | eReadNow, 247 | eRead, 248 | eInsert 249 | }; 250 | 251 | ECbAction m_CbAction; 252 | 253 | time_t m_CbTimeOut; 254 | 255 | QString m_old_text; 256 | 257 | void GrabCB(ECbAction CbAction); 258 | }; 259 | -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/UltraTTS.ico -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | images/info.png 4 | images/new.png 5 | images/open.png 6 | images/paste.png 7 | images/pencil.png 8 | images/print.png 9 | images/save.png 10 | images/save_as.png 11 | images/exit.png 12 | images/font.png 13 | images/copy.png 14 | images/create.png 15 | images/cut.png 16 | images/edit_redo.png 17 | images/edit_undo.png 18 | images/bold.png 19 | images/italic.png 20 | images/underline.png 21 | images/player_pause.png 22 | images/player_play.png 23 | images/player_stop.png 24 | images/read_cb.png 25 | images/rotateleft.png 26 | images/player_play2.png 27 | 28 | 29 | -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "UltraTTS.ico" 2 | 3 | -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | UltraTTSClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 700 10 | 400 11 | 12 | 13 | 14 | Ultra TTS 15 | 16 | 17 | 18 | 19 | 3 20 | 21 | 22 | 3 23 | 24 | 25 | 3 26 | 27 | 28 | 3 29 | 30 | 31 | 32 | 33 | 3 34 | 35 | 36 | 3 37 | 38 | 39 | 3 40 | 41 | 42 | 3 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 75 51 | 16777215 52 | 53 | 54 | 55 | TTS Engine: 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 22 67 | 22 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | :/images/rotateleft.png:/images/rotateleft.png 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 75 84 | 16777215 85 | 86 | 87 | 88 | Filter 89 | 90 | 91 | true 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 0 104 | 100 105 | 106 | 107 | 108 | TTS Properties 109 | 110 | 111 | 112 | 113 | 140 114 | 20 115 | 221 116 | 21 117 | 118 | 119 | 120 | Qt::Horizontal 121 | 122 | 123 | QSlider::TicksBelow 124 | 125 | 126 | 127 | 128 | 129 | 140 130 | 60 131 | 221 132 | 21 133 | 134 | 135 | 136 | Qt::Horizontal 137 | 138 | 139 | QSlider::TicksBelow 140 | 141 | 142 | 143 | 144 | 145 | 390 146 | 30 147 | 31 148 | 61 149 | 150 | 151 | 152 | 100 153 | 154 | 155 | Qt::Vertical 156 | 157 | 158 | QSlider::TicksBothSides 159 | 160 | 161 | 20 162 | 163 | 164 | 165 | 166 | 167 | 380 168 | 10 169 | 41 170 | 16 171 | 172 | 173 | 174 | Volume: 175 | 176 | 177 | 178 | 179 | 180 | 80 181 | 20 182 | 41 183 | 16 184 | 185 | 186 | 187 | Rate: 188 | 189 | 190 | 191 | 192 | 193 | 80 194 | 60 195 | 41 196 | 16 197 | 198 | 199 | 200 | Pitch: 201 | 202 | 203 | 204 | 205 | 206 | 130 207 | 40 208 | 31 209 | 16 210 | 211 | 212 | 213 | -10 214 | 215 | 216 | Qt::AlignCenter 217 | 218 | 219 | 220 | 221 | 222 | 230 223 | 40 224 | 41 225 | 16 226 | 227 | 228 | 229 | 0 230 | 231 | 232 | Qt::AlignCenter 233 | 234 | 235 | 236 | 237 | 238 | 340 239 | 40 240 | 31 241 | 16 242 | 243 | 244 | 245 | 10 246 | 247 | 248 | Qt::AlignCenter 249 | 250 | 251 | 252 | 253 | 254 | 130 255 | 80 256 | 31 257 | 16 258 | 259 | 260 | 261 | -10 262 | 263 | 264 | Qt::AlignCenter 265 | 266 | 267 | 268 | 269 | 270 | 230 271 | 80 272 | 41 273 | 16 274 | 275 | 276 | 277 | 0 278 | 279 | 280 | Qt::AlignCenter 281 | 282 | 283 | 284 | 285 | 286 | 340 287 | 80 288 | 31 289 | 16 290 | 291 | 292 | 293 | 10 294 | 295 | 296 | Qt::AlignCenter 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | QFrame::Sunken 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 0 314 | 0 315 | 700 316 | 21 317 | 318 | 319 | 320 | 321 | File 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | Edit 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | Speech 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | Help 361 | 362 | 363 | 364 | 365 | 366 | Options 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | TopToolBarArea 381 | 382 | 383 | false 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | :/images/new.png:/images/new.png 408 | 409 | 410 | New 411 | 412 | 413 | New text document 414 | 415 | 416 | Ctrl+N 417 | 418 | 419 | 420 | 421 | 422 | :/images/open.png:/images/open.png 423 | 424 | 425 | Open 426 | 427 | 428 | Open file 429 | 430 | 431 | Ctrl+O 432 | 433 | 434 | 435 | 436 | 437 | :/images/save.png:/images/save.png 438 | 439 | 440 | Save 441 | 442 | 443 | Save file 444 | 445 | 446 | Ctrl+S 447 | 448 | 449 | 450 | 451 | 452 | :/images/save_as.png:/images/save_as.png 453 | 454 | 455 | Save as 456 | 457 | 458 | Save file as 459 | 460 | 461 | Alt+S 462 | 463 | 464 | 465 | 466 | 467 | :/images/print.png:/images/print.png 468 | 469 | 470 | Print 471 | 472 | 473 | Print file 474 | 475 | 476 | 477 | 478 | 479 | :/images/exit.png:/images/exit.png 480 | 481 | 482 | Exit 483 | 484 | 485 | Exit UltraTTS 486 | 487 | 488 | 489 | 490 | 491 | :/images/copy.png:/images/copy.png 492 | 493 | 494 | Copy 495 | 496 | 497 | Ctrl+C 498 | 499 | 500 | 501 | 502 | 503 | :/images/cut.png:/images/cut.png 504 | 505 | 506 | Cut 507 | 508 | 509 | Ctrl+X 510 | 511 | 512 | 513 | 514 | 515 | :/images/paste.png:/images/paste.png 516 | 517 | 518 | Paste 519 | 520 | 521 | Ctrl+V 522 | 523 | 524 | 525 | 526 | 527 | :/images/edit_undo.png:/images/edit_undo.png 528 | 529 | 530 | Undo 531 | 532 | 533 | Ctrl+Z 534 | 535 | 536 | 537 | 538 | 539 | :/images/edit_redo.png:/images/edit_redo.png 540 | 541 | 542 | Redo 543 | 544 | 545 | Ctrl+Y 546 | 547 | 548 | 549 | 550 | 551 | :/images/font.png:/images/font.png 552 | 553 | 554 | Font 555 | 556 | 557 | 558 | 559 | true 560 | 561 | 562 | 563 | :/images/italic.png:/images/italic.png 564 | 565 | 566 | Italic 567 | 568 | 569 | Italic font 570 | 571 | 572 | Ctrl+I 573 | 574 | 575 | 576 | 577 | true 578 | 579 | 580 | 581 | :/images/bold.png:/images/bold.png 582 | 583 | 584 | actionBold 585 | 586 | 587 | Bold 588 | 589 | 590 | Ctrl+B 591 | 592 | 593 | 594 | 595 | true 596 | 597 | 598 | 599 | :/images/underline.png:/images/underline.png 600 | 601 | 602 | Underline 603 | 604 | 605 | Underline 606 | 607 | 608 | Ctrl+U 609 | 610 | 611 | 612 | 613 | 614 | :/images/info.png:/images/info.png 615 | 616 | 617 | About 618 | 619 | 620 | 621 | 622 | 623 | :/images/player_play.png:/images/player_play.png 624 | 625 | 626 | Read 627 | 628 | 629 | 630 | 631 | 632 | :/images/player_pause.png:/images/player_pause.png 633 | 634 | 635 | Pause 636 | 637 | 638 | 639 | 640 | 641 | :/images/player_stop.png:/images/player_stop.png 642 | 643 | 644 | Stop 645 | 646 | 647 | 648 | 649 | 650 | :/images/read_cb.png:/images/read_cb.png 651 | 652 | 653 | Read Clipboard 654 | 655 | 656 | 657 | 658 | Configuration 659 | 660 | 661 | 662 | 663 | 664 | :/images/player_play2.png:/images/player_play2.png 665 | 666 | 667 | ReadAll 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | 14 | {B12702AD-ABFB-343A-A199-8E24837244A3} 15 | Qt4VSv1.0 16 | 7.0 17 | 18 | 19 | 20 | Application 21 | v140_xp 22 | 23 | 24 | false 25 | 26 | 27 | Application 28 | v140_xp 29 | 30 | 31 | 32 | $(MSBuildProjectDirectory)\QtMsBuild 33 | 34 | 35 | $(SolutionDir)$(Platform)\$(Configuration)\ 36 | 37 | 38 | $(SolutionDir)$(Platform)\$(Configuration)\ 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | true 58 | UNICODE;_UNICODE;WIN32;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;QT_PRINTSUPPORT_LIB;%(PreprocessorDefinitions) 59 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport;%(AdditionalIncludeDirectories) 60 | Disabled 61 | ProgramDatabase 62 | MultiThreadedDebugDLL 63 | true 64 | Use 65 | stdafx.h 66 | $(IntDir)$(TargetName).pch 67 | 68 | 69 | Windows 70 | $(OutDir)\$(ProjectName).exe 71 | $(QTDIR)\lib;%(AdditionalLibraryDirectories) 72 | true 73 | qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;ole32.lib;Qt5PrintSupportd.lib;..\win32\debug\UGlobalHotkey.lib;..\win32\debug\cld_d.lib;%(AdditionalDependencies) 74 | 75 | 76 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 77 | Moc'ing %(Identity)... 78 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport;%(AdditionalIncludeDirectories) 79 | UNICODE;_UNICODE;WIN32;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;QT_PRINTSUPPORT_LIB;%(PreprocessorDefinitions) 80 | stdafx.h;../../%(Filename)%(Extension) 81 | 82 | 83 | Uic'ing %(Identity)... 84 | .\GeneratedFiles\ui_%(Filename).h 85 | 86 | 87 | Rcc'ing %(Identity)... 88 | .\GeneratedFiles\qrc_%(Filename).cpp 89 | 90 | 91 | 92 | 93 | true 94 | UNICODE;_UNICODE;WIN32;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;QT_PRINTSUPPORT_LIB;%(PreprocessorDefinitions) 95 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport;%(AdditionalIncludeDirectories) 96 | 97 | MultiThreadedDLL 98 | true 99 | Use 100 | stdafx.h 101 | $(IntDir)$(TargetName).pch 102 | 103 | 104 | Windows 105 | $(OutDir)\$(ProjectName).exe 106 | $(QTDIR)\lib;%(AdditionalLibraryDirectories) 107 | false 108 | qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5PrintSupport.lib;..\win32\release\UGlobalHotkey.lib;..\win32\release\cld_d.lib;%(AdditionalDependencies) 109 | 110 | 111 | .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp 112 | Moc'ing %(Identity)... 113 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport;%(AdditionalIncludeDirectories) 114 | UNICODE;_UNICODE;WIN32;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;QT_PRINTSUPPORT_LIB;%(PreprocessorDefinitions) 115 | stdafx.h;../../%(Filename)%(Extension) 116 | 117 | 118 | Uic'ing %(Identity)... 119 | .\GeneratedFiles\ui_%(Filename).h 120 | 121 | 122 | Rcc'ing %(Identity)... 123 | .\GeneratedFiles\qrc_%(Filename).cpp 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | Create 134 | Create 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport 143 | .\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;$(QTDIR)\include\QtPrintSupport 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /UltraTTS/UltraTTS.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 14 | qrc;* 15 | false 16 | 17 | 18 | {99349809-55BA-4b9d-BF79-8FDBB0286EB3} 19 | ui 20 | 21 | 22 | {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E} 23 | qrc;* 24 | false 25 | 26 | 27 | {71ED8ED8-ACB9-4CE9-BBE1-E00B30144E11} 28 | moc;h;cpp 29 | False 30 | 31 | 32 | {1ac6f738-fe90-4b4c-9bac-f6856d2baec6} 33 | 34 | 35 | {c1816d43-8bbd-4c38-9144-6c4d0506c850} 36 | 37 | 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Sapi 50 | 51 | 52 | Sapi 53 | 54 | 55 | Sapi 56 | 57 | 58 | Utils 59 | 60 | 61 | Utils 62 | 63 | 64 | Source Files 65 | 66 | 67 | 68 | 69 | Header Files 70 | 71 | 72 | Sapi 73 | 74 | 75 | Sapi 76 | 77 | 78 | Sapi 79 | 80 | 81 | Utils 82 | 83 | 84 | Utils 85 | 86 | 87 | 88 | 89 | Header Files 90 | 91 | 92 | Header Files 93 | 94 | 95 | 96 | 97 | Form Files 98 | 99 | 100 | Form Files 101 | 102 | 103 | 104 | 105 | Resource Files 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /UltraTTS/Utils/Functions.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Functions.h" 3 | 4 | StrPair Split2(const QString& String, QString Separator, bool Back) 5 | { 6 | int Sep = Back ? String.lastIndexOf(Separator) : String.indexOf(Separator); 7 | if (Sep != -1) 8 | return qMakePair(String.left(Sep).trimmed(), String.mid(Sep + Separator.length()).trimmed()); 9 | return qMakePair(String.trimmed(), QString()); 10 | } 11 | 12 | QStringList SplitStr(const QString& String, QString Separator) 13 | { 14 | QStringList List = String.split(Separator); 15 | for (int i = 0; i < List.count(); i++) 16 | { 17 | List[i] = List[i].trimmed(); 18 | if (List[i].isEmpty()) 19 | List.removeAt(i--); 20 | } 21 | return List; 22 | } 23 | 24 | void SendCtrlC() 25 | { 26 | INPUT ip; 27 | ip.type = INPUT_KEYBOARD; 28 | ip.ki.wScan = 0; 29 | ip.ki.time = 0; 30 | ip.ki.dwExtraInfo = 0; 31 | 32 | // Press the "Ctrl" key 33 | ip.ki.wVk = VK_CONTROL; 34 | ip.ki.dwFlags = 0; // 0 for key press 35 | SendInput(1, &ip, sizeof(INPUT)); 36 | 37 | // Press the "V" key 38 | ip.ki.wVk = 'C'; 39 | ip.ki.dwFlags = 0; // 0 for key press 40 | SendInput(1, &ip, sizeof(INPUT)); 41 | 42 | // Release the "V" key 43 | ip.ki.wVk = 'C'; 44 | ip.ki.dwFlags = KEYEVENTF_KEYUP; 45 | SendInput(1, &ip, sizeof(INPUT)); 46 | 47 | // Release the "Ctrl" key 48 | ip.ki.wVk = VK_CONTROL; 49 | ip.ki.dwFlags = KEYEVENTF_KEYUP; 50 | SendInput(1, &ip, sizeof(INPUT)); 51 | } -------------------------------------------------------------------------------- /UltraTTS/Utils/Functions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef QPair StrPair; 4 | StrPair Split2(const QString& String, QString Separator = "=", bool Back = false); 5 | QStringList SplitStr(const QString& String, QString Separator); 6 | 7 | 8 | void SendCtrlC(); 9 | -------------------------------------------------------------------------------- /UltraTTS/Utils/LangDetect.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "LangDetect.h" 3 | 4 | 5 | #define CLD_WINDOWS 6 | 7 | #include "../cld/encodings/compact_lang_det/compact_lang_det.h" 8 | #include "../cld/encodings/compact_lang_det/ext_lang_enc.h" 9 | #include "../cld/encodings/compact_lang_det/unittest_data.h" 10 | #include "../cld/encodings/proto/encodings.pb.h" 11 | #include "../cld/languages/proto/languages.pb.h" 12 | 13 | QPair DetectLanguage(const QString& text, int* pLang) 14 | { 15 | bool is_plain_text = true; 16 | bool do_allow_extended_languages = true; 17 | bool do_pick_summary_language = false; 18 | bool do_remove_weak_matches = false; 19 | bool is_reliable; 20 | const char* tld_hint = NULL; 21 | int encoding_hint = UTF8; // UNKNOWN_ENCODING; 22 | Language language_hint = pLang ? (Language)*pLang : UNKNOWN_LANGUAGE; 23 | double normalized_score3[3]; 24 | Language language3[3]; 25 | int percent3[3]; 26 | int text_bytes; 27 | 28 | QByteArray str = text.toUtf8(); 29 | const char* src = str.data(); 30 | Language lang = CompactLangDet::DetectLanguage(0, src, strlen(src), is_plain_text, 31 | do_allow_extended_languages, do_pick_summary_language, do_remove_weak_matches, 32 | tld_hint, encoding_hint, language_hint, 33 | language3, percent3, normalized_score3, 34 | &text_bytes, &is_reliable); 35 | 36 | if (pLang) 37 | *pLang = lang; 38 | 39 | QString Lang = QString(LanguageName(lang)); 40 | 41 | return QPair(Lang.mid(0, 1) + Lang.mid(1).toLower(), percent3[0]); 42 | } -------------------------------------------------------------------------------- /UltraTTS/Utils/LangDetect.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | QPair DetectLanguage(const QString& text, int* pLang = 0); -------------------------------------------------------------------------------- /UltraTTS/images/accessories-calculator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/accessories-calculator.png -------------------------------------------------------------------------------- /UltraTTS/images/accessories-text-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/accessories-text-editor.png -------------------------------------------------------------------------------- /UltraTTS/images/artsfftscope.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/artsfftscope.png -------------------------------------------------------------------------------- /UltraTTS/images/block.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/block.png -------------------------------------------------------------------------------- /UltraTTS/images/bold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/bold.png -------------------------------------------------------------------------------- /UltraTTS/images/copy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/copy.png -------------------------------------------------------------------------------- /UltraTTS/images/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/create.png -------------------------------------------------------------------------------- /UltraTTS/images/cut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/cut.png -------------------------------------------------------------------------------- /UltraTTS/images/edit_redo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/edit_redo.png -------------------------------------------------------------------------------- /UltraTTS/images/edit_undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/edit_undo.png -------------------------------------------------------------------------------- /UltraTTS/images/exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/exit.png -------------------------------------------------------------------------------- /UltraTTS/images/font.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/font.png -------------------------------------------------------------------------------- /UltraTTS/images/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/info.png -------------------------------------------------------------------------------- /UltraTTS/images/italic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/italic.png -------------------------------------------------------------------------------- /UltraTTS/images/new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/new.png -------------------------------------------------------------------------------- /UltraTTS/images/ok.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/ok.png -------------------------------------------------------------------------------- /UltraTTS/images/open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/open.png -------------------------------------------------------------------------------- /UltraTTS/images/paste.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/paste.png -------------------------------------------------------------------------------- /UltraTTS/images/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/pencil.png -------------------------------------------------------------------------------- /UltraTTS/images/player_pause.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/player_pause.png -------------------------------------------------------------------------------- /UltraTTS/images/player_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/player_play.png -------------------------------------------------------------------------------- /UltraTTS/images/player_play2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/player_play2.png -------------------------------------------------------------------------------- /UltraTTS/images/player_stop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/player_stop.png -------------------------------------------------------------------------------- /UltraTTS/images/print.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/print.png -------------------------------------------------------------------------------- /UltraTTS/images/read_cb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/read_cb.png -------------------------------------------------------------------------------- /UltraTTS/images/rotateleft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/rotateleft.png -------------------------------------------------------------------------------- /UltraTTS/images/rotateright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/rotateright.png -------------------------------------------------------------------------------- /UltraTTS/images/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/save.png -------------------------------------------------------------------------------- /UltraTTS/images/save_as.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/save_as.png -------------------------------------------------------------------------------- /UltraTTS/images/underline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/underline.png -------------------------------------------------------------------------------- /UltraTTS/images/zoomin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/zoomin.png -------------------------------------------------------------------------------- /UltraTTS/images/zoomout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidXanatos/UltraTTS/63a840422d0b7c5b11401c3b0922f06bb3ace9a0/UltraTTS/images/zoomout.png -------------------------------------------------------------------------------- /UltraTTS/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "UltraTTS.h" 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | QApplication a(argc, argv); 8 | 9 | CUltraTTS w; 10 | w.show(); 11 | return a.exec(); 12 | } 13 | -------------------------------------------------------------------------------- /UltraTTS/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /UltraTTS/stdafx.h: -------------------------------------------------------------------------------- 1 | #include 2 | --------------------------------------------------------------------------------