Add general dispatcher for CSI and escape functions
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalcsi.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp
|
||||
objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalcsi.o swrite.o terminalframebuffer.o terminaldispatcher.o
|
||||
source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp
|
||||
objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o
|
||||
repos = templates.rpo
|
||||
executables = parse termemu
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <wchar.h>
|
||||
#include <string>
|
||||
|
||||
#include "terminal.hpp"
|
||||
|
||||
@@ -14,3 +15,4 @@ template class std::deque<Terminal::Row>;
|
||||
template class std::vector<Terminal::Cell *>;
|
||||
template class std::vector<wchar_t>;
|
||||
template class std::vector<int>;
|
||||
template class std::map<std::string, Terminal::Function>;
|
||||
|
||||
+5
-41
@@ -10,12 +10,12 @@
|
||||
using namespace Terminal;
|
||||
|
||||
Emulator::Emulator( size_t s_width, size_t s_height )
|
||||
: parser(), fb( s_width, s_height ), dispatch(), terminal_to_host()
|
||||
: parser(), fb( s_width, s_height ), dispatch()
|
||||
{}
|
||||
|
||||
std::string Emulator::input( char c, int actfd )
|
||||
{
|
||||
terminal_to_host.clear();
|
||||
dispatch.terminal_to_host.clear();
|
||||
|
||||
std::vector<Parser::Action *> vec = parser.input( c );
|
||||
|
||||
@@ -36,7 +36,7 @@ std::string Emulator::input( char c, int actfd )
|
||||
}
|
||||
|
||||
/* the user is supposed to send this string to the host, as if typed */
|
||||
return terminal_to_host;
|
||||
return dispatch.terminal_to_host;
|
||||
}
|
||||
|
||||
void Emulator::execute( Parser::Execute *act )
|
||||
@@ -118,48 +118,12 @@ void Emulator::print( Parser::Print *act )
|
||||
|
||||
void Emulator::CSI_dispatch( Parser::CSI_Dispatch *act )
|
||||
{
|
||||
/* add final char to dispatch key */
|
||||
assert( act->char_present );
|
||||
Parser::Collect act2;
|
||||
act2.char_present = true;
|
||||
act2.ch = act->ch;
|
||||
dispatch.collect( &act2 );
|
||||
|
||||
std::string dispatch_chars = dispatch.dispatch_chars;
|
||||
|
||||
if ( dispatch_chars == "K" ) {
|
||||
CSI_EL();
|
||||
act->handled = true;
|
||||
} else if ( dispatch_chars == "J" ) {
|
||||
CSI_ED();
|
||||
act->handled = true;
|
||||
} else if ( (dispatch_chars == "A")
|
||||
|| (dispatch_chars == "B")
|
||||
|| (dispatch_chars == "C")
|
||||
|| (dispatch_chars == "D")
|
||||
|| (dispatch_chars == "H")
|
||||
|| (dispatch_chars == "f") ) {
|
||||
CSI_cursormove();
|
||||
act->handled = true;
|
||||
} else if ( dispatch_chars == "c" ) {
|
||||
CSI_DA();
|
||||
act->handled = true;
|
||||
}
|
||||
dispatch.dispatch( CSI, act, &fb );
|
||||
}
|
||||
|
||||
void Emulator::Esc_dispatch( Parser::Esc_Dispatch *act )
|
||||
{
|
||||
/* add final char to dispatch key */
|
||||
assert( act->char_present );
|
||||
Parser::Collect act2;
|
||||
act2.char_present = true;
|
||||
act2.ch = act->ch;
|
||||
dispatch.collect( &act2 );
|
||||
|
||||
if ( dispatch.dispatch_chars == "#8" ) {
|
||||
Esc_DECALN();
|
||||
act->handled = true;
|
||||
}
|
||||
dispatch.dispatch( ESCAPE, act, &fb );
|
||||
}
|
||||
|
||||
void Emulator::debug_printout( int fd )
|
||||
|
||||
@@ -25,8 +25,6 @@ namespace Terminal {
|
||||
Framebuffer fb;
|
||||
Dispatcher dispatch;
|
||||
|
||||
std::string terminal_to_host;
|
||||
|
||||
/* action methods */
|
||||
void print( Parser::Print *act );
|
||||
void execute( Parser::Execute *act );
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "terminal.hpp"
|
||||
|
||||
using namespace Terminal;
|
||||
|
||||
static void clearline( Framebuffer *fb, int row, int start, int end )
|
||||
{
|
||||
for ( int col = start; col <= end; col++ ) {
|
||||
fb->get_cell( row, col )->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::CSI_EL( void )
|
||||
{
|
||||
/* default: active position to end of line, inclusive */
|
||||
int start = fb.ds.get_cursor_col(), end = fb.ds.get_width() - 1;
|
||||
|
||||
if ( dispatch.params == "1" ) { /* start of screen to active position, inclusive */
|
||||
start = 0;
|
||||
end = fb.ds.get_cursor_col();
|
||||
} else if ( dispatch.params == "2" ) { /* all of line */
|
||||
start = 0;
|
||||
}
|
||||
|
||||
clearline( &fb, -1, start, end );
|
||||
}
|
||||
|
||||
void Emulator::CSI_ED( void ) {
|
||||
if ( dispatch.params == "1" ) { /* start of screen to active position, inclusive */
|
||||
for ( int y = 0; y < fb.ds.get_cursor_row(); y++ ) {
|
||||
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
|
||||
}
|
||||
clearline( &fb, -1, 0, fb.ds.get_cursor_col() );
|
||||
} else if ( dispatch.params == "2" ) { /* entire screen */
|
||||
for ( int y = 0; y < fb.ds.get_height(); y++ ) {
|
||||
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
|
||||
}
|
||||
} else { /* active position to end of screen, inclusive */
|
||||
clearline( &fb, -1, fb.ds.get_cursor_col(), fb.ds.get_width() - 1 );
|
||||
for ( int y = fb.ds.get_cursor_row() + 1; y < fb.ds.get_height(); y++ ) {
|
||||
clearline( &fb, y, 0, fb.ds.get_width() - 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::CSI_cursormove( void )
|
||||
{
|
||||
int num = dispatch.getparam( 0, 1 );
|
||||
|
||||
switch ( dispatch.dispatch_chars[ 0 ] ) {
|
||||
case 'A':
|
||||
fb.ds.move_row( -num, true );
|
||||
break;
|
||||
case 'B':
|
||||
fb.ds.move_row( num, true );
|
||||
break;
|
||||
case 'C':
|
||||
fb.ds.move_col( num, true );
|
||||
break;
|
||||
case 'D':
|
||||
fb.ds.move_col( -num, true );
|
||||
break;
|
||||
case 'H':
|
||||
case 'f':
|
||||
int x = dispatch.getparam( 0, 1 );
|
||||
int y = dispatch.getparam( 1, 1 );
|
||||
fb.ds.move_row( x - 1 );
|
||||
fb.ds.move_col( y - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
void Emulator::CSI_DA( void )
|
||||
{
|
||||
terminal_to_host.append( "\033[?1;0c" );
|
||||
}
|
||||
|
||||
void Emulator::Esc_DECALN( void )
|
||||
{
|
||||
for ( int y = 0; y < fb.ds.get_height(); y++ ) {
|
||||
for ( int x = 0; x < fb.ds.get_width(); x++ ) {
|
||||
fb.get_cell( y, x )->reset();
|
||||
fb.get_cell( y, x )->contents.push_back( L'E' );
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
-1
@@ -8,7 +8,8 @@
|
||||
using namespace Terminal;
|
||||
|
||||
Dispatcher::Dispatcher()
|
||||
: params(), parsed_params(), parsed( false ), dispatch_chars()
|
||||
: params(), parsed_params(), parsed( false ), dispatch_chars(),
|
||||
terminal_to_host()
|
||||
{}
|
||||
|
||||
void Dispatcher::newparamchar( Parser::Param *act )
|
||||
@@ -106,3 +107,44 @@ std::string Dispatcher::str( void )
|
||||
dispatch_chars.c_str(), params.c_str() );
|
||||
return std::string( assum );
|
||||
}
|
||||
|
||||
static void register_function( Function_Type type,
|
||||
std::string dispatch_chars,
|
||||
Function f )
|
||||
{
|
||||
switch ( type ) {
|
||||
case ESCAPE:
|
||||
global_dispatch_registry.escape.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
|
||||
break;
|
||||
case CSI:
|
||||
global_dispatch_registry.CSI.insert( dispatch_map_t::value_type( dispatch_chars, f ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Function::Function( Function_Type type, std::string dispatch_chars,
|
||||
void (*s_function)( Framebuffer *, Dispatcher * ) )
|
||||
: function( s_function )
|
||||
{
|
||||
register_function( type, dispatch_chars, *this );
|
||||
}
|
||||
|
||||
void Dispatcher::dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb )
|
||||
{
|
||||
/* add final char to dispatch key */
|
||||
assert( act->char_present );
|
||||
Parser::Collect act2;
|
||||
act2.char_present = true;
|
||||
act2.ch = act->ch;
|
||||
collect( &act2 );
|
||||
|
||||
dispatch_map_t *map = (type == ESCAPE) ? &global_dispatch_registry.escape : &global_dispatch_registry.CSI;
|
||||
|
||||
dispatch_map_t::const_iterator i = map->find( dispatch_chars );
|
||||
if ( i == map->end() ) {
|
||||
return;
|
||||
} else {
|
||||
act->handled = true;
|
||||
return i->second.function( fb, this );
|
||||
}
|
||||
}
|
||||
|
||||
+34
-1
@@ -3,17 +3,45 @@
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace Parser {
|
||||
class Action;
|
||||
class Param;
|
||||
class Collect;
|
||||
class Clear;
|
||||
class Esc_Dispatch;
|
||||
class CSI_Dispatch;
|
||||
}
|
||||
|
||||
namespace Terminal {
|
||||
class Framebuffer;
|
||||
class Dispatcher;
|
||||
|
||||
enum Function_Type { ESCAPE, CSI };
|
||||
|
||||
class Function {
|
||||
public:
|
||||
Function() : function( NULL ) {}
|
||||
Function( Function_Type type, std::string dispatch_chars,
|
||||
void (*s_function)( Framebuffer *, Dispatcher * ) );
|
||||
void (*function)( Framebuffer *, Dispatcher * );
|
||||
};
|
||||
|
||||
typedef std::map<std::string, Function> dispatch_map_t;
|
||||
|
||||
class DispatchRegistry {
|
||||
public:
|
||||
dispatch_map_t escape;
|
||||
dispatch_map_t CSI;
|
||||
|
||||
DispatchRegistry() : escape(), CSI() {}
|
||||
};
|
||||
|
||||
static DispatchRegistry global_dispatch_registry;
|
||||
|
||||
class Dispatcher {
|
||||
private:
|
||||
public: /* tmp */
|
||||
std::string params;
|
||||
std::vector<int> parsed_params;
|
||||
bool parsed;
|
||||
@@ -23,6 +51,8 @@ namespace Terminal {
|
||||
void parse_params( void );
|
||||
|
||||
public:
|
||||
std::string terminal_to_host; /* this is the reply string */
|
||||
|
||||
Dispatcher();
|
||||
int getparam( size_t N, int defaultval );
|
||||
|
||||
@@ -31,6 +61,9 @@ namespace Terminal {
|
||||
void clear( Parser::Clear *act );
|
||||
|
||||
std::string str( void );
|
||||
|
||||
void dispatch( Function_Type type, Parser::Action *act, Framebuffer *fb );
|
||||
const std::string get_dispatch_chars( void ) { return dispatch_chars; }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "terminaldispatcher.hpp"
|
||||
#include "terminalframebuffer.hpp"
|
||||
|
||||
using namespace Terminal;
|
||||
|
||||
static void clearline( Framebuffer *fb, int row, int start, int end )
|
||||
{
|
||||
for ( int col = start; col <= end; col++ ) {
|
||||
fb->get_cell( row, col )->reset();
|
||||
}
|
||||
}
|
||||
|
||||
void CSI_EL( Framebuffer *fb, Dispatcher *dispatch )
|
||||
{
|
||||
switch ( dispatch->getparam( 0, 0 ) ) {
|
||||
case 0: /* default: active position to end of line, inclusive */
|
||||
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
|
||||
break;
|
||||
case 1: /* start of screen to active position, inclusive */
|
||||
clearline( fb, -1, 0, fb->ds.get_cursor_col() );
|
||||
break;
|
||||
case 2: /* all of line */
|
||||
clearline( fb, -1, 0, fb->ds.get_width() - 1 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Function func_CSI_EL( CSI, "K", CSI_EL );
|
||||
|
||||
void CSI_ED( Framebuffer *fb, Dispatcher *dispatch ) {
|
||||
switch ( dispatch->getparam( 0, 0 ) ) {
|
||||
case 0: /* active position to end of screen, inclusive */
|
||||
clearline( fb, -1, fb->ds.get_cursor_col(), fb->ds.get_width() - 1 );
|
||||
for ( int y = fb->ds.get_cursor_row() + 1; y < fb->ds.get_height(); y++ ) {
|
||||
clearline( fb, y, 0, fb->ds.get_width() - 1 );
|
||||
}
|
||||
break;
|
||||
case 1: /* start of screen to active position, inclusive */
|
||||
for ( int y = 0; y < fb->ds.get_cursor_row(); y++ ) {
|
||||
clearline( fb, y, 0, fb->ds.get_width() - 1 );
|
||||
}
|
||||
clearline( fb, -1, 0, fb->ds.get_cursor_col() );
|
||||
break;
|
||||
case 2: /* entire screen */
|
||||
for ( int y = 0; y < fb->ds.get_height(); y++ ) {
|
||||
clearline( fb, y, 0, fb->ds.get_width() - 1 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static Function func_CSI_ED( CSI, "J", CSI_ED );
|
||||
|
||||
void CSI_cursormove( Framebuffer *fb, Dispatcher *dispatch )
|
||||
{
|
||||
int num = dispatch->getparam( 0, 1 );
|
||||
|
||||
switch ( dispatch->get_dispatch_chars()[ 0 ] ) {
|
||||
case 'A':
|
||||
fb->ds.move_row( -num, true );
|
||||
break;
|
||||
case 'B':
|
||||
fb->ds.move_row( num, true );
|
||||
break;
|
||||
case 'C':
|
||||
fb->ds.move_col( num, true );
|
||||
break;
|
||||
case 'D':
|
||||
fb->ds.move_col( -num, true );
|
||||
break;
|
||||
case 'H':
|
||||
case 'f':
|
||||
int x = dispatch->getparam( 0, 1 );
|
||||
int y = dispatch->getparam( 1, 1 );
|
||||
fb->ds.move_row( x - 1 );
|
||||
fb->ds.move_col( y - 1 );
|
||||
}
|
||||
}
|
||||
|
||||
static Function func_CSI_cursormove_A( CSI, "A", CSI_cursormove );
|
||||
static Function func_CSI_cursormove_B( CSI, "B", CSI_cursormove );
|
||||
static Function func_CSI_cursormove_C( CSI, "C", CSI_cursormove );
|
||||
static Function func_CSI_cursormove_D( CSI, "D", CSI_cursormove );
|
||||
static Function func_CSI_cursormove_H( CSI, "H", CSI_cursormove );
|
||||
static Function func_CSI_cursormove_f( CSI, "f", CSI_cursormove );
|
||||
|
||||
void CSI_DA( Framebuffer *fb __attribute((unused)), Dispatcher *dispatch )
|
||||
{
|
||||
dispatch->terminal_to_host.append( "\033[?1;0c" );
|
||||
}
|
||||
|
||||
static Function func_CSI_DA( CSI, "c", CSI_DA );
|
||||
|
||||
void Esc_DECALN( Framebuffer *fb, Dispatcher *dispatch __attribute((unused)) )
|
||||
{
|
||||
for ( int y = 0; y < fb->ds.get_height(); y++ ) {
|
||||
for ( int x = 0; x < fb->ds.get_width(); x++ ) {
|
||||
fb->get_cell( y, x )->reset();
|
||||
fb->get_cell( y, x )->contents.push_back( L'E' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Function func_Esc_DECALN( ESCAPE, "#8", Esc_DECALN );
|
||||
Reference in New Issue
Block a user