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=# "; |
static const String g_prompt = "lscp=# "; |
38 |
|
static std::vector<String> g_commandHistory; |
39 |
|
static int g_commandHistoryIndex = -1; |
40 |
|
|
41 |
static void printUsage() { |
static void printUsage() { |
42 |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
cout << "lscp - The LinuxSampler Control Protocol (LSCP) Shell." << endl; |
86 |
g_client->send(s); |
g_client->send(s); |
87 |
} |
} |
88 |
|
|
89 |
|
static void commandFromHistory(int offset) { |
90 |
|
if (g_commandHistoryIndex + offset < 0 || |
91 |
|
g_commandHistoryIndex + offset >= g_commandHistory.size()) return; |
92 |
|
g_commandHistoryIndex += offset; |
93 |
|
int len = g_goodPortion.size() + g_badPortion.size(); |
94 |
|
// erase current active line |
95 |
|
for (int i = 0; i < len; ++i) g_client->send('\b'); |
96 |
|
// transmit new/old line to LSCP server |
97 |
|
String command = g_commandHistory[g_commandHistory.size() - g_commandHistoryIndex - 1]; |
98 |
|
g_client->send(command); |
99 |
|
} |
100 |
|
|
101 |
|
static void previousCommand() { |
102 |
|
commandFromHistory(1); |
103 |
|
} |
104 |
|
|
105 |
|
static void nextCommand() { |
106 |
|
commandFromHistory(-1); |
107 |
|
} |
108 |
|
|
109 |
|
static void storeCommandInHistory(const String& sCommand) { |
110 |
|
g_commandHistoryIndex = -1; // reset history index |
111 |
|
// don't save the command if the previous one was the same |
112 |
|
if (g_commandHistory.empty() || g_commandHistory.back() != sCommand) |
113 |
|
g_commandHistory.push_back(sCommand); |
114 |
|
} |
115 |
|
|
116 |
int main(int argc, char *argv[]) { |
int main(int argc, char *argv[]) { |
117 |
String host = LSCP_DEFAULT_HOST; |
String host = LSCP_DEFAULT_HOST; |
118 |
int port = LSCP_DEFAULT_PORT; |
int port = LSCP_DEFAULT_PORT; |
168 |
g_keyboardReader = new KeyboardReader; |
g_keyboardReader = new KeyboardReader; |
169 |
g_keyboardReader->setCallback(onNewKeyboardInputAvailable); |
g_keyboardReader->setCallback(onNewKeyboardInputAvailable); |
170 |
g_keyboardReader->startReading(); |
g_keyboardReader->startReading(); |
171 |
|
|
172 |
|
int iKbdEscapeCharsExpected = 0; |
173 |
|
char kbdPrevEscapeChar; |
174 |
|
|
175 |
// main thread's loop |
// main thread's loop |
176 |
while (true) { |
while (true) { |
177 |
// sleep until either new data from the network or from keyboard arrived |
// sleep until either new data from the network or from keyboard arrived |
289 |
CFmt cfmt; |
CFmt cfmt; |
290 |
cfmt.white(); |
cfmt.white(); |
291 |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
//std::cout << c << "(" << int(c) << ")" << std::endl << std::flush; |
292 |
if (c == KBD_BACKSPACE) { |
if (iKbdEscapeCharsExpected) { // escape sequence (still) expected now ... |
293 |
|
iKbdEscapeCharsExpected--; |
294 |
|
if (iKbdEscapeCharsExpected) kbdPrevEscapeChar = c; |
295 |
|
else { // escape sequence is complete ... |
296 |
|
if (kbdPrevEscapeChar == 91 && c == 65) // up key |
297 |
|
previousCommand(); |
298 |
|
else if (kbdPrevEscapeChar == 91 && c == 66) // down key |
299 |
|
nextCommand(); |
300 |
|
else if (kbdPrevEscapeChar == 91 && c == 68) { // left key |
301 |
|
//TODO: move cursor left |
302 |
|
} else if (kbdPrevEscapeChar == 91 && c == 67) { // right key |
303 |
|
//TODO: move cursor right |
304 |
|
} |
305 |
|
} |
306 |
|
continue; // don't send this escape sequence character to LSCP server |
307 |
|
} else if (c == KBD_ESCAPE) { // escape sequence for special keys expected next ... |
308 |
|
iKbdEscapeCharsExpected = 2; |
309 |
|
continue; // don't send ESC character to LSCP server |
310 |
|
} else if (c == KBD_BACKSPACE) { |
311 |
if (promptOffset() < CCursor::now().column()) |
if (promptOffset() < CCursor::now().column()) |
312 |
cout << "\b \b" << flush; |
cout << "\b \b" << flush; |
313 |
c = '\b'; |
c = '\b'; |
314 |
} else if (c == '\t') { // auto completion ... |
} else if (c == '\t') { // auto completion ... |
315 |
autoComplete(); |
autoComplete(); |
316 |
continue; // don't send tab character to LSCP server |
continue; // don't send tab character to LSCP server |
317 |
} else if (c != '\n') { // don't apply RETURN stroke yet, since the typed command might still be corrected by the sampler |
} else if (c == '\n') { |
318 |
|
storeCommandInHistory(g_goodPortion + g_badPortion); |
319 |
|
} else { // don't apply RETURN stroke yet, since the typed command might still be corrected by the sampler |
320 |
cout << c << flush; |
cout << c << flush; |
321 |
} |
} |
322 |
|
|