Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/shell/shell_input.cc @ 6027

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

orxonox/trunk: safer shell, better key-handling

File size: 8.9 KB
RevLine 
[4744]1/*
[1853]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.
[1855]10
11   ### File Specific:
[5254]12   main-programmer: Benjamin Grauer
[1855]13   co-programmer: ...
[1853]14*/
15
[3955]16//#define DEBUG_SPECIAL_MODULE DEBUG_MODULE_
[1853]17
[5178]18#include "shell_input.h"
[1853]19
[5181]20
21
22#include "shell_command.h"
[5639]23#include "shell_command_class.h"
[5181]24#include "shell_completion.h"
[5180]25#include "event_handler.h"
[5179]26
27#include "debug.h"
28#include "list.h"
29#include "compiler.h"
30#include "stdlibincl.h"
[5180]31#include "key_names.h"
[5179]32
[5180]33
[1856]34using namespace std;
[1853]35
[5202]36SHELL_COMMAND(help, ShellInput, help)
37    ->describe("retrieve some help about the input mode")
38    ->setAlias("help");
[5237]39
[3245]40/**
[5249]41 * constructor
42 * this also generates a ShellCompletion automatically.
[3245]43*/
[5306]44ShellInput::ShellInput () : Text ((const char*)NULL)
[3365]45{
[5179]46  this->pressedKey = SDLK_FIRST;
[5202]47  this->setClassID(CL_SHELL_INPUT, "ShellInput");
[4320]48
[5179]49  this->inputLine = new char[1];
50  this->inputLine[0] = '\0';
[5784]51  this->historyIT = this->history.begin();
[5245]52  this->setHistoryLength(50);
[5243]53  this->historyScrolling = false;
[5180]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++)
[5309]60  {
61    if (!evh->isSubscribed(ES_SHELL, i))
62      evh->subscribe(this, ES_SHELL, i);
63  }
[5184]64  this->completion = new ShellCompletion(this);
[3365]65}
[1853]66
[3245]67/**
[4838]68 * standard deconstructor
[3245]69*/
[5178]70ShellInput::~ShellInput ()
[3543]71{
72  // delete what has to be deleted here
[5181]73  delete[] this->inputLine;
74  delete this->completion;
[5182]75
[5784]76  while (!this->history.empty())
[5182]77  {
[5784]78    delete[] this->history.front();
79    this->history.pop_front();
[5182]80  }
[3543]81}
[5179]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/**
[5244]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/**
[5179]130 * adds one character to the inputLine
131 * @param character the character to add to the inputLine
132 */
133void ShellInput::addCharacter(char character)
134{
[5244]135  if (this->historyScrolling)
136  {
[5784]137    delete[] this->history.back();
138    this->history.pop_back();
[5244]139    this->historyScrolling = false;
140  }
141
[5182]142  char* addCharLine = new char[strlen(this->inputLine)+2];
[5179]143
144  sprintf(addCharLine, "%s%c", this->inputLine, character);
[5182]145  delete[] this->inputLine;
[5179]146  this->inputLine = addCharLine;
[5182]147  this->setText(this->inputLine, true);
[5179]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{
[5244]156  if (this->historyScrolling)
157  {
[5784]158    delete[] this->history.back();
159    this->history.pop_back();
[5244]160    this->historyScrolling = false;
161  }
162
[5182]163  char* addCharLine = new char[strlen(this->inputLine)+strlen(characters)+1];
[5179]164
165  sprintf(addCharLine, "%s%s", this->inputLine, characters);
[5182]166  delete[] this->inputLine;
[5179]167  this->inputLine = addCharLine;
[5182]168  this->setText(this->inputLine, true);
[5179]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{
[5244]177  if (this->historyScrolling)
178  {
[5784]179    delete[] this->history.back();
180    this->history.pop_back();
[5244]181    this->historyScrolling = false;
182  }
183
[5179]184  if (strlen(this->inputLine) == 0)
185    return;
186
187  if (characterCount > strlen(this->inputLine))
188    characterCount = strlen(this->inputLine);
189
[5182]190  char* removeCharLine = new char[strlen(this->inputLine)-characterCount+1];
[5179]191
[5182]192  strncpy(removeCharLine, this->inputLine, strlen(this->inputLine)-characterCount);
193  removeCharLine[strlen(this->inputLine)-characterCount] = '\0';
194  delete[] this->inputLine;
[5179]195  this->inputLine = removeCharLine;
[5182]196  this->setText(this->inputLine, true);
[5179]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
[5369]207  if (strlen(this->inputLine) == 0)
208    return false;
209
[5179]210  char* newCommand = new char[strlen(this->inputLine)+1];
211  strcpy(newCommand, this->inputLine);
212
[5636]213  ShellCommand::execute(newCommand);
[5369]214
[5243]215  // removing the eventually added Entry (from scrolling) to the List
216  if (this->historyScrolling)
217  {
[5784]218    delete[] this->history.back();
219    this->history.pop_back();
[5243]220    this->historyScrolling = false;
221  }
222
223  // adding the new Command to the History
[5784]224  this->history.push_back(newCommand);
225  if (this->history.size() > this->historyLength)
[5243]226  {
[5784]227    delete[] this->history.front();
228    this->history.pop_front();
[5243]229  }
230
[5179]231  this->flush();
232
[5369]233  return true;
[5179]234}
235
[5180]236
237/**
[5243]238 * moves one entry up in the history.
239 */
240void ShellInput::historyMoveUp()
241{
242  if (!this->historyScrolling)
243  {
[5244]244    char* currentText = new char[strlen(this->inputLine)+1];
245    strcpy(currentText, this->inputLine);
[5784]246    this->history.push_back(currentText);
[5243]247    this->historyScrolling = true;
[5785]248    this->historyIT = --this->history.end();
[5243]249  }
250
[5785]251  if(this->historyIT != this->history.begin())
[5243]252  {
[5785]253    char* prevElem = *(--this->historyIT);
254    if (prevElem == NULL)
255      return;
256    else
257    {
258      this->flush();
259      this->setInputText(prevElem);
260    }
[5243]261  }
262}
263
264/**
265 * moves one entry down in the history
266 */
267void ShellInput::historyMoveDown()
268{
269  if (!this->historyScrolling)
270    return;
[5785]271  if (this->historyIT != this->history.end())
[5243]272  {
[5785]273    char* nextElem = *(++this->historyIT);
274    if (nextElem == NULL)
275      return;
276    else
277    {
278      this->flush();
279      this->setInputText(nextElem);
280    }
[5243]281  }
282}
283
284
285/**
[5180]286 * prints out some nice help about the Shell
287 */
[5204]288void ShellInput::help(const char* className, const char* functionName)
[5180]289{
[5207]290  printf("%s::%s\n", className, functionName);
291
[5204]292  if (strlen(className) == 0)
293  {
294    PRINT(0)("Help for the most important Shell-commands\n");
[5248]295    PRINT(0)("F1 - HELP; F2 - DEBUG; '`' - open/close shell\n");
[5204]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  }
[5180]306}
307
[5197]308/**
309 * ticks the ShellInput
310 * @param dt the time passed since the last update
311 */
[5180]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;
[5786]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    }
[5180]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)
[5786]351    {
[5248]352      ;//this->debug();
[5786]353    }
[5243]354    else if (event.type == SDLK_UP)
[5786]355    {
[5243]356      this->historyMoveUp();
[5786]357      this->pressedKey = event.type;
358    }
[5243]359    else if (event.type == SDLK_DOWN)
[5786]360    {
[5243]361      this->historyMoveDown();
[5786]362      this->pressedKey = event.type;
363    }
[5180]364    else if (event.type == SDLK_TAB)
[5184]365      this->completion->autoComplete();
[5180]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)
[5786]373    {
[5180]374      this->executeCommand();
[5786]375      this->pressedKey = event.type;
376    }
[5244]377    // any other keyboard key
[5180]378    else if (likely(event.type < 127))
379    {
[5786]380      this->addCharacter(event.x);
381      this->pressedKey = event.x;
[5180]382    }
[5786]383    this->delayed = this->repeatDelay;
[5180]384  }
385  else // if(!event.bPressed)
386  {
[5787]387    if (this->pressedKey == event.x || this->pressedKey == event.type)
[5180]388    {
[5786]389      this->pressedKey = 0;
[5180]390      this->delayed = 0.0;
391    }
392  }
393}
Note: See TracBrowser for help on using the repository browser.