First local echo
This commit is contained in:
@@ -164,6 +164,8 @@ bool STMClient::process_user_input( int fd )
|
|||||||
for ( int i = 0; i < bytes_read; i++ ) {
|
for ( int i = 0; i < bytes_read; i++ ) {
|
||||||
char the_byte = buf[ i ];
|
char the_byte = buf[ i ];
|
||||||
|
|
||||||
|
overlays.get_prediction_engine().new_user_byte( the_byte, *local_framebuffer );
|
||||||
|
|
||||||
if ( quit_sequence_started ) {
|
if ( quit_sequence_started ) {
|
||||||
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
|
if ( the_byte == '.' ) { /* Quit sequence is Ctrl-^ . */
|
||||||
if ( network->attached() && (!network->shutdown_in_progress()) ) {
|
if ( network->attached() && (!network->shutdown_in_progress()) ) {
|
||||||
|
|||||||
+85
-2
@@ -1,6 +1,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <wchar.h>
|
#include <wchar.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <typeinfo>
|
||||||
|
|
||||||
#include "terminaloverlay.hpp"
|
#include "terminaloverlay.hpp"
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ void OverlayCell::apply( Framebuffer &fb ) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
*(fb.get_mutable_cell( row, col )) = replacement;
|
*(fb.get_mutable_cell( row, col )) = replacement;
|
||||||
|
fb.get_mutable_cell( row, col )->renditions.bold = true; /* XXX */
|
||||||
}
|
}
|
||||||
|
|
||||||
Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb ) const
|
Validity ConditionalOverlayCell::get_validity( const Framebuffer &fb ) const
|
||||||
@@ -84,13 +86,25 @@ void OverlayEngine::apply( Framebuffer &fb ) const
|
|||||||
|
|
||||||
void OverlayEngine::cull( const Framebuffer &fb )
|
void OverlayEngine::cull( const Framebuffer &fb )
|
||||||
{
|
{
|
||||||
elements.remove_if( [fb]( OverlayElement *x ) { return IncorrectOrExpired == x->get_validity( fb ); } );
|
auto i = elements.begin();
|
||||||
|
while ( i != elements.end() ) {
|
||||||
|
if ( (*i)->get_validity( fb ) != Pending ) {
|
||||||
|
delete (*i);
|
||||||
|
i = elements.erase( i );
|
||||||
|
} else {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OverlayCell::OverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color )
|
OverlayCell::OverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color )
|
||||||
: OverlayElement( expiration_time ), row( s_row ), col( s_col ), replacement( background_color )
|
: OverlayElement( expiration_time ), row( s_row ), col( s_col ), replacement( background_color )
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
CursorMove::CursorMove( uint64_t expiration_time, int s_new_row, int s_new_col )
|
||||||
|
: OverlayElement( expiration_time ), new_row( s_new_row ), new_col( s_new_col )
|
||||||
|
{}
|
||||||
|
|
||||||
NotificationEngine::NotificationEngine()
|
NotificationEngine::NotificationEngine()
|
||||||
: needs_render( true ),
|
: needs_render( true ),
|
||||||
last_word( timestamp() ),
|
last_word( timestamp() ),
|
||||||
@@ -238,7 +252,76 @@ void NotificationEngine::apply( Framebuffer &fb ) const
|
|||||||
OverlayEngine::apply( fb );
|
OverlayEngine::apply( fb );
|
||||||
}
|
}
|
||||||
|
|
||||||
void OverlayManager::apply( Framebuffer &fb ) const
|
void OverlayManager::apply( Framebuffer &fb )
|
||||||
{
|
{
|
||||||
|
calculate_score( fb );
|
||||||
|
predictions.cull( fb );
|
||||||
|
|
||||||
|
if ( prediction_score > 3 ) {
|
||||||
|
predictions.apply( fb );
|
||||||
|
} else if ( prediction_score == -1 ) {
|
||||||
|
predictions.clear();
|
||||||
|
prediction_score = 0;
|
||||||
|
}
|
||||||
|
|
||||||
notifications.apply( fb );
|
notifications.apply( fb );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OverlayManager::calculate_score( const Framebuffer &fb )
|
||||||
|
{
|
||||||
|
for ( auto i = predictions.begin(); i != predictions.end(); i++ ) {
|
||||||
|
switch( (*i)->get_validity( fb ) ) {
|
||||||
|
case Pending:
|
||||||
|
break;
|
||||||
|
case Correct:
|
||||||
|
prediction_score++;
|
||||||
|
break;
|
||||||
|
case IncorrectOrExpired:
|
||||||
|
prediction_score = -1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PredictionEngine::new_user_byte( char the_byte, const Framebuffer &fb )
|
||||||
|
{
|
||||||
|
uint64_t now = timestamp();
|
||||||
|
int prediction_len = 1000; /* XXX */
|
||||||
|
|
||||||
|
if ( elements.empty() ) {
|
||||||
|
/* starting from scratch */
|
||||||
|
|
||||||
|
elements.push_front( new ConditionalCursorMove( now + prediction_len,
|
||||||
|
fb.ds.get_cursor_row(),
|
||||||
|
fb.ds.get_cursor_col() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( typeid( ConditionalCursorMove ) == typeid( *elements.front() ) );
|
||||||
|
ConditionalCursorMove *ccm = static_cast<ConditionalCursorMove *>( elements.front() );
|
||||||
|
|
||||||
|
if ( (ccm->new_row >= fb.ds.get_height()) || (ccm->new_col >= fb.ds.get_width()) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (the_byte >= 0x20) && (the_byte <= 0x7E) ) {
|
||||||
|
/* XXX need to kill existing prediction if present */
|
||||||
|
|
||||||
|
const Cell *existing_cell = fb.get_cell( ccm->new_row, ccm->new_col );
|
||||||
|
|
||||||
|
ConditionalOverlayCell *coc = new ConditionalOverlayCell( now + prediction_len,
|
||||||
|
ccm->new_row, ccm->new_col,
|
||||||
|
existing_cell->renditions.background_color,
|
||||||
|
*existing_cell );
|
||||||
|
|
||||||
|
coc->replacement = *existing_cell;
|
||||||
|
coc->replacement.contents.clear();
|
||||||
|
coc->replacement.contents.push_back( the_byte );
|
||||||
|
|
||||||
|
ccm->new_col++;
|
||||||
|
ccm->expiration_time = now + prediction_len;
|
||||||
|
|
||||||
|
elements.push_back( coc );
|
||||||
|
} else {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+28
-2
@@ -43,6 +43,12 @@ namespace Overlay {
|
|||||||
Cell original_contents;
|
Cell original_contents;
|
||||||
|
|
||||||
Validity get_validity( const Framebuffer &fb ) const;
|
Validity get_validity( const Framebuffer &fb ) const;
|
||||||
|
|
||||||
|
ConditionalOverlayCell( uint64_t expiration_time, int s_row, int s_col, int background_color,
|
||||||
|
Cell s_original_contents )
|
||||||
|
: OverlayCell( expiration_time, s_row, s_col, background_color ),
|
||||||
|
original_contents( s_original_contents )
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
class CursorMove : public OverlayElement {
|
class CursorMove : public OverlayElement {
|
||||||
@@ -50,11 +56,17 @@ namespace Overlay {
|
|||||||
int new_row, new_col;
|
int new_row, new_col;
|
||||||
|
|
||||||
void apply( Framebuffer &fb ) const;
|
void apply( Framebuffer &fb ) const;
|
||||||
|
|
||||||
|
CursorMove( uint64_t expiration_time, int s_new_row, int s_new_col );
|
||||||
};
|
};
|
||||||
|
|
||||||
class ConditionalCursorMove : public CursorMove {
|
class ConditionalCursorMove : public CursorMove {
|
||||||
public:
|
public:
|
||||||
Validity get_validity( const Framebuffer &fb ) const;
|
Validity get_validity( const Framebuffer &fb ) const;
|
||||||
|
|
||||||
|
ConditionalCursorMove( uint64_t expiration_time, int s_new_row, int s_new_col )
|
||||||
|
: CursorMove( expiration_time, s_new_row, s_new_col )
|
||||||
|
{}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* the various overlays -- some predictive and some for local notifications */
|
/* the various overlays -- some predictive and some for local notifications */
|
||||||
@@ -67,6 +79,9 @@ namespace Overlay {
|
|||||||
virtual void apply( Framebuffer &fb ) const;
|
virtual void apply( Framebuffer &fb ) const;
|
||||||
void clear( void );
|
void clear( void );
|
||||||
|
|
||||||
|
typename list<OverlayElement *>::const_iterator begin( void ) { return elements.begin(); }
|
||||||
|
typename list<OverlayElement *>::const_iterator end( void ) { return elements.end(); }
|
||||||
|
|
||||||
OverlayEngine() : elements() {}
|
OverlayEngine() : elements() {}
|
||||||
virtual ~OverlayEngine();
|
virtual ~OverlayEngine();
|
||||||
};
|
};
|
||||||
@@ -90,17 +105,28 @@ namespace Overlay {
|
|||||||
NotificationEngine();
|
NotificationEngine();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PredictionEngine : public OverlayEngine {
|
||||||
|
public:
|
||||||
|
void new_user_byte( char the_byte, const Framebuffer &fb );
|
||||||
|
};
|
||||||
|
|
||||||
/* the overlay manager */
|
/* the overlay manager */
|
||||||
class OverlayManager {
|
class OverlayManager {
|
||||||
private:
|
private:
|
||||||
NotificationEngine notifications;
|
NotificationEngine notifications;
|
||||||
|
PredictionEngine predictions;
|
||||||
|
|
||||||
|
int prediction_score;
|
||||||
|
|
||||||
|
void calculate_score( const Framebuffer &fb );
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void apply( Framebuffer &fb ) const;
|
void apply( Framebuffer &fb );
|
||||||
|
|
||||||
NotificationEngine & get_notification_engine( void ) { return notifications; }
|
NotificationEngine & get_notification_engine( void ) { return notifications; }
|
||||||
|
PredictionEngine & get_prediction_engine( void ) { return predictions; }
|
||||||
|
|
||||||
OverlayManager() : notifications() {}
|
OverlayManager() : notifications(), predictions(), prediction_score( 0 ) {}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user