Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/branches/height_map/src/lib/shell/shell_input.cc @ 6390

Last change on this file since 6390 was 5787, checked in by bensch, 19 years ago

orxonox/trunk: safer shell, better key-handling

File size: 8.9 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Benjamin Grauer
13   co-programmer: ...
14*/
15
16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
17
18#include "shell_input.h"
19
20
21
22#include "shell_command.h"
23#include "shell_command_class.h"
24#include "shell_completion.h"
25#include "event_handler.h"
26
27#include "debug.h"
28#include "list.h"
29#include "compiler.h"
30#include "stdlibincl.h"
31#include "key_names.h"
32
33
34using namespace std;
35
36SHELL_COMMAND(help, ShellInput, help)
37    ->describe("retrieve some help about the input mode")
38    ->setAlias("help");
39
40/**
41 * constructor
42 * this also generates a ShellCompletion automatically.
43*/
44ShellInput::ShellInput () : Text ((const char*)NULL)
45{
46  this->pressedKey = SDLK_FIRST;
47  this->setClassID(CL_SHELL_INPUT, "ShellInput");
48
49  this->inputLine = new char[1];
50  this->inputLine[0] = '\0';
51  this->historyIT = this->history.begin();
52  this->setHistoryLength(50);
53  this->historyScrolling = false;
54  this->delayed = 0;
55  this->setRepeatDelay(.3, .05);
56
57  // subscribe all keyboard commands to ES_SEHLL
58  EventHandler* evh = EventHandler::getInstance();
59  for (int i = 1; i < SDLK_LAST; i++)
60  {
61    if (!evh->isSubscribed(ES_SHELL, i))
62      evh->subscribe(this, ES_SHELL, i);
63  }
64  this->completion = new ShellCompletion(this);
65}
66
67/**
68 * standard deconstructor
69*/
70ShellInput::~ShellInput ()
71{
72  // delete what has to be deleted here
73  delete[] this->inputLine;
74  delete this->completion;
75
76  while (!this->history.empty())
77  {
78    delete[] this->history.front();
79    this->history.pop_front();
80  }
81}
82
83/**
84 * sets the Repeate-delay and rate
85 * @param repeatDelay the Delay it takes, to repeate a key
86 * @param repeatRate the rate to repeate a pressed key
87 */
88void ShellInput::setRepeatDelay(float repeatDelay, float repeatRate)
89{
90  this->repeatDelay = repeatDelay;
91  this->repeatRate = repeatRate;
92}
93
94/**
95 * deletes the InputLine
96 */
97void ShellInput::flush()
98{
99  if (likely(this->inputLine != NULL))
100  {
101    delete[] this->inputLine;
102  }
103  this->inputLine = new char[1];
104  *this->inputLine = '\0';
105  this->setText(this->inputLine, true);
106}
107
108/**
109 * sets the entire text of the InputLine to text
110 * @param text the new Text to set as InputLine
111 */
112void ShellInput::setInputText(const char* text)
113{
114  delete[] this->inputLine;
115  if (text == NULL)
116  {
117    this->inputLine = new char[1];
118    this->inputLine[0] = '\0';
119  }
120  else
121  {
122    this->inputLine = new char[strlen(text)+1];
123    strcpy(this->inputLine, text);
124  }
125  this->setText(this->inputLine, true);
126}
127
128
129/**
130 * adds one character to the inputLine
131 * @param character the character to add to the inputLine
132 */
133void ShellInput::addCharacter(char character)
134{
135  if (this->historyScrolling)
136  {
137    delete[] this->history.back();
138    this->history.pop_back();
139    this->historyScrolling = false;
140  }
141
142  char* addCharLine = new char[strlen(this->inputLine)+2];
143
144  sprintf(addCharLine, "%s%c", this->inputLine, character);
145  delete[] this->inputLine;
146  this->inputLine = addCharLine;
147  this->setText(this->inputLine, true);
148}
149
150/**
151 * adds multiple Characters to thr inputLine
152 * @param characters a \\0 terminated char-array to add to the InputLine
153 */
154void ShellInput::addCharacters(const char* characters)
155{
156  if (this->historyScrolling)
157  {
158    delete[] this->history.back();
159    this->history.pop_back();
160    this->historyScrolling = false;
161  }
162
163  char* addCharLine = new char[strlen(this->inputLine)+strlen(characters)+1];
164
165  sprintf(addCharLine, "%s%s", this->inputLine, characters);
166  delete[] this->inputLine;
167  this->inputLine = addCharLine;
168  this->setText(this->inputLine, true);
169}
170
171/**
172 * removes characterCount characters from the InputLine
173 * @param characterCount the count of Characters to remove from the input Line
174 */
175void ShellInput::removeCharacters(unsigned int characterCount)
176{
177  if (this->historyScrolling)
178  {
179    delete[] this->history.back();
180    this->history.pop_back();
181    this->historyScrolling = false;
182  }
183
184  if (strlen(this->inputLine) == 0)
185    return;
186
187  if (characterCount > strlen(this->inputLine))
188    characterCount = strlen(this->inputLine);
189
190  char* removeCharLine = new char[strlen(this->inputLine)-characterCount+1];
191
192  strncpy(removeCharLine, this->inputLine, strlen(this->inputLine)-characterCount);
193  removeCharLine[strlen(this->inputLine)-characterCount] = '\0';
194  delete[] this->inputLine;
195  this->inputLine = removeCharLine;
196  this->setText(this->inputLine, true);
197}
198
199/**
200 * executes the command stored in the inputLine
201 * @return true if the command was commited successfully, false otherwise
202 */
203bool ShellInput::executeCommand()
204{
205  ShellBuffer::addBufferLineStatic("Execute Command: %s\n", this->inputLine);
206
207  if (strlen(this->inputLine) == 0)
208    return false;
209
210  char* newCommand = new char[strlen(this->inputLine)+1];
211  strcpy(newCommand, this->inputLine);
212
213  ShellCommand::execute(newCommand);
214
215  // removing the eventually added Entry (from scrolling) to the List
216  if (this->historyScrolling)
217  {
218    delete[] this->history.back();
219    this->history.pop_back();
220    this->historyScrolling = false;
221  }
222
223  // adding the new Command to the History
224  this->history.push_back(newCommand);
225  if (this->history.size() > this->historyLength)
226  {
227    delete[] this->history.front();
228    this->history.pop_front();
229  }
230
231  this->flush();
232
233  return true;
234}
235
236
237/**
238 * moves one entry up in the history.
239 */
240void ShellInput::historyMoveUp()
241{
242  if (!this->historyScrolling)
243  {
244    char* currentText = new char[strlen(this->inputLine)+1];
245    strcpy(currentText, this->inputLine);
246    this->history.push_back(currentText);
247    this->historyScrolling = true;
248    this->historyIT = --this->history.end();
249  }
250
251  if(this->historyIT != this->history.begin())
252  {
253    char* prevElem = *(--this->historyIT);
254    if (prevElem == NULL)
255      return;
256    else
257    {
258      this->flush();
259      this->setInputText(prevElem);
260    }
261  }
262}
263
264/**
265 * moves one entry down in the history
266 */
267void ShellInput::historyMoveDown()
268{
269  if (!this->historyScrolling)
270    return;
271  if (this->historyIT != this->history.end())
272  {
273    char* nextElem = *(++this->historyIT);
274    if (nextElem == NULL)
275      return;
276    else
277    {
278      this->flush();
279      this->setInputText(nextElem);
280    }
281  }
282}
283
284
285/**
286 * prints out some nice help about the Shell
287 */
288void ShellInput::help(const char* className, const char* functionName)
289{
290  printf("%s::%s\n", className, functionName);
291
292  if (strlen(className) == 0)
293  {
294    PRINT(0)("Help for the most important Shell-commands\n");
295    PRINT(0)("F1 - HELP; F2 - DEBUG; '`' - open/close shell\n");
296    PRINT(0)("input order:\n");
297    PRINT(0)("ClassName [objectName] function [parameter1, [parameter2 ...]]  or\n");
298    PRINT(0)("Alias [parameter]\n");
299    PRINT(0)("- Also try 'help className'");
300  }
301  else if (strlen (className) > 0 && strlen (functionName) == 0)
302  {
303    ShellCommandClass::help(className);
304    //PRINTF(1)("%s::%s\n", className, functionName);
305  }
306}
307
308/**
309 * ticks the ShellInput
310 * @param dt the time passed since the last update
311 */
312void ShellInput::tick(float dt)
313{
314  if (this->delayed > 0.0)
315    this->delayed -= dt;
316  else if (this->pressedKey != SDLK_FIRST )
317  {
318    this->delayed = this->repeatRate;
319    switch (this->pressedKey )
320    {
321      case SDLK_BACKSPACE:
322        this->removeCharacters(1);
323        break;
324      case SDLK_UP:
325        this->historyMoveUp();
326        break;
327      case SDLK_DOWN:
328        this->historyMoveDown();
329        break;
330      default:
331      {
332        if (likely(pressedKey < 127))
333          this->addCharacter(this->pressedKey);
334      }
335    }
336  }
337}
338
339/**
340 * listens for some event
341 * @param event the Event happened
342 */
343void ShellInput::process(const Event &event)
344{
345  if (event.bPressed)
346  {
347    PRINTF(5)("Shell received command %s\n", SDLKToKeyname(event.type));
348    if (event.type == SDLK_F1)
349      this->help();
350    else if (event.type == SDLK_F2)
351    {
352      ;//this->debug();
353    }
354    else if (event.type == SDLK_UP)
355    {
356      this->historyMoveUp();
357      this->pressedKey = event.type;
358    }
359    else if (event.type == SDLK_DOWN)
360    {
361      this->historyMoveDown();
362      this->pressedKey = event.type;
363    }
364    else if (event.type == SDLK_TAB)
365      this->completion->autoComplete();
366    else if (event.type == SDLK_BACKSPACE)
367    {
368      this->delayed = this->repeatDelay;
369      this->pressedKey = SDLK_BACKSPACE;
370      this->removeCharacters(1);
371    }
372    else if (event.type == SDLK_RETURN)
373    {
374      this->executeCommand();
375      this->pressedKey = event.type;
376    }
377    // any other keyboard key
378    else if (likely(event.type < 127))
379    {
380      this->addCharacter(event.x);
381      this->pressedKey = event.x;
382    }
383    this->delayed = this->repeatDelay;
384  }
385  else // if(!event.bPressed)
386  {
387    if (this->pressedKey == event.x || this->pressedKey == event.type)
388    {
389      this->pressedKey = 0;
390      this->delayed = 0.0;
391    }
392  }
393}
Note: See TracBrowser for help on using the repository browser.