[英]How do I make a TUI dialog box?
基本上每種編程語言都允許您制作 TUI 或 CLI。
可能最愚蠢的實現方式是使用 ANSI 轉義碼和 UNICODE 個字符。 您可以繪制一個彩色菜單並移動 cursor 以覆蓋 output 或隱藏無用的東西。
使用裸 bash 的示例:鏈接到 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
參考:
但是那個例子有很多問題和可以改進的地方(例如這段代碼不驗證密碼字符,像 CTRL+stuff 這樣的特殊字符被認為是 2+ 個字符)並且它可能比使用專門為這個任務(例如對話)。
另一個使用 curses 的例子 (C++):鏈接到 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
為了使這項工作(根據對話框)顯然你必須確保你已經安裝了 curses(Debian 的示例: sudo apt-get install libncurses5-dev libncursesw5-dev
,並在使用 g++ 編譯它時使用-lncurses
標志)。
我建議您看一下TurboVision ,它是 1990 年為 MS-DOS 發布的 TUI 框架。GitHub上有一個有趣的現代端口,它是跨平台的。 以下是您可以執行的一些操作:預覽。
否則,您可以包含windows.h
header 並使用SetConsoleTextAttribute()
為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:例子
或者簡單地使用_getch()
處理輸入 stream 以用星號屏蔽密碼:
#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:例子
我認為您無法獲得與帶有dialog
的屏幕截圖中相同的 TUI,但這是一個嘗試; 我使用動態生成的DIALOGRC
定義 colors:
#!/bin/bash
# DIALOGRC overrides:
IFS='' read -r -d '' dialogrc <<'EOF'
use_shadow = OFF
use_colors = ON
screen_color = (GREEN,BLACK,ON)
dialog_color = screen_color
border_color = screen_color
border2_color = screen_color
inputbox_color = screen_color
button_active_color = screen_color
button_inactive_color = screen_color
button_key_active_color = screen_color
button_key_inactive_color = screen_color
button_label_active_color = screen_color
button_label_inactive_color = screen_color
EOF
input_passwd=$(
3>&1 >/dev/tty \
DIALOGRC=<(printf '%s' "$dialogrc") \
dialog \
--output-fd 3 \
--no-lines \
--insecure \
--passwordbox $' Please enter the passphrase to\n protect your key' 8 60
) || exit 1
printf '\ninput_password=%q\n' "$input_passwd"
請注意dialog
的標准輸出重定向到/dev/tty
以及我如何通過不同的文件描述符捕獲結果; 3>&1 >/dev/tty
中的順序對於這樣做很重要。
我必須實現一個 TUI 數據庫接口來為權限數據庫構建工作流。 鑒於 TUI 界面看起來不如 GUI,對話框提供了非常合理的解決方案,並且可以在 1-2 小時內完成。
對於單個密碼字段,請使用如下密碼框。 它產生類似於您的屏幕截圖的 output 。
input_pw=$(dialog --strdo--insecure --passwordbox "Enter Password ..." 0 0 )
if [ "$input_pw" = "SeCrEt" ] ; then
do-something
fi
請注意,為了更好看的屏幕,您很可能希望使用“--form”選項,它可以更輕松地“裝飾”屏幕、添加說明、控制字段布局、小部件的大小等。我花了大約 1一天的工作來弄清楚,並將其集成到我的腳本中(權限數據庫的前端)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.