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() int main()
{ {
retro::InitConsole(); 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()); retro::Console::currentInstance->write(out.data(), out.size());
std::string in; std::string in;
do do
{ {

View File

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

View File

@ -30,6 +30,9 @@
using namespace retro; using namespace retro;
const char BEL = 7;
const char MAX_LEN = 250;
Console *Console::currentInstance = NULL; Console *Console::currentInstance = NULL;
Attributes::Attributes(void) Attributes::Attributes(void)
@ -162,7 +165,7 @@ void Console::Init(GrafPtr port, Rect r)
onscreen = chars; onscreen = chars;
cursorX = cursorY = 0; cursorX = cursorY = 0;
isProcessingEscSequence=false; sequenceState=State::noSequence;
} }
void Console::SetAttributes(Attributes aa) void Console::SetAttributes(Attributes aa)
@ -265,18 +268,22 @@ void Console::ScrollUp(short n)
dirtyRect.bottom = dirtyRect.bottom > 0 ? dirtyRect.bottom - 1 : 0; 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=='[') if(c=='[')
++sequenceStep; sequenceState=State::waitingForControlSequence;
else if(c==']')
sequenceState=State::waitingForOSCStart;
else else
isProcessingEscSequence=false; sequenceState=State::noSequence; // Unrecognized sequence
break; break;
case 1: case State::waitingForControlSequence:
++sequenceStep; sequenceState=State::waitingForM;
switch(c) switch(c)
{ {
case '0': // Normal character case '0': // Normal character
@ -292,35 +299,59 @@ void Console::ProcessEscSequence(char c)
currentAttr.setUnderline(true); currentAttr.setUnderline(true);
break; break;
default: default:
isProcessingEscSequence=false; sequenceState=State::noSequence; // Unrecognized sequence
} }
break; break;
case 2: case State::waitingForM:
if(c=='m') if(c=='m')
isProcessingEscSequence=false; sequenceState=State::noSequence; // Normal end of sequence
else if(c==';')
sequenceStep=1;
else 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; break;
default: default:
sequenceStep=0; sequenceState=State::noSequence;
break;
} }
return true;
} }
void Console::PutCharNoUpdate(char c) void Console::PutCharNoUpdate(char c)
{ {
if(isProcessingEscSequence) if(ProcessEscSequence(c))
{
ProcessEscSequence(c);
return; return;
}
InvalidateCursor(); InvalidateCursor();
switch(c) switch(c)
{ {
case '\033': // Begin of an ANSI escape sequence case '\033': // Begin of an ANSI escape sequence
isProcessingEscSequence=true; sequenceState=State::waitingForSequenceStart;
sequenceStep=0;
break; break;
case '\r': case '\r':
cursorX = 0; cursorX = 0;

View File

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

View File

@ -24,6 +24,8 @@
#include "ConsoleWindow.h" #include "ConsoleWindow.h"
#include "Events.h" #include "Events.h"
#include <unordered_map> #include <unordered_map>
#include <cstring>
#include <TextUtils.h>
using namespace retro; using namespace retro;
@ -35,7 +37,6 @@ namespace
ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title) ConsoleWindow::ConsoleWindow(Rect r, ConstStr255Param title)
{ {
GrafPtr port; GrafPtr port;
//Retro68 Improved Console
win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0); win = NewWindow(NULL, &r, "\pRetro68 Console", true, 0, (WindowPtr)-1, true, 0);
#if !TARGET_API_MAC_CARBON #if !TARGET_API_MAC_CARBON
@ -63,6 +64,25 @@ ConsoleWindow::~ConsoleWindow()
DisposeWindow(win); 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() char ConsoleWindow::WaitNextChar()
{ {
EventRecord event; EventRecord event;

View File

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