19 |
#include "CCursor.h" |
#include "CCursor.h" |
20 |
|
|
21 |
#include "../common/global.h" |
#include "../common/global.h" |
22 |
|
#include "../common/global_private.h" |
23 |
#include "../common/Condition.h" |
#include "../common/Condition.h" |
24 |
|
|
25 |
#define LSCP_DEFAULT_HOST "localhost" |
#define LSCP_DEFAULT_HOST "localhost" |
28 |
using namespace std; |
using namespace std; |
29 |
using namespace LinuxSampler; |
using namespace LinuxSampler; |
30 |
|
|
31 |
static LSCPClient g_client; |
static LSCPClient* g_client = NULL; |
32 |
static KeyboardReader g_keyboardReader; |
static KeyboardReader* g_keyboardReader = NULL; |
33 |
static Condition g_todo; |
static Condition g_todo; |
34 |
static String g_goodPortion; |
static String g_goodPortion; |
35 |
static String g_badPortion; |
static String g_badPortion; |
36 |
static String g_suggestedPortion; |
static String g_suggestedPortion; |
37 |
|
static const String g_prompt = "lscp=# "; |
38 |
|
|
39 |
static void printUsage() { |
static void printUsage() { |
40 |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
49 |
cout << endl; |
cout << endl; |
50 |
} |
} |
51 |
|
|
52 |
|
static void printWelcome() { |
53 |
|
cout << "Welcome to lscp " << VERSION << ", the LinuxSampler Control Protocol (LSCP) shell." << endl; |
54 |
|
cout << endl; |
55 |
|
} |
56 |
|
|
57 |
|
static void printPrompt() { |
58 |
|
cout << g_prompt << flush; |
59 |
|
} |
60 |
|
|
61 |
|
static int promptOffset() { |
62 |
|
return g_prompt.size(); |
63 |
|
} |
64 |
|
|
65 |
// Called by the network reading thread, whenever new data arrived from the |
// Called by the network reading thread, whenever new data arrived from the |
66 |
// network connection. |
// network connection. |
67 |
static void onLSCPClientNewInputAvailable(LSCPClient* client) { |
static void onLSCPClientNewInputAvailable(LSCPClient* client) { |
81 |
// now add the suggested, correct characters |
// now add the suggested, correct characters |
82 |
s += g_suggestedPortion; |
s += g_suggestedPortion; |
83 |
g_suggestedPortion.clear(); |
g_suggestedPortion.clear(); |
84 |
g_client.send(s); |
g_client->send(s); |
85 |
} |
} |
86 |
|
|
87 |
int main(int argc, char *argv[]) { |
int main(int argc, char *argv[]) { |
118 |
|
|
119 |
// try to connect to the sampler's LSCP server and start a thread for |
// try to connect to the sampler's LSCP server and start a thread for |
120 |
// receiving incoming network data from the sampler's LSCP server |
// receiving incoming network data from the sampler's LSCP server |
121 |
g_client.setCallback(onLSCPClientNewInputAvailable); |
g_client = new LSCPClient; |
122 |
if (!g_client.connect(host, port)) return -1; |
g_client->setCallback(onLSCPClientNewInputAvailable); |
123 |
String sResponse = g_client.sendCommandSync( |
if (!g_client->connect(host, port)) return -1; |
124 |
|
String sResponse = g_client->sendCommandSync( |
125 |
(autoCorrect) ? "SET SHELL AUTO_CORRECT 1" : "SET SHELL AUTO_CORRECT 0" |
(autoCorrect) ? "SET SHELL AUTO_CORRECT 1" : "SET SHELL AUTO_CORRECT 0" |
126 |
); |
); |
127 |
sResponse = g_client.sendCommandSync("SET SHELL INTERACT 1"); |
sResponse = g_client->sendCommandSync("SET SHELL INTERACT 1"); |
128 |
if (sResponse.substr(0, 2) != "OK") { |
if (sResponse.substr(0, 2) != "OK") { |
129 |
cerr << "Error: sampler too old, it does not support shell instructions\n"; |
cerr << "Error: sampler too old, it does not support shell instructions\n"; |
130 |
return -1; |
return -1; |
131 |
} |
} |
132 |
|
|
133 |
|
printWelcome(); |
134 |
|
printPrompt(); |
135 |
|
|
136 |
// start a thread for reading from the local text input keyboard |
// start a thread for reading from the local text input keyboard |
137 |
// (keyboard echo will be disabled as well to have a clean control on what |
// (keyboard echo will be disabled as well to have a clean control on what |
138 |
// is appearing on the screen) |
// is appearing on the screen) |
139 |
g_keyboardReader.setCallback(onNewKeyboardInputAvailable); |
g_keyboardReader = new KeyboardReader; |
140 |
g_keyboardReader.startReading(); |
g_keyboardReader->setCallback(onNewKeyboardInputAvailable); |
141 |
|
g_keyboardReader->startReading(); |
142 |
|
|
143 |
// main thread's loop |
// main thread's loop |
144 |
while (true) { |
while (true) { |
149 |
g_todo.Unlock(); |
g_todo.Unlock(); |
150 |
|
|
151 |
// did network data arrive? |
// did network data arrive? |
152 |
while (g_client.messageComplete()) { |
while (g_client->messageComplete()) { |
153 |
String line = *g_client.popLine(); |
String line = *g_client->popLine(); |
154 |
//printf("line '%s'\n", line.c_str()); |
//printf("line '%s'\n", line.c_str()); |
155 |
if (line.substr(0,4) == "SHU:") { |
if (line.substr(0,4) == "SHU:") { |
156 |
int code = 0, n = 0; |
int code = 0, n = 0; |
198 |
//printf("line '%s' good='%s' bad='%s' suggested='%s' cursor=%d\n", line.c_str(), sGood.c_str(), sBad.c_str(), sSuggest.c_str(), cursorColumn); |
//printf("line '%s' good='%s' bad='%s' suggested='%s' cursor=%d\n", line.c_str(), sGood.c_str(), sBad.c_str(), sSuggest.c_str(), cursorColumn); |
199 |
|
|
200 |
CCursor cursor = CCursor::now().toColumn(0).clearLine(); |
CCursor cursor = CCursor::now().toColumn(0).clearLine(); |
201 |
|
printPrompt(); |
202 |
|
|
203 |
CFmt cfmt; |
CFmt cfmt; |
204 |
if (code == LSCP_SHU_COMPLETE) cfmt.bold().green(); |
if (code == LSCP_SHU_COMPLETE) cfmt.bold().green(); |
209 |
cfmt.bold().yellow(); |
cfmt.bold().yellow(); |
210 |
cout << sSuggest << flush; |
cout << sSuggest << flush; |
211 |
|
|
212 |
cursor.toColumn(cursorColumn); |
cursor.toColumn(cursorColumn + promptOffset()); |
213 |
} |
} |
214 |
} else if (line.substr(0,2) == "OK") { // single-line response expected ... |
} else if (line.substr(0,2) == "OK") { // single-line response expected ... |
215 |
cout << endl << flush; |
cout << endl << flush; |
218 |
cout << line.substr(0,2) << flush; |
cout << line.substr(0,2) << flush; |
219 |
cfmt.reset(); |
cfmt.reset(); |
220 |
cout << line.substr(2) << endl << flush; |
cout << line.substr(2) << endl << flush; |
221 |
|
printPrompt(); |
222 |
} else if (line.substr(0,3) == "WRN") { // single-line response expected ... |
} else if (line.substr(0,3) == "WRN") { // single-line response expected ... |
223 |
cout << endl << flush; |
cout << endl << flush; |
224 |
CFmt cfmt; |
CFmt cfmt; |
226 |
cout << line.substr(0,3) << flush; |
cout << line.substr(0,3) << flush; |
227 |
cfmt.reset(); |
cfmt.reset(); |
228 |
cout << line.substr(3) << endl << flush; |
cout << line.substr(3) << endl << flush; |
229 |
|
printPrompt(); |
230 |
} else if (line.substr(0,3) == "ERR") { // single-line response expected ... |
} else if (line.substr(0,3) == "ERR") { // single-line response expected ... |
231 |
cout << endl << flush; |
cout << endl << flush; |
232 |
CFmt cfmt; |
CFmt cfmt; |
234 |
cout << line.substr(0,3) << flush; |
cout << line.substr(0,3) << flush; |
235 |
cfmt.reset(); |
cfmt.reset(); |
236 |
cout << line.substr(3) << endl << flush; |
cout << line.substr(3) << endl << flush; |
237 |
} else if (g_client.multiLine()) { // multi-line response expected ... |
printPrompt(); |
238 |
|
} else if (g_client->multiLine()) { // multi-line response expected ... |
239 |
cout << endl << flush; |
cout << endl << flush; |
240 |
while (true) { |
while (true) { |
241 |
cout << line << endl << flush; |
cout << line << endl << flush; |
242 |
if (line.substr(0, 1) == ".") break; |
if (line.substr(0, 1) == ".") break; |
243 |
if (!g_client.lineAvailable()) break; |
if (!g_client->lineAvailable()) break; |
244 |
line = *g_client.popLine(); |
line = *g_client->popLine(); |
245 |
} |
} |
246 |
|
printPrompt(); |
247 |
} else { |
} else { |
248 |
cout << endl << line << endl << flush; |
cout << endl << line << endl << flush; |
249 |
|
printPrompt(); |
250 |
} |
} |
251 |
} |
} |
252 |
|
|
253 |
// did keyboard input arrive? |
// did keyboard input arrive? |
254 |
while (g_keyboardReader.charAvailable()) { |
while (g_keyboardReader->charAvailable()) { |
255 |
char c = g_keyboardReader.popChar(); |
char c = g_keyboardReader->popChar(); |
256 |
|
|
257 |
CFmt cfmt; |
CFmt cfmt; |
258 |
cfmt.white(); |
cfmt.white(); |
259 |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
260 |
if (c == KBD_BACKSPACE) { |
if (c == KBD_BACKSPACE) { |
261 |
cout << "\b \b" << flush; |
if (promptOffset() < CCursor::now().column()) |
262 |
|
cout << "\b \b" << flush; |
263 |
c = '\b'; |
c = '\b'; |
264 |
} else if (c == '\t') { // auto completion ... |
} else if (c == '\t') { // auto completion ... |
265 |
autoComplete(); |
autoComplete(); |
268 |
cout << c << flush; |
cout << c << flush; |
269 |
} |
} |
270 |
|
|
271 |
g_client.send(c); |
g_client->send(c); |
272 |
} |
} |
273 |
} |
} |
274 |
|
|