簡體   English   中英

如何制作 TUI 對話框?

[英]How do I make a TUI dialog box?

有沒有辦法復制這個:Shell 腳本或類似 C 的TUI 對話框(當然不是我的屏幕截圖)? 這看起來比使用 對話框package 更好。

基本上每種編程語言都允許您制作 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標志)。

一些C代碼為Windows

我建議您看一下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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM