diff --git a/Makefile b/Makefile index de78ca1..a70367e 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -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 +source = parse.cpp parserstate.cpp parser.cpp templates.cpp terminal.cpp termemu.cpp parseraction.cpp terminalfunctions.cpp swrite.cpp terminalframebuffer.cpp terminaldispatcher.cpp terminaluserinput.cpp +objects = parserstate.o parser.o templates.o terminal.o parseraction.o terminalfunctions.o swrite.o terminalframebuffer.o terminaldispatcher.o terminaluserinput.o repos = templates.rpo executables = parse termemu diff --git a/parseraction.cpp b/parseraction.cpp index 9d1326e..a234e98 100644 --- a/parseraction.cpp +++ b/parseraction.cpp @@ -65,3 +65,8 @@ void OSC_End::act_on_terminal( Terminal::Emulator *emu ) { emu->OSC_end( this ); } + +void UserByte::act_on_terminal( Terminal::Emulator *emu ) +{ + emu->dispatch.terminal_to_host.append( emu->user.input( this ) ); +} diff --git a/parseraction.hpp b/parseraction.hpp index 14743ae..fc9a329 100644 --- a/parseraction.hpp +++ b/parseraction.hpp @@ -87,6 +87,17 @@ namespace Parser { std::string name( void ) { return std::string( "OSC_End" ); } void act_on_terminal( Terminal::Emulator *emu ); }; + + class UserByte : public Action { + /* user keystroke -- not part of the host-source state machine*/ + public: + char c; /* The user-source byte. We don't try to interpret the charset */ + + std::string name( void ) { return std::string( "UserByte" ); } + void act_on_terminal( Terminal::Emulator *emu ); + + UserByte( int s_c ) : c( s_c ) {} + }; } #endif diff --git a/termemu.cpp b/termemu.cpp index ced15b8..cf0d292 100644 --- a/termemu.cpp +++ b/termemu.cpp @@ -24,8 +24,9 @@ const size_t buf_size = 1024; void emulate_terminal( int fd, int debug_fd ); int copy( int src, int dest ); -int termemu( int fd, Parser::UTF8Parser *parser, - Terminal::Emulator *terminal, int debug_fd ); +int termemu( int host_fd, int src_fd, bool user, int debug_fd, + Parser::UTF8Parser *parser, + Terminal::Emulator *terminal ); int main( int argc, char *argv[], @@ -134,11 +135,11 @@ void emulate_terminal( int fd, int debug_fd ) } if ( pollfds[ 0 ].revents & POLLIN ) { - if ( copy( STDIN_FILENO, fd ) < 0 ) { + if ( termemu( fd, STDIN_FILENO, true, debug_fd, &parser, &terminal ) < 0 ) { return; } } else if ( pollfds[ 1 ].revents & POLLIN ) { - if ( termemu( fd, &parser, &terminal, debug_fd ) < 0 ) { + if ( termemu( fd, fd, false, debug_fd, &parser, &terminal ) < 0 ) { return; } } else if ( (pollfds[ 0 ].revents | pollfds[ 1 ].revents) @@ -150,28 +151,14 @@ void emulate_terminal( int fd, int debug_fd ) } } -int copy( int src, int dest ) -{ - char buf[ buf_size ]; - - ssize_t bytes_read = read( src, buf, buf_size ); - if ( bytes_read == 0 ) { /* EOF */ - return -1; - } else if ( bytes_read < 0 ) { - perror( "read" ); - return -1; - } - - return swrite( dest, buf, bytes_read ); -} - -int termemu( int fd, Parser::UTF8Parser *parser, - Terminal::Emulator *terminal, int debug_fd ) +int termemu( int host_fd, int src_fd, bool user, int debug_fd, + Parser::UTF8Parser *parser, + Terminal::Emulator *terminal ) { char buf[ buf_size ]; /* fill buffer if possible */ - ssize_t bytes_read = read( fd, buf, buf_size ); + ssize_t bytes_read = read( src_fd, buf, buf_size ); if ( bytes_read == 0 ) { /* EOF */ return -1; } else if ( bytes_read < 0 ) { @@ -179,21 +166,37 @@ int termemu( int fd, Parser::UTF8Parser *parser, return -1; } - /* feed bytes to parser, and actions to terminal */ for ( int i = 0; i < bytes_read; i++ ) { - std::list actions = parser->input( buf[ i ] ); + /* feed bytes to parser */ + std::list actions; + if ( user ) { + actions.push_back( new Parser::UserByte( buf[ i ] ) ); + } else { + actions = parser->input( buf[ i ] ); + } + + /* apply actions to terminal */ for ( std::list::iterator i = actions.begin(); i != actions.end(); i++ ) { - (*i)->act_on_terminal( terminal ); + Parser::Action *act = *i; + /* apply action to terminal */ + act->act_on_terminal( terminal ); + + /* print out action for debugging */ + if ( (debug_fd > 0) ) { + char actsum[ 64 ]; + snprintf( actsum, 64, "%s ", act->str().c_str() ); + swrite( debug_fd, actsum ); + } + + delete *i; } } terminal->debug_printout( STDOUT_FILENO ); - debug_fd = debug_fd; - /* write writeback */ std::string terminal_to_host = terminal->read_octets_to_host(); - return swrite( fd, terminal_to_host.c_str(), terminal_to_host.length() ); + return swrite( host_fd, terminal_to_host.c_str(), terminal_to_host.length() ); } diff --git a/terminal.cpp b/terminal.cpp index b2b8998..55218c5 100644 --- a/terminal.cpp +++ b/terminal.cpp @@ -10,7 +10,7 @@ using namespace Terminal; Emulator::Emulator( size_t s_width, size_t s_height ) - : fb( s_width, s_height ), dispatch() + : fb( s_width, s_height ), dispatch(), user() {} std::string Emulator::read_octets_to_host( void ) diff --git a/terminal.hpp b/terminal.hpp index ba462ed..5877d85 100644 --- a/terminal.hpp +++ b/terminal.hpp @@ -9,6 +9,7 @@ #include "parseraction.hpp" #include "terminalframebuffer.hpp" #include "terminaldispatcher.hpp" +#include "terminaluserinput.hpp" namespace Terminal { class Emulator { @@ -22,10 +23,12 @@ namespace Terminal { friend void Parser::OSC_Start::act_on_terminal( Emulator * ); friend void Parser::OSC_Put::act_on_terminal( Emulator * ); friend void Parser::OSC_End::act_on_terminal( Emulator * ); + friend void Parser::UserByte::act_on_terminal( Emulator * ); private: Framebuffer fb; Dispatcher dispatch; + UserInput user; /* action methods */ void print( Parser::Print *act ); diff --git a/terminaluserinput.cpp b/terminaluserinput.cpp new file mode 100644 index 0000000..f279989 --- /dev/null +++ b/terminaluserinput.cpp @@ -0,0 +1,25 @@ +#include "terminaluserinput.hpp" + +using namespace Terminal; + +std::string UserInput::input( Parser::UserByte *act ) +{ + char translated_str[ 2 ] = { act->c, 0 }; + + /* The user will always be in application mode. If rtm is not in + application mode, convert user's cursor control function to an + ANSI cursor control sequence */ + + /* We don't need lookahead to do this for 7-bit. */ + + if ( (!application_mode_cursor) + && (last_byte == 0x1b) /* ESC */ + && (act->c == 'O') ) { /* ESC O = 7-bit SS3 = application mode */ + translated_str[ 0 ] = '['; + } + + /* This doesn't handle the 8-bit SS3 C1 control, which would be + two octets in UTF-8. Fortunately nobody seems to send this. */ + + return std::string( translated_str ); +} diff --git a/terminaluserinput.hpp b/terminaluserinput.hpp new file mode 100644 index 0000000..37cec66 --- /dev/null +++ b/terminaluserinput.hpp @@ -0,0 +1,24 @@ +#ifndef TERMINALUSERINPUT_HPP +#define TERMINALUSERINPUT_HPP + +#include +#include "parseraction.hpp" + +namespace Terminal { + class UserInput { + private: + bool last_byte; + bool application_mode_cursor; + + public: + UserInput() + : last_byte( 0 ), + application_mode_cursor( false ) + {} + + std::string input( Parser::UserByte *act ); + void set_cursor_application_mode( bool mode ) { application_mode_cursor = mode; } + }; +} + +#endif