Merge pull request #103 from DarwinNE/master

Implement escape sequence to change window title
This commit is contained in:
Wolfgang Thaller 2020-01-18 23:43:35 +00:00 committed by GitHub
commit cf75b4d9ba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 104 additions and 36 deletions

View File

@ -9,9 +9,10 @@ namespace retro
int main()
{
retro::InitConsole();
std::string out = "Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n";
std::string out = "\033]0;Hello world win\007Hello, \033[1mexternal world of \033[0m\033[3mtrue beauty and \033[4mgreatness\033[0m.\nEnter \"exit\" to quit.\n";
retro::Console::currentInstance->write(out.data(), out.size());
std::string in;
do
{

View File

@ -1,17 +1,18 @@
IConsole
Console
This is a slightly improved version of Retro68's Console library, offering a
support for a subset of ANSI control sequences.
This library provides a simple console library, offering a limited support for ANSI control sequences.
Here is a list of the supported sequences and their meaning:
ESC[0m Reset all text style
ESC[1m Bold font (*)
ESC[3m Italic font
ESC[4m Underline font
ESC[0m Reset all text style
ESC[1m Bold font (*)
ESC[3m Italic font
ESC[4m Underline font
ESC]0;NewnameBEL Set the window title to "Newname" (**)
NOTES:
(*) Obtained with bold + condense style together, so that the character grid
remains regular (this way, the width of bold characters remains the same as
regular ones).
(**) BEL is ASCII character 7.

View File

@ -30,6 +30,9 @@
using namespace retro;
const char BEL = 7;
const char MAX_LEN = 250;
Console *Console::currentInstance = NULL;
Attributes::Attributes(void)
@ -162,7 +165,7 @@ void Console::Init(GrafPtr port, Rect r)
onscreen = chars;
cursorX = cursorY = 0;
isProcessingEscSequence=false;
sequenceState=State::noSequence;
}
void Console::SetAttributes(Attributes aa)
@ -265,18 +268,22 @@ void Console::ScrollUp(short n)
dirtyRect.bottom = dirtyRect.bottom > 0 ? dirtyRect.bottom - 1 : 0;
}
void Console::ProcessEscSequence(char c)
bool Console::ProcessEscSequence(char c)
{
switch(sequenceStep)
switch(sequenceState)
{
case 0:
case State::noSequence:
return false; // Break is not needed there.
case State::waitingForSequenceStart:
if(c=='[')
++sequenceStep;
sequenceState=State::waitingForControlSequence;
else if(c==']')
sequenceState=State::waitingForOSCStart;
else
isProcessingEscSequence=false;
sequenceState=State::noSequence; // Unrecognized sequence
break;
case 1:
++sequenceStep;
case State::waitingForControlSequence:
sequenceState=State::waitingForM;
switch(c)
{
case '0': // Normal character
@ -292,35 +299,59 @@ void Console::ProcessEscSequence(char c)
currentAttr.setUnderline(true);
break;
default:
isProcessingEscSequence=false;
sequenceState=State::noSequence; // Unrecognized sequence
}
break;
case 2:
case State::waitingForM:
if(c=='m')
isProcessingEscSequence=false;
else if(c==';')
sequenceStep=1;
sequenceState=State::noSequence; // Normal end of sequence
else
isProcessingEscSequence=false;
sequenceState=State::noSequence; // Unrecognized sequence (but we end it anyway!)
break;
case State::waitingForOSCStart:
if(c=='0')
sequenceState=State::waitingForSemicolon;
else
sequenceState=State::noSequence; // Normal end of sequence
break;
case State::waitingForSemicolon:
if(c==';')
{
sequenceState=State::inWindowName;
windowName="";
}
else
sequenceState=State::noSequence; // Normal end of sequence
break;
case State::inWindowName:
if(c==BEL)
{
setWindowName(std::move(windowName));
sequenceState=State::noSequence; // Normal end of sequence
}
else
{
if(windowName.size() < MAX_LEN) // Ignore subsequent characters
windowName+=c;
}
break;
default:
sequenceStep=0;
sequenceState=State::noSequence;
break;
}
return true;
}
void Console::PutCharNoUpdate(char c)
{
if(isProcessingEscSequence)
{
ProcessEscSequence(c);
if(ProcessEscSequence(c))
return;
}
InvalidateCursor();
switch(c)
{
case '\033': // Begin of an ANSI escape sequence
isProcessingEscSequence=true;
sequenceStep=0;
sequenceState=State::waitingForSequenceStart;
break;
case '\r':
cursorX = 0;

View File

@ -59,8 +59,16 @@ namespace retro
AttributedChar(char cc, Attributes aa) {c=cc; attrs=aa;}
};
// inline bool operator==(const Attributes& lhs, const Attributes& rhs);
// inline bool operator!=(const Attributes& lhs, const Attributes& rhs);
enum class State
{
noSequence,
waitingForSequenceStart,
waitingForControlSequence,
waitingForM,
waitingForOSCStart,
waitingForSemicolon,
inWindowName
};
class Console
{
@ -83,17 +91,22 @@ namespace retro
short GetRows() const { return rows; }
short GetCols() const { return cols; }
virtual void setWindowName(std::string newName) {};
void Idle();
bool IsEOF() const { return eof; }
private:
State sequenceState;
std::string windowName;
GrafPtr consolePort = nullptr;
Rect bounds;
Attributes currentAttr;
std::vector<AttributedChar> chars, onscreen;
bool isProcessingEscSequence;
int sequenceStep;
short cellSizeX;
short cellSizeY;
@ -117,7 +130,7 @@ namespace retro
void DrawCell(short x, short y, bool erase = true);
void DrawCells(short x1, short x2, short y, bool erase = true);
void ScrollUp(short n = 1);
void ProcessEscSequence(char c);
bool ProcessEscSequence(char c);
void SetAttributes(Attributes aa);
void InvalidateCursor();

View File

@ -24,6 +24,8 @@
#include "ConsoleWindow.h"
#include "Events.h"
#include <unordered_map>
#include <cstring>
#include <TextUtils.h>
using namespace retro;
@ -35,7 +37,6 @@ namespace
ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title)
{
GrafPtr port;
//Retro68 Improved Console
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0);
#if !TARGET_API_MAC_CARBON
@ -63,6 +64,25 @@ ConsoleWindow::~ConsoleWindow()
DisposeWindow(win);
}
void ConsoleWindow::setWindowName(std::string newName)
{
Str255 pname;
#if TARGET_API_MAC_CARBON
// Carbon has the new, sane version.
c2pstrcpy(pname,newName.c_str());
#else
// It is also availble in various glue code libraries and
// in some versions of InterfaceLib, but it's confusing.
// Using the inplace variant, c2pstr, isn't much better than
// doing things by hand:
strncpy((char *)&pname[1],newName.c_str(),255);
pname[0] = newName.length();
#endif
SetWTitle(win, pname);
}
char ConsoleWindow::WaitNextChar()
{
EventRecord event;

View File

@ -34,6 +34,8 @@ namespace retro
public:
ConsoleWindow(Rect r, ConstStr255Param title);
~ConsoleWindow();
void setWindowName(std::string newName);
private:
WindowPtr win;