1 // =========================================================================
2 // @author Leonardo Florez-Valencia (florez-l@javeriana.edu.co)
3 // =========================================================================
5 #include <TinyCon/Console.h>
8 // -------------------------------------------------------------------------
9 #if defined(WIN32) || defined(_WIN32) || defined(__WIN32)
12 const char TinyCon::Console::KEY_CTRL1 = -32;
13 const char TinyCon::Console::BACKSPACE = 8;
14 const char TinyCon::Console::UP_ARROW = 72;
15 const char TinyCon::Console::DOWN_ARROW = 80;
16 const char TinyCon::Console::RIGHT_ARROW = 77;
17 const char TinyCon::Console::LEFT_ARROW = 75;
18 const char TinyCon::Console::NEWLINE = '\r';
23 const char TinyCon::Console::KEY_CTRL1 = 17;
24 const char TinyCon::Console::BACKSPACE = 127;
25 const char TinyCon::Console::UP_ARROW = 65;
26 const char TinyCon::Console::DOWN_ARROW = 66;
27 const char TinyCon::Console::RIGHT_ARROW = 67;
28 const char TinyCon::Console::LEFT_ARROW = 68;
29 const char TinyCon::Console::NEWLINE = '\n';
33 struct termios oldt, newt;
35 tcgetattr( STDIN_FILENO, &oldt );
37 newt.c_lflag &= ~( ICANON | ECHO );
38 tcsetattr( STDIN_FILENO, TCSANOW, &newt );
41 if( ch == TinyCon::Console::ESC )
45 ch = TinyCon::Console::KEY_CTRL1;
47 tcsetattr( STDIN_FILENO, TCSANOW, &oldt );
50 #endif // defined(WIN32) || defined(_WIN32) || defined(__WIN32)
52 // -------------------------------------------------------------------------
53 const unsigned long TinyCon::Console::MAX_HISTORY = 500;
54 const char TinyCon::Console::TAB = 9;
55 const char TinyCon::Console::ESC = 27;
56 const char TinyCon::Console::DEL = 51;
57 const short TinyCon::Console::M_LINE = 0;
58 const short TinyCon::Console::M_PASSWORD = 1;
60 // -------------------------------------------------------------------------
64 this->m_MaxHistory = Self::MAX_HISTORY;
68 this->m_SkipOut = false;
71 // -------------------------------------------------------------------------
73 Console( const std::string& prompt )
75 this->m_MaxHistory = Self::MAX_HISTORY;
77 this->m_Prompt = prompt;
80 this->m_SkipOut = false;
83 // -------------------------------------------------------------------------
89 // -------------------------------------------------------------------------
90 void TinyCon::Console::
93 std::cout << this->m_Prompt;
98 this->m_Char = getch( );
99 if( this->hotkeys( this->m_Char ) == 0 )
101 switch( this->m_Char )
107 case Self::KEY_CTRL1:
114 if( this->m_History.size( ) > 0 )
116 if( this->m_Pos == -1 )
118 // store current command
120 this->m_Unused.assign(
121 this->m_Buffer.begin( ), this->m_Buffer.end( )
126 for( int i = 0; i < this->m_LinePos; ++i )
127 std::cout << "\b \b";
130 this->m_Buffer.clear( );
133 if( this->m_Pos > ( this->m_History.size( ) - 1 ) )
134 this->m_Pos = this->m_History.size( ) - 1;
137 for( int i = 0; i < this->m_History[ this->m_Pos ].size( ); ++i )
138 this->m_Buffer.push_back( this->m_History[ this->m_Pos ][ i ] );
139 this->m_LinePos = this->m_Buffer.size( );
140 std::cout << this->m_History[ this->m_Pos ];
144 case Self::DOWN_ARROW:
146 if( this->m_History.size( ) > 0 )
149 for( int i = 0; i < this->m_LinePos; ++i )
150 std::cout << "\b \b";
153 this->m_Buffer.clear( );
156 if( this->m_Pos < -1 )
158 if( this->m_Pos >= 0 )
160 std::cout << this->m_History[ this->m_Pos ];
162 for( int i = 0; i < this->m_History[ this->m_Pos ].size( ); ++i )
163 this->m_Buffer.push_back(
164 this->m_History[ this->m_Pos ][ i ]
169 if( this->m_Buffer.size( ) > 0 )
171 std::cout << this->m_Unused;
174 for( int i = 0; i < this->m_Unused.size( ); ++i )
175 this->m_Buffer.push_back( this->m_Unused[ i ] );
178 this->m_LinePos = this->m_Buffer.size( );
182 case Self::LEFT_ARROW:
184 // if there are characters to move left over, do so
185 if( this->m_LinePos > 0 )
192 case Self::RIGHT_ARROW:
194 // if there are characters to move right over, do so
195 if( this->m_LinePos < this->m_Buffer.size( ) )
197 std::cout << this->m_Buffer[ this->m_LinePos ];
204 if( this->m_LinePos < this->m_Buffer.size( ) )
206 this->m_SkipOut = true;
207 this->m_Buffer.erase( this->m_Buffer.begin( ) + this->m_LinePos );
208 // update screen after current position
209 for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
210 std::cout << this->m_Buffer[ i ];
213 for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
215 // make-up for erase position
222 this->m_SkipOut = true;
228 case Self::BACKSPACE:
230 if( this->m_LinePos > 0 )
232 // move cursor back, blank char, and move cursor back again
233 std::cout << "\b \b";
234 // don't forget to clean the buffer and update line position
235 if( this->m_LinePos == this->m_Buffer.size( ) )
237 this->m_Buffer.pop_back( );
243 this->m_Buffer.erase( this->m_Buffer.begin( ) + this->m_LinePos );
244 // update screen after current position
245 for( int i = this->m_LinePos; i < this->m_Buffer.size( ); ++i )
246 std::cout << this->m_Buffer[ i ];
249 for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
251 // make-up for erase position and go to new position
264 this->m_String.assign(
265 this->m_Buffer.begin( ), this->m_Buffer.end( )
268 // save command to history
269 // trimming of command should be done in callback function
270 if( this->m_String.length( ) > 0 )
271 this->m_History.push_front( this->m_String );
274 std::cout << std::endl;
275 this->trigger( this->m_String );
277 // check for exit command
278 ok = !( this->m_Quit );
281 if( this->m_History.size( ) > this->m_MaxHistory )
282 this->m_History.pop_back( );
285 this->m_Buffer.clear( );
287 // print prompt. new line should be added from callback function
288 std::cout << this->m_Prompt;
298 if( !( this->m_SkipOut ) )
300 std::cout << this->m_Char;
301 if( this->m_LinePos != this->m_Buffer.size( ) )
303 // line position is not at end. Insert new char
304 this->m_Buffer.insert(
305 this->m_Buffer.begin( ) + this->m_LinePos, this->m_Char
307 // update screen after current position
308 for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
309 std::cout << this->m_Buffer[ i ];
310 for( int i = this->m_LinePos + 1; i < this->m_Buffer.size( ); ++i )
314 this->m_Buffer.push_back( this->m_Char );
318 this->m_SkipOut = false;
326 // -------------------------------------------------------------------------
327 void TinyCon::Console::
328 setPrompt( const std::string& prompt )
330 this->m_Prompt = prompt;
333 // -------------------------------------------------------------------------
334 int TinyCon::Console::
335 trigger( const std::string& cmd )
337 return( ( this->m_Quit )? 1: 0 );
340 // -------------------------------------------------------------------------
341 int TinyCon::Console::
347 // -------------------------------------------------------------------------
348 void TinyCon::Console::
354 // -------------------------------------------------------------------------
355 void TinyCon::Console::
361 // -------------------------------------------------------------------------
362 std::string TinyCon::Console::
365 return( this->getLine( Self::M_LINE, "" ) );
368 // -------------------------------------------------------------------------
369 std::string TinyCon::Console::
370 getLine( int mode, const std::string& delimiter )
378 if( c == Self::NEWLINE )
380 std::cout << std::endl;
383 else if( c == Self::BACKSPACE )
385 if( line.length( ) > 0 )
387 line = line.substr( 0,line.size( ) - 1 );
388 if( mode != Self::M_PASSWORD )
389 std::cout << "\b \b";
395 if( mode != Self::M_PASSWORD )
402 // -------------------------------------------------------------------------
403 void TinyCon::Console::
404 setMaxHistory( int count )
406 this->m_MaxHistory = count;
409 // -------------------------------------------------------------------------
410 void TinyCon::Console::
411 setBuffer( const std::string& buffer )
413 this->m_Buffer.assign( buffer.begin( ), buffer.end( ) );
414 this->m_LinePos = this->m_Buffer.size( );