Is there a way to replicate this: TUI dialog(screenshot not mine of course) on something Shell Script or something like C? This looks better than using dialog package.
Basically every programming language allows you to make TUI or CLI.
Probably, the most dumb way to implement that is to use ANSI escape codes and UNICODE characters. You can draw a colored menu and move the cursor to override the output or to hide the useless stuff.
Example using bare bash: link to GitHub Gist - password_input_tui.sh
#!/bin/bash
max_pass_length=40
pass_length=30
i=0
password=
prompt=$' \u2502 Passphrase: '
clear
echo -e "\e[32;40m\e[H"
echo -e " \u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 "
echo -e " \u2502 Please enter the passphrase to \u2502 "
echo -e " \u2502 protect your new key \u2502 "
echo -e " \u2502 \u2502 "
echo -e -n " \u2502 Passphrase: "; while [ $i -lt $pass_length ]; do echo -e -n "_"; i=$(expr $i + 1); done; while [ $i -lt $max_pass_length ]; do echo -e -n " "; i=$(expr $i + 1); done; echo -e " \u2502 "
echo -e " \u2502 \u2502 "
echo -e " \u2502 <OK> <Cancel> \u2502 "
echo -e " \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 "
echo -e "\e[5;H"
# Read password
i=0
while IFS= read -p "$prompt" -r -s -n 1 char
do
if [[ $i -eq $(expr $pass_length - 1) ]]
then
password+=$'\0'
break
fi
if [[ $char == $'\0' ]]
then
break
fi
if [[ $char == $'\177' || $char == $'\b' ]]
then
if [ $i -gt 0 ]
then
i=$(expr $i - 1)
prompt=$'\b_\b'
password="${password%?}"
else
prompt=''
fi
else
i=$(expr $i + 1)
prompt='*'
password+="$char"
fi
done
# Select <OK> or <Cancel>
choice=1
echo -e -n "\e[8;14H\e[30;42m<OK>\e[0m\e[10H"
while read -r -s -n 1 ui; do
case "$ui" in
$'\x1b') # Handle ESC sequence.
# Flush read. We account for sequences for Fx keys as
# well. 6 should suffice far more then enough.
read -r -s -n 1 -t 0.1 char
if [[ "$char" == "[" ]]; then
read -r -s -n 1 -t 0.1 char
case "$char" in
#"A") printf "Up\n";;
#"B") printf "Down\n";;
"C") # right
echo -e -n "\e[8;14H\e[32;40m<OK>\e[0m"
echo -e -n "\e[8;48H\e[30;42m<Cancel>\e[0m"
echo -e -n "\e[10H"
choice=0;;
"D") # left
echo -e -n "\e[8;14H\e[30;42m<OK>\e[0m"
echo -e -n "\e[8;48H\e[32;40m<Cancel>\e[0m"
echo -e -n "\e[10H"
choice=1;;
esac
fi
# Flush "stdin" with 0.1 sec timeout.
read -rsn5 -t 0.1
;;
$'\0')
break ;;
# Other one byte (char) cases. Here only quit.
q)
choice=1
break;;
esac
done
# Show result
if [[ choice -eq 1 ]]
then
echo "Password: $password"
else
echo "Operation canceled"
fi
exit 0
Output: bash.gif
References:
But that example has many problems and bits that could be improved (for example this code doesn't validate the password characters, and special characters like CTRL+stuff are considered as 2+ characters) and it's probably much harder than using tools made exactly for this task (e.g. dialog).
Another example (C++) using curses: Link to GitHub Gist - password_input_tui.cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curses.h>
#define MAX_PASSWD_LENGTH 32
#define M1Y 7
#define M1X 8
#define M2Y 7
#define M2X 33
void menu(int choice);
int yBottom, xBottom;
int yTop, xTop;
WINDOW* win;
int main(int argc, char** argv)
{
initscr();
noecho();
curs_set(0);
int xMax, yMax, i, choice, exit;
char password[MAX_PASSWD_LENGTH];
char ch;
getmaxyx(stdscr, yMax, xMax);
yBottom = yMax / 1.5, xBottom = xMax / 1.5;
yTop = yMax / 6, xTop = xMax / 6;
win = newwin(yBottom, xBottom, yTop, xTop);
box(win, 0, 0);
mvwprintw(win, 2, 2, "Please enter the passphrase to");
mvwprintw(win, 3, 2, "protect your new key");
mvwprintw(win, 5, 2, "Passphrase: ");
i=0;
while (i < MAX_PASSWD_LENGTH) {
ch = wgetch(win);
if (ch == ' ' || ch == 27 || ch == 127) {
continue;
}
else if (ch == '\b' || ch == 8) {
if (i > 0) {
mvwprintw(win, 5, 14 + i, "\b \b");
--i;
}
else {
continue;
}
}
else if (ch == '\n' || ch == 10 || ch == '\r' || ch == '\t') {
break;
}
else if (ch == 0 || ch == 224) {
ch = wgetch(win);
continue;
}
else {
mvwprintw(win, 5, 14 + i, "*");
password[i++] = ch;
}
}
password[i] = '\0';
wattron(win, A_STANDOUT);
mvwprintw(win, M1Y, M1X, "<OK>");
wattroff(win, A_STANDOUT);
mvwprintw(win, M2Y, M2X, "<Cancel>");
choice = 1;
exit = 0;
while(ch = wgetch(win))
{
switch(ch)
{
case '\033':
{
wgetch(win);
switch(wgetch(win))
{
case 'D':
{
choice = 1;
break;
}
case 'C':
{
choice = 2;
break;
}
}
break;
}
case '\n':
{
exit = 1;
break;
}
default:
break;
}
if(exit)
break;
menu(choice);
}
if(choice == 1)
mvwprintw(win, 10, 10, "Password: %s", password);
else
mvwprintw(win, 10, 10, "Operation canceled");
wgetch(win);
endwin();
return 0;
}
void menu(int choice)
{
switch(choice)
{
case 1:
wattron(win, A_STANDOUT);
mvwprintw(win, M1Y, M1X, "<OK>");
wattroff(win, A_STANDOUT);
mvwprintw(win, M2Y, M2X, "<Cancel>");
break;
case 2:
mvwprintw(win, M1Y, M1X, "<OK>");
wattron(win, A_STANDOUT);
mvwprintw(win, M2Y, M2X, "<Cancel>");
wattroff(win, A_STANDOUT);
break;
default:
wattron(win, A_STANDOUT);
mvwprintw(win, M1Y, M1X, "<OK>");
wattroff(win, A_STANDOUT);
mvwprintw(win, M2Y, M2X, "<Cancel>");
break;
}
}
Output: cpp.gif
To make this work (as per dialog) obviously you have to make sure you have installed curses (Example for Debian: sudo apt-get install libncurses5-dev libncursesw5-dev
, and use -lncurses
flag when you compile it with g++).
I suggest you take a look at TurboVision, which is a TUI framework released for MS-DOS in 1990. There's a interesting modern port on GitHub, which is cross platform. Here's a bit of what you can do: preview.
Otherwise you could include windows.h
header and use SetConsoleTextAttribute()
to color the output:
#include <stdio.h>
#include <windows.h>
int main(int argc, char** argv)
{
HANDLE hConsole;
int k;
hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// you can loop k higher to see more color choices
for (k = 1; k < 255; k++)
{
// pick the colorattribute k you want
SetConsoleTextAttribute(hConsole, k);
printf("%3d %s\n", k, "I want to be nice today!");
}
return 0;
}
Output: example
Or simply handle the input stream with _getch()
to mask the password with asterisks:
#include <stdio.h>
#define PASSWORD_LENGTH 32
int main(int argc, char** argv) {
int i = 0;
char password[PASSWORD_LENGTH + 1];
int ch;
printf("Enter Password (max length: %d): ", PASSWORD_LENGTH);
while (i < PASSWORD_LENGTH) {
ch = _getch();
if (ch == ' ' || ch == 27) {
continue;
}
else if (ch == '\b') {
if (i > 0) {
printf("\b \b");
--i;
}
else {
continue;
}
}
else if (ch == '\r' || ch == '\t') {
break;
}
else if (ch == 0 || ch == 224) {
ch = _getch();
continue;
}
else {
password[i++] = ch;
printf("*");
}
}
password[i] = '\0';
printf("\nPassword: %s", password);
return 0;
}
Output: example