1
by Gunnar Schmidt
Imported KMouth into kdeaccessibility |
1 |
/***************************************************************************
|
486.1.3
by Jeremy Whiting
Updated copyright headers and add missing ones. |
2 |
* Copyright (C) 2002 by Gunnar Schmi Dt <kmouth@schmi-dt.de *
|
3 |
* (C) 2015 by Jeremy Whiting <jpwhiting@kde.org> *
|
|
1
by Gunnar Schmidt
Imported KMouth into kdeaccessibility |
4 |
* *
|
5 |
* This program is free software; you can redistribute it and/or modify *
|
|
6 |
* it under the terms of the GNU General Public License as published by *
|
|
7 |
* the Free Software Foundation; either version 2 of the License, or *
|
|
8 |
* (at your option) any later version. *
|
|
9 |
* *
|
|
486.1.3
by Jeremy Whiting
Updated copyright headers and add missing ones. |
10 |
* This program is distributed in the hope that it will be useful, *
|
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
13 |
* GNU General Public License for more details. *
|
|
14 |
* *
|
|
15 |
* You should have received a copy of the GNU General Public License *
|
|
16 |
* along with this program; if not, write to the *
|
|
17 |
* Free Software Foundation, Inc., *
|
|
18 |
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
|
1
by Gunnar Schmidt
Imported KMouth into kdeaccessibility |
19 |
***************************************************************************/
|
20 |
||
21 |
#include "speech.h" |
|
327
by Laurent Montel
Remove not necessary include |
22 |
|
489
by Jeremy Whiting
Cleanup headers and bump version to 1.2.0 |
23 |
#include <QHash> |
24 |
#include <QRegExp> |
|
25 |
#include <QStack> |
|
26 |
#include <QTextCodec> |
|
27 |
#include <QTextStream> |
|
361
by Arto Hytönen
QtModule/QClass fixes |
28 |
|
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
29 |
#define macroExpander
|
30 |
#include <kmacroexpander.h> |
|
31 |
||
32 |
Speech::Speech() |
|
33 |
{
|
|
34 |
}
|
|
35 |
||
36 |
Speech::~Speech() |
|
37 |
{
|
|
38 |
}
|
|
39 |
||
40 |
QString Speech::prepareCommand(QString command, const QString &text, |
|
41 |
const QString &filename, const QString &language) |
|
42 |
{
|
|
98
by Gunnar Schmidt
Added the possibility to pass the text via a file to the speech synthesizer and modified the code to use the KMacroExpander |
43 |
#ifdef macroExpander
|
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
44 |
QHash<QChar, QString> map; |
45 |
map[QLatin1Char('t')] = text; |
|
46 |
map[QLatin1Char('f')] = filename; |
|
47 |
map[QLatin1Char('l')] = language; |
|
48 |
return KMacroExpander::expandMacrosShellQuote(command, map); |
|
98
by Gunnar Schmidt
Added the possibility to pass the text via a file to the speech synthesizer and modified the code to use the KMacroExpander |
49 |
#else
|
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
50 |
QStack<bool> stack; // saved isdoublequote values during parsing of braces |
51 |
bool issinglequote = false; // inside '...' ? |
|
52 |
bool isdoublequote = false; // inside "..." ? |
|
53 |
int noreplace = 0; // nested braces when within ${...} |
|
54 |
QString escText = K3ShellProcess::quote(text); |
|
55 |
||
56 |
// character sequences that change the state or need to be otherwise processed
|
|
57 |
QRegExp re_singlequote("('|%%|%t|%f|%l)"); |
|
58 |
QRegExp re_doublequote("(\"|\\\\|`|\\$\\(|\\$\\{|%%|%t|%f|%l)"); |
|
59 |
QRegExp re_noquote("('|\"|\\\\|`|\\$\\(|\\$\\{|\\(|\\{|\\)|\\}|%%|%t|%f|%l)"); |
|
60 |
||
61 |
// parse the command:
|
|
62 |
for (int i = re_noquote.search(command); |
|
63 |
i != -1; |
|
64 |
i = (issinglequote ? re_singlequote.search(command, i) |
|
65 |
: isdoublequote ? re_doublequote.search(command, i) |
|
66 |
: re_noquote.search(command, i)) |
|
67 |
)
|
|
68 |
// while there are character sequences that need to be processed
|
|
69 |
{
|
|
70 |
if ((command[i] == '(') || (command[i] == '{')) { // (...) or {...} |
|
71 |
// assert(isdoublequote == false)
|
|
72 |
stack.push(isdoublequote); |
|
73 |
if (noreplace > 0) |
|
74 |
// count nested braces when within ${...}
|
|
75 |
noreplace++; |
|
76 |
i++; |
|
77 |
} else if (command[i] == '$') { // $(...) or ${...} |
|
78 |
stack.push(isdoublequote); |
|
79 |
isdoublequote = false; |
|
80 |
if ((noreplace > 0) || (command[i + 1] == '{')) |
|
81 |
// count nested braces when within ${...}
|
|
82 |
noreplace++; |
|
83 |
i += 2; |
|
84 |
} else if ((command[i] == ')') || (command[i] == '}')) { |
|
85 |
// $(...) or (...) or ${...} or {...}
|
|
86 |
if (!stack.isEmpty()) |
|
87 |
isdoublequote = stack.pop(); |
|
88 |
else
|
|
89 |
qWarning("Parse error."); |
|
90 |
if (noreplace > 0) |
|
91 |
// count nested braces when within ${...}
|
|
92 |
noreplace--; |
|
93 |
i++; |
|
94 |
} else if (command[i] == '\'') { |
|
95 |
issinglequote = !issinglequote; |
|
96 |
i++; |
|
97 |
} else if (command[i] == '"') { |
|
98 |
isdoublequote = !isdoublequote; |
|
99 |
i++; |
|
100 |
} else if (command[i] == '\\') |
|
101 |
i += 2; |
|
102 |
else if (command[i] == '`') { |
|
103 |
// Replace all `...` with safer $(...)
|
|
104 |
command.replace(i, 1, "$("); |
|
105 |
QRegExp re_backticks("(`|\\\\`|\\\\\\\\|\\\\\\$)"); |
|
106 |
for (int i2 = re_backticks.search(command, i + 2); |
|
107 |
i2 != -1; |
|
108 |
i2 = re_backticks.search(command, i2) |
|
109 |
) { |
|
110 |
if (command[i2] == '`') { |
|
111 |
command.replace(i2, 1, ")"); |
|
112 |
i2 = command.length(); // leave loop |
|
113 |
} else { |
|
114 |
// remove backslash and ignore following character
|
|
115 |
command.remove(i2, 1); |
|
116 |
i2++; |
|
117 |
}
|
|
118 |
}
|
|
119 |
// Leave i unchanged! We need to process "$("
|
|
120 |
} else if (noreplace > 0) { // do not replace macros within ${...} |
|
121 |
if (issinglequote) |
|
122 |
i += re_singlequote.matchedLength(); |
|
123 |
else if (isdoublequote) |
|
124 |
i += re_doublequote.matchedLength(); |
|
125 |
else
|
|
126 |
i += re_noquote.matchedLength(); |
|
127 |
} else { // replace macro |
|
128 |
QString match, v; |
|
129 |
||
130 |
// get match
|
|
131 |
if (issinglequote) |
|
132 |
match = re_singlequote.cap(); |
|
133 |
else if (isdoublequote) |
|
134 |
match = re_doublequote.cap(); |
|
135 |
else
|
|
136 |
match = re_noquote.cap(); |
|
137 |
||
138 |
// substitute %variables
|
|
139 |
if (match == "%t") |
|
140 |
v = escText; |
|
141 |
else if (match == "%f") |
|
142 |
v = filename; |
|
143 |
else if (match == "%%") |
|
144 |
v = "%"; |
|
145 |
else if (match == "%l") |
|
146 |
v = language; |
|
147 |
||
148 |
// %variable inside of a quote?
|
|
149 |
if (isdoublequote) |
|
150 |
v = '"' + v + '"'; |
|
151 |
else if (issinglequote) |
|
152 |
v = '\'' + v + '\''; |
|
153 |
||
154 |
command.replace(i, match.length(), v); |
|
155 |
i += v.length(); |
|
156 |
}
|
|
157 |
}
|
|
158 |
return command; |
|
98
by Gunnar Schmidt
Added the possibility to pass the text via a file to the speech synthesizer and modified the code to use the KMacroExpander |
159 |
#endif
|
1
by Gunnar Schmidt
Imported KMouth into kdeaccessibility |
160 |
}
|
161 |
||
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
162 |
void Speech::speak(QString command, bool stdIn, const QString &text, const QString &language, int encoding, QTextCodec *codec) |
163 |
{
|
|
164 |
if (text.length() > 0) { |
|
165 |
// 1. prepare the text:
|
|
166 |
// 1.a) encode the text
|
|
167 |
QTextStream ts(&encText, QIODevice::WriteOnly); |
|
168 |
if (encoding == Local) |
|
169 |
ts.setCodec(QTextCodec::codecForLocale()); |
|
170 |
else if (encoding == Latin1) |
|
171 |
ts.setCodec("ISO-8859-1"); |
|
172 |
else if (encoding == Unicode) |
|
173 |
ts.setCodec("UTF-16"); |
|
174 |
else
|
|
175 |
ts.setCodec(codec); |
|
176 |
ts << text; |
|
177 |
ts.flush(); |
|
178 |
||
179 |
// 1.b) create a temporary file for the text
|
|
180 |
tempFile.open(); |
|
181 |
QTextStream fs(&tempFile); |
|
182 |
if (encoding == Local) |
|
183 |
fs.setCodec(QTextCodec::codecForLocale()); |
|
184 |
else if (encoding == Latin1) |
|
185 |
fs.setCodec("ISO-8859-1"); |
|
186 |
else if (encoding == Unicode) |
|
187 |
fs.setCodec("UTF-16"); |
|
188 |
else
|
|
189 |
fs.setCodec(codec); |
|
190 |
fs << text; |
|
191 |
fs << endl; |
|
192 |
QString filename = tempFile.fileName(); |
|
193 |
tempFile.flush(); |
|
194 |
||
195 |
// 2. prepare the command:
|
|
196 |
command = prepareCommand(command, QLatin1String(encText), filename, language); |
|
197 |
||
198 |
// 3. create a new process
|
|
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
199 |
connect(&m_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processExited(int, QProcess::ExitStatus))); |
200 |
//connect(&process, SIGNAL(wroteStdin(K3Process*)), this, SLOT(wroteStdin(K3Process*)));
|
|
201 |
//connect(&process, SIGNAL(receivedStdout(K3Process*, char*, int)), this, SLOT(receivedStdout(K3Process*, char*, int)));
|
|
202 |
//connect(&process, SIGNAL(receivedStderr(K3Process*, char*, int)), this, SLOT(receivedStderr(K3Process*, char*, int)));
|
|
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
203 |
|
204 |
// 4. start the process
|
|
205 |
if (stdIn) { |
|
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
206 |
m_process.start(command); |
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
207 |
if (encText.size() > 0) |
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
208 |
m_process.write(encText, encText.size()); |
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
209 |
else
|
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
210 |
m_process.close(); |
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
211 |
} else |
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
212 |
m_process.start(command); |
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
213 |
}
|
214 |
}
|
|
215 |
||
487
by Jeremy Whiting
Initial port to kf5/qt5/QtSpeech. |
216 |
//void Speech::receivedStdout(K3Process *, char *buffer, int buflen)
|
217 |
//{
|
|
218 |
// kDebug() << QString::fromLatin1(buffer, buflen) + QLatin1Char('\n');
|
|
219 |
//}
|
|
220 |
//void Speech::receivedStderr(K3Process *, char *buffer, int buflen)
|
|
221 |
//{
|
|
222 |
// kDebug() << QString::fromLatin1(buffer, buflen) + QLatin1Char('\n');
|
|
223 |
//}
|
|
224 |
||
225 |
//void Speech::wroteStdin(K3Process *)
|
|
226 |
//{
|
|
227 |
// process.closeStdin();
|
|
228 |
//}
|
|
229 |
||
230 |
void Speech::processExited(int exitCode, QProcess::ExitStatus exitStatus) |
|
484.1.19
by Jeremy Whiting
Restyle with astyle as per kdelibs coding style. |
231 |
{
|
232 |
delete this; |
|
1
by Gunnar Schmidt
Imported KMouth into kdeaccessibility |
233 |
}
|
234 |
||
235 |
#include "speech.moc" |