mirror of
https://github.com/autc04/Retro68.git
synced 2024-11-24 23:32:06 +00:00
Merge pull request #103 from DarwinNE/master
Implement escape sequence to change window title
This commit is contained in:
commit
cf75b4d9ba
@ -9,7 +9,8 @@ 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;
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user