Skip to content

Commit

Permalink
Add native::console::echo method
Browse files Browse the repository at this point in the history
  • Loading branch information
gammasoft71 committed Oct 6, 2023
1 parent 8e7caa7 commit 5dc2d16
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 72 deletions.
103 changes: 68 additions & 35 deletions src/xtd.core.native.macos/src/xtd/native/macos/console.mm
Original file line number Diff line number Diff line change
Expand Up @@ -41,69 +41,64 @@ static void signal_handler(int_least32_t signal) {
}

// The SIGINT signal catcher conflicts with with xtd::environment::cancel_interrupt signal...
inline static std::map<int_least32_t, int_least32_t> signal_keys_ {{SIGQUIT, CONSOLE_SPECIAL_KEY_CTRL_BS}, {SIGTSTP, CONSOLE_SPECIAL_KEY_CTRL_Z}/*, {SIGINT, CONSOLE_SPECIAL_KEY_CTRL_C}*/};
inline static std::map<int_least32_t, int_least32_t> signal_keys_ {{SIGQUIT, CONSOLE_SPECIAL_KEY_CTRL_BS}, {SIGTSTP, CONSOLE_SPECIAL_KEY_CTRL_Z}/*, {SIGINT, CONSOLE_SPECIAL_KEY_CTRL_C}*/};
static console_intercept_signals console_intercept_signals_;
};

console_intercept_signals console_intercept_signals::console_intercept_signals_;

class terminal final {
private:
terminal() {
auto termioAttributes = termios {};
tcgetattr(0, &termioAttributes);
backupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &termioAttributes);
}
~terminal() {
tcsetattr(0, TCSANOW, &backupedTermioAttributes);
if (is_ansi_supported())
std::cout << "\x1b]0;\x7" << std::flush;
public:
bool echo(bool on) {
auto status = termios {};
tcgetattr(0, &status);
if (on) status.c_lflag |= ECHO;
else status.c_lflag &= ~ECHO;
return tcsetattr(0, TCSANOW, &status) == 0;
}

public:
bool icanon(bool on) {
auto status = termios {};
tcgetattr(0, &status);
if (on) status.c_lflag |= ICANON;
else status.c_lflag &= ~ICANON;
status.c_cc[VMIN] = on ? 1 : 0;
status.c_cc[VTIME] = 0; // Can be discarded.
return tcsetattr(0, TCSANOW, &status) == 0;
}

int_least32_t getch() {
if (peek_character != -1) {
auto character = peek_character;
peek_character = -1;
return character;
}

auto termioAttributes = termios {};
tcgetattr(0, &termioAttributes);
auto localeBackupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~(ICANON | ECHO);
termioAttributes.c_cc[VTIME] = 0;
termioAttributes.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &termioAttributes);

push_status();
echo(false);
icanon(false);

auto character = '\0';
while (read(0, &character, 1) != 1);

tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);


pop_status();
return character;
}

bool key_available() {
if (peek_character != -1)
return true;

auto termioAttributes = termios {};
tcgetattr(0, &termioAttributes);
auto localeBackupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~(ICANON | ECHO);
termioAttributes.c_cc[VTIME] = 0;
termioAttributes.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &termioAttributes);
push_status();
echo(false);
icanon(false);

if (read(0, &peek_character, 1) == -1) {
tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);
pop_status();
return false;
}

tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);
pop_status();
return peek_character != -1;
}

Expand All @@ -115,8 +110,42 @@ static bool is_ansi_supported() {
static terminal terminal_;

private:
terminal() {
push_status();
echo(false);
icanon(true);
}
~terminal() {
pop_status();
reset_colors_and_attributes();
}

void reset_colors_and_attributes() {
if (is_ansi_supported()) std::cout << "\x1b]0;\x7" << std::flush;
}

termios push_status() {
auto status = termios {};
tcgetattr(0, &status);
statuses.push_back(status);
return status;
}

termios pop_status() {
if (statuses.size() == 0) {
auto status = termios {};
tcgetattr(0, &status);
return status;
}
auto status = statuses.back();
statuses.pop_back();
tcsetattr(0, TCSANOW, &status);
return status;
}


int_least8_t peek_character {-1};
termios backupedTermioAttributes;
std::vector<termios> statuses;
};

terminal terminal::terminal_;
Expand Down Expand Up @@ -728,6 +757,10 @@ static OSStatus au_renderer_proc(void* in_ref_con, AudioUnitRenderActionFlags* i
return ::foreground_color;
}

bool console::echo(bool on) {
return terminal::terminal_.echo(on);
}

bool console::foreground_color(int_least32_t color) {
static auto colors = std::map<int_least32_t, const char*> {{CONSOLE_COLOR_DEFAULT, "\x1b[39m"}, {CONSOLE_COLOR_BLACK, "\x1b[30m"}, {CONSOLE_COLOR_DARK_BLUE, "\x1b[34m"}, {CONSOLE_COLOR_DARK_GREEN, "\x1b[32m"}, {CONSOLE_COLOR_DARK_CYAN, "\x1b[36m"}, {CONSOLE_COLOR_DARK_RED, "\x1b[31m"}, {CONSOLE_COLOR_DARK_MAGENTA, "\x1b[35m"}, {CONSOLE_COLOR_DARK_YELLOW, "\x1b[33m"}, {CONSOLE_COLOR_GRAY, "\x1b[37m"}, {CONSOLE_COLOR_DARK_GRAY, "\x1b[90m"}, {CONSOLE_COLOR_BLUE, "\x1b[94m"}, {CONSOLE_COLOR_GREEN, "\x1b[92m"}, {CONSOLE_COLOR_CYAN, "\x1b[96m"}, {CONSOLE_COLOR_RED, "\x1b[91m"}, {CONSOLE_COLOR_MAGENTA, "\x1b[95m"}, {CONSOLE_COLOR_YELLOW, "\x1b[93m"}, {CONSOLE_COLOR_WHITE, "\x1b[97m"}};
auto it = colors.find(color);
Expand Down
105 changes: 69 additions & 36 deletions src/xtd.core.native.unix/src/xtd/native/unix/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,82 +43,111 @@ namespace {
}

// The SIGINT signal catcher conflicts with with xtd::environment::cancel_interrupt signal...
inline static std::map<int_least32_t, int_least32_t> signal_keys_ {{SIGQUIT, CONSOLE_SPECIAL_KEY_CTRL_BS}, {SIGTSTP, CONSOLE_SPECIAL_KEY_CTRL_Z}/*, {SIGINT, CONSOLE_SPECIAL_KEY_CTRL_C}*/};
inline static std::map<int_least32_t, int_least32_t> signal_keys_ {{SIGQUIT, CONSOLE_SPECIAL_KEY_CTRL_BS}, {SIGTSTP, CONSOLE_SPECIAL_KEY_CTRL_Z}/*, {SIGINT, CONSOLE_SPECIAL_KEY_CTRL_C}*/};
static console_intercept_signals console_intercept_signals_;
};

console_intercept_signals console_intercept_signals::console_intercept_signals_;

class terminal final {
private:
terminal() {
termios termioAttributes;
tcgetattr(0, &termioAttributes);
backupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~ECHO;
tcsetattr(0, TCSANOW, &termioAttributes);
public:
bool echo(bool on) {
auto status = termios {};
tcgetattr(0, &status);
if (on) status.c_lflag |= ECHO;
else status.c_lflag &= ~ECHO;
return tcsetattr(0, TCSANOW, &status) == 0;
}
~terminal() {
tcsetattr(0, TCSANOW, &backupedTermioAttributes);
if (is_ansi_supported())
std::cout << "\x1b]0;\x7" << std::flush;

bool icanon(bool on) {
auto status = termios {};
tcgetattr(0, &status);
if (on) status.c_lflag |= ICANON;
else status.c_lflag &= ~ICANON;
status.c_cc[VMIN] = on ? 1 : 0;
status.c_cc[VTIME] = 0; // Can be discarded.
return tcsetattr(0, TCSANOW, &status) == 0;
}

public:
int_least32_t getch() {
if (peek_character != -1) {
int_least8_t character = peek_character;
auto character = peek_character;
peek_character = -1;
return character;
}

termios termioAttributes;
tcgetattr(0, &termioAttributes);
termios localeBackupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~(ICANON | ECHO);
termioAttributes.c_cc[VTIME] = 0;
termioAttributes.c_cc[VMIN] = 1;
tcsetattr(0, TCSANOW, &termioAttributes);
push_status();
echo(false);
icanon(false);

int_least8_t character = 0;
auto character = '\0';
while (read(0, &character, 1) != 1);

tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);

pop_status();
return character;
}

bool key_available() {
if (peek_character != -1)
return true;

termios termioAttributes;
tcgetattr(0, &termioAttributes);
termios localeBackupedTermioAttributes = termioAttributes;
termioAttributes.c_lflag &= ~(ICANON | ECHO);
termioAttributes.c_cc[VTIME] = 0;
termioAttributes.c_cc[VMIN] = 0;
tcsetattr(0, TCSANOW, &termioAttributes);

push_status();
echo(false);
icanon(false);

if (read(0, &peek_character, 1) == -1) {
tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);
pop_status();
return false;
}

tcsetattr(0, TCSANOW, &localeBackupedTermioAttributes);
pop_status();
return peek_character != -1;
}

static bool is_ansi_supported() {
static std::string terminal = getenv("TERM") == nullptr ? "" : getenv("TERM");
static auto terminal = std::string {getenv("TERM") == nullptr ? "" : getenv("TERM")};
return isatty(fileno(stdout)) && (terminal == "xterm" || terminal == "xterm-color" || terminal == "xterm-256color" || terminal == "screen" || terminal == "screen-256color" || terminal == "linux" || terminal == "cygwin");
}

static terminal terminal_;

private:
terminal() {
push_status();
echo(false);
icanon(true);
}
~terminal() {
pop_status();
reset_colors_and_attributes();
}

void reset_colors_and_attributes() {
if (is_ansi_supported()) std::cout << "\x1b]0;\x7" << std::flush;
}

termios push_status() {
auto status = termios {};
tcgetattr(0, &status);
statuses.push_back(status);
return status;
}

termios pop_status() {
if (statuses.size() == 0) {
auto status = termios {};
tcgetattr(0, &status);
return status;
}
auto status = statuses.back();
statuses.pop_back();
tcsetattr(0, TCSANOW, &status);
return status;
}


int_least8_t peek_character {-1};
termios backupedTermioAttributes;
std::vector<termios> statuses;
};

terminal terminal::terminal_;
Expand Down Expand Up @@ -675,6 +704,10 @@ bool console::cursor_visible(bool visible) {
return true;
}

bool console::echo(bool on) {
return terminal::terminal_.echo(on);
}

int_least32_t console::foreground_color() {
return ::foreground_color;
}
Expand Down
11 changes: 11 additions & 0 deletions src/xtd.core.native.win32/src/xtd/native/win32/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,17 @@ bool console::cursor_visible(bool visible) {
return SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci) == TRUE;
}

bool console::echo(bool on) {
/*
DWORD mode = 0;
GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &mode);
if (on) mode |= ENABLE_ECHO_INPUT;
else mode &= ~ENABLE_ECHO_INPUT;
return SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), mode) == TRUE;
*/
return true;
}

int_least32_t console::foreground_color() {
return ::foreground_color;
}
Expand Down
3 changes: 3 additions & 0 deletions src/xtd.core.native/include/xtd/native/console.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ namespace xtd {
/// @param visible true if the cursor is visible; otherwise, false.
/// @warning Internal use only
static bool cursor_visible(bool visible);

static bool echo(bool on);

/// @brief Gets the foreground color of the console.
/// @return the foreground console color.
/// @warning Internal use only
Expand Down
5 changes: 4 additions & 1 deletion src/xtd.core/src/xtd/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,10 @@ int32 console::read() {
ustring console::read_line() {
register_cancel_key_press(); // Must be first...
out.flush();
return stream_reader {in}.read_line();
if (!is_input_redirected()) native::console::echo(true);
auto result = stream_reader {in}.read_line();
if (!is_input_redirected()) native::console::echo(false);
return result;
}

console_key_info console::read_key() {
Expand Down

0 comments on commit 5dc2d16

Please sign in to comment.