@@ -404,7 +404,7 @@ void Console::Update()
404404 Rect r = CellRect (cursorX, cursorY);
405405 if (cursorDrawn)
406406 DrawCell (cursorX, cursorY, true );
407- else
407+ else if (cursorRequestedHidden == false )
408408 InvertRect (&r);
409409 cursorDrawn = !cursorDrawn;
410410 }
@@ -546,9 +546,21 @@ char Console::WaitNextChar()
546546// Map a letter to a function
547547void Console::InitEscapeSequenceMap ()
548548{
549- escapeSequenceMap.insert ({' H' , [&](std::string args) { Console::SetCursorPosition (args); } });
549+ escapeSequenceMap.insert ({' A' , [&](std::string args) { MoveCursorUp (args); } });
550+ escapeSequenceMap.insert ({' B' , [&](std::string args) { MoveCursorDown (args); } });
551+ escapeSequenceMap.insert ({' C' , [&](std::string args) { MoveCursorForward (args); } });
552+ escapeSequenceMap.insert ({' D' , [&](std::string args) { MoveCursorBack (args); } });
553+ escapeSequenceMap.insert ({' E' , [&](std::string args) { MoveCursorNextLine (args); } });
554+ escapeSequenceMap.insert ({' F' , [&](std::string args) { MoveCursorPreviousLine (args); } });
555+ escapeSequenceMap.insert ({' G' , [&](std::string args) { MoveCursorHorizonalAbsolute (args); } });
556+ escapeSequenceMap.insert ({' H' , [&](std::string args) { SetCursorPosition (args); } });
550557 escapeSequenceMap.insert ({' J' , [&](std::string args) { EraseInDisplay (args); } });
558+ escapeSequenceMap.insert ({' K' , [&](std::string args) { EraseInLine (args); } });
559+ escapeSequenceMap.insert ({' h' , [&](std::string args) { ShowCursor (args); } });
560+ escapeSequenceMap.insert ({' l' , [&](std::string args) { HideCursor (args); } });
551561 escapeSequenceMap.insert ({' m' , [&](std::string args) { SetDisplayAttributes (args); } });
562+ escapeSequenceMap.insert ({' s' , [&](std::string args) { SaveCursorPosition (args); } });
563+ escapeSequenceMap.insert ({' u' , [&](std::string args) { RestoreCursorPosition (args); } });
552564}
553565
554566// turns an argument string into numbers
@@ -590,8 +602,8 @@ void Console::SetCursorPosition(std::string args)
590602 // -> (1,1)
591603
592604 auto numberVector = parseArguments (args);
593- cursorX = numberVector.at (1 );
594- cursorY = numberVector.at (0 );
605+ SetCursorX ( numberVector.at (1 ) );
606+ SetCursorY ( numberVector.at (0 ) );
595607 Update ();
596608}
597609
@@ -667,7 +679,7 @@ void Console::ClearWindow()
667679// Clears the window of text from the current cursor position to the bottom of the window
668680void Console::ClearFromCursorToEndOfWindow ()
669681{
670- int newPosition = cursorY * cols + cursorX ;
682+ int newPosition = GetCursorY () * cols + GetCursorX () - 1 ;
671683
672684 // Fill the buffer with blank spaces
673685 std::fill (chars.begin () + newPosition, chars.end (), AttributedChar (' ' , currentAttr));
@@ -682,7 +694,7 @@ void Console::ClearFromCursorToEndOfWindow()
682694// Clears the window from the top to the current cursor position
683695void Console::ClearFromTopOfWindowToCursor ()
684696{
685- int newPosition = cursorY * cols + cursorX ;
697+ int newPosition = GetCursorY () * cols + GetCursorX () ;
686698
687699 // Fill the buffer with blank spaces
688700 std::fill (chars.begin (), chars.begin () + newPosition, AttributedChar (' ' , currentAttr));
@@ -710,3 +722,282 @@ void Console::HandleControlSequence(char c)
710722 argument = argument + c;
711723 }
712724}
725+
726+ // Bound to ANSI escape code A
727+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
728+ // Section: Some ANSI control sequences
729+ // Name: Cursor Up
730+ void Console::MoveCursorUp (std::string args)
731+ {
732+ auto numberVector = parseArguments (args);
733+ int lines;
734+ if (numberVector.size () == 0 )
735+ {
736+ lines = 1 ;
737+ }
738+ else
739+ {
740+ lines = numberVector.at (0 );
741+ }
742+ SetCursorY (GetCursorY () - lines);
743+ Update ();
744+ }
745+
746+ // Bound to ANSI escape code B
747+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
748+ // Section: Some ANSI control sequences
749+ // Name: Cursor Down
750+ void Console::MoveCursorDown (std::string args)
751+ {
752+ auto numberVector = parseArguments (args);
753+ int lines;
754+ if (numberVector.size () == 0 )
755+ {
756+ lines = 1 ;
757+ }
758+ else
759+ {
760+ lines = numberVector.at (0 );
761+ }
762+ SetCursorY (GetCursorY () + lines);
763+ Update ();
764+ }
765+
766+ // Bound to ANSI escape code C
767+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
768+ // Section: Some ANSI control sequences
769+ // Name: Cursor Forward
770+ void Console::MoveCursorForward (std::string args)
771+ {
772+ auto numberVector = parseArguments (args);
773+ int columns;
774+ if (numberVector.size () == 0 )
775+ {
776+ columns = 1 ;
777+ }
778+ else
779+ {
780+ columns = numberVector.at (0 );
781+ }
782+ SetCursorX (GetCursorX () + columns);
783+ Update ();
784+ }
785+
786+ // Bound to ANSI escape code D
787+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
788+ // Section: Some ANSI control sequences
789+ // Name: Cursor Back
790+ void Console::MoveCursorBack (std::string args)
791+ {
792+ auto numberVector = parseArguments (args);
793+ int columns;
794+ if (numberVector.size () == 0 )
795+ {
796+ columns = 1 ;
797+ }
798+ else
799+ {
800+ columns = numberVector.at (0 );
801+ }
802+ SetCursorX (GetCursorX () - columns);
803+ Update ();
804+ }
805+
806+ // Bound to ANSI escape code E
807+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
808+ // Section: Some ANSI control sequences
809+ // Name: Cursor Next Line
810+ void Console::MoveCursorNextLine (std::string args)
811+ {
812+ auto numberVector = parseArguments (args);
813+ int lines;
814+ if (numberVector.size () == 0 )
815+ {
816+ lines = 1 ;
817+ }
818+ else
819+ {
820+ lines = numberVector.at (0 );
821+ }
822+ SetCursorX (1 );
823+ SetCursorY (GetCursorY () + lines);
824+ Update ();
825+ }
826+
827+ // Bound to ANSI escape code F
828+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
829+ // Section: Some ANSI control sequences
830+ // Name: Cursor Previous Line
831+ void Console::MoveCursorPreviousLine (std::string args)
832+ {
833+ auto numberVector = parseArguments (args);
834+ int lines;
835+ if (numberVector.size () == 0 )
836+ {
837+ lines = 1 ;
838+ }
839+ else
840+ {
841+ lines = numberVector.at (0 );
842+ }
843+ SetCursorX (1 );
844+ SetCursorY (GetCursorY () - lines);
845+ Update ();
846+ }
847+
848+ // Bound to ANSI escape code G
849+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
850+ // Section: Some ANSI control sequences
851+ // Name: Cursor Horizontal Absolute
852+ void Console::MoveCursorHorizonalAbsolute (std::string args)
853+ {
854+ auto numberVector = parseArguments (args);
855+ auto newPosition = numberVector.at (0 );
856+ SetCursorX (newPosition);
857+ Update ();
858+ }
859+
860+ // Bound to ANSI escape code K
861+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
862+ // Section: Some ANSI control sequences
863+ // Name: Erase in Line
864+ void Console::EraseInLine (std::string args)
865+ {
866+ auto numberVector = parseArguments (args);
867+ int argument = numberVector.at (0 );
868+ switch (argument)
869+ {
870+ case 0 :
871+ ClearFromCursorToEndOfLine ();
872+ break ;
873+ case 1 :
874+ ClearFromBeginningOfLineToCursor ();
875+ break ;
876+ case 2 :
877+ ClearEntireLine ();
878+ break ;
879+ }
880+ }
881+
882+ // Erases from the current cursor position to the end of the line
883+ void Console::ClearFromCursorToEndOfLine ()
884+ {
885+ int currentPosition = (GetCursorY () - 1 ) * cols + GetCursorX () - 1 ;
886+ int endOfLinePosition = GetCursorY () * cols;
887+
888+ // Fill part of the buffer with blank spaces
889+ std::fill (chars.begin () + currentPosition, chars.begin () + endOfLinePosition, AttributedChar (' ' , currentAttr));
890+ std::fill (onscreen.begin () + currentPosition, onscreen.begin () + endOfLinePosition, AttributedChar (' ' , currentAttr));
891+
892+ Update ();
893+
894+ // Erase only on the line the cursor is on
895+ Rect rect;
896+ rect = CellRect (cursorX, cursorY);
897+ rect.right = cols * cellSizeX;
898+ EraseRect (&rect);
899+ }
900+
901+ // Erases from the beginning of the line to the cursor's position
902+ void Console::ClearFromBeginningOfLineToCursor ()
903+ {
904+ int currentPosition = (GetCursorY () - 1 ) * cols + GetCursorX ();
905+ int beginningOfLinePosition = (GetCursorY () - 1 ) * cols;
906+
907+ // Fill part of the buffer with blank spaces
908+ std::fill (chars.begin () + beginningOfLinePosition, chars.begin () + currentPosition, AttributedChar (' ' , currentAttr));
909+ std::fill (onscreen.begin () + beginningOfLinePosition, onscreen.begin () + currentPosition, AttributedChar (' ' , currentAttr));
910+
911+ Update ();
912+
913+ // Erase only on the line the cursor is on
914+ Rect rect;
915+ rect = CellRect (0 , cursorY);
916+ rect.right = GetCursorX () * cellSizeX;
917+ EraseRect (&rect);
918+ }
919+
920+ // Erases the entire line the cursor is on
921+ void Console::ClearEntireLine ()
922+ {
923+ int beginningOfLinePosition = (GetCursorY () - 1 ) * cols;
924+ int endOfLinePosition = GetCursorY () * cols;
925+
926+ // Fill part of the buffer with blank spaces
927+ std::fill (chars.begin () + beginningOfLinePosition, chars.begin () + endOfLinePosition, AttributedChar (' ' , currentAttr));
928+ std::fill (onscreen.begin () + beginningOfLinePosition, onscreen.begin () + endOfLinePosition, AttributedChar (' ' , currentAttr));
929+
930+ Update ();
931+
932+ // Erase only the line the cursor is on
933+ Rect rect;
934+ rect = CellRect (0 , cursorY);
935+ rect.right = cols * cellSizeX;
936+ EraseRect (&rect);
937+ }
938+
939+ // Bound to ANSI escape code h
940+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
941+ // Section: Some popular private sequences
942+ // Description: Sets a variable to indicate the cursor should be shown
943+ void Console::ShowCursor (std::string args)
944+ {
945+ cursorRequestedHidden = false ;
946+ }
947+
948+ // Bound to ANSI escape code l
949+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
950+ // Section: Some popular private sequences
951+ // Description: Sets a variable to indicate the cursor should be hidden
952+ void Console::HideCursor (std::string args)
953+ {
954+ cursorRequestedHidden = true ;
955+ }
956+
957+ // Bound to ANSI escape code s
958+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
959+ // Section: Some popular private sequences
960+ // Description: Saves the current cursor position
961+ void Console::SaveCursorPosition (std::string args)
962+ {
963+ savedCursorX = cursorX;
964+ savedCursorY = cursorY;
965+ }
966+
967+ // Bound to ANSI escape code u
968+ // Page: https://en.wikipedia.org/wiki/ANSI_escape_code
969+ // Section: Some popular private sequences
970+ // Description: Restores the cursor's position to the saved value
971+ void Console::RestoreCursorPosition (std::string args)
972+ {
973+ cursorX = savedCursorX;
974+ cursorY = savedCursorY;
975+ }
976+
977+ /*
978+ These setter and getter functions fix a problem where ANSI escape codes expect
979+ an origin of (1,1) while the Console class expects an origin of (0,0).
980+ Only functions that work with ANSI escape codes should use these functions.
981+ */
982+
983+ void Console::SetCursorX (int newX)
984+ {
985+ cursorX = newX - 1 ;
986+ cursorX = cursorX < 0 ? 0 : cursorX; // Terminal.app does this so we will too
987+ }
988+
989+ int Console::GetCursorX ()
990+ {
991+ return cursorX + 1 ;
992+ }
993+
994+ void Console::SetCursorY (int newY)
995+ {
996+ cursorY = newY - 1 ;
997+ cursorY = cursorY < 0 ? 0 : cursorY; // Terminal.app does this so we will too
998+ }
999+
1000+ int Console::GetCursorY ()
1001+ {
1002+ return cursorY + 1 ;
1003+ }
0 commit comments