cformsfieldncurses

Form validation using Ncurses (FORM)


Cannot implement character input validation. I have sketched out the code of a simple program for input validation. Various characters are displayed in the field.

#include <form.h>

int main() {
    initscr();
    curs_set(1);
    WINDOW *win = newwin(5, 40, 10, 10);
    keypad(win, TRUE);
    box(win, 0, 0);
    wrefresh(win);

    FIELD *fields[2];
    fields[0] = new_field(1, 20, 2, 2, 0, 0);
    fields[1] = NULL;
    set_field_type(fields[0], TYPE_REGEXP, "^[0-9]*$");
    set_field_opts(fields[0], O_VISIBLE | O_ACTIVE | O_EDIT);

    FORM *form = new_form(fields);
    set_form_win(form, win);
    set_form_sub(form, derwin(win, 3, 38, 1, 1));
    post_form(form);
    wrefresh(win);

    int ch;
    while ((ch = wgetch(win)) != KEY_F(1)) {
        int status = form_driver(form, ch);
        if (status == E_INVALID_FIELD) {
            form_driver(form, REQ_VALIDATION);
        } else if (status == E_OK) {
            wrefresh(win);
        }
    }

    unpost_form(form);
    free_form(form);
    free_field(fields[0]);
    endwin();

    return 0;
}

enter image description here

UPD 1:

    while ((ch = wgetch(win)) != KEY_F(1)) {
        int status = form_driver(form, ch);
        if( status == E_OK ) {
            status = form_driver(form, REQ_VALIDATION);
        }
        if (status == E_INVALID_FIELD) {
            frefresh(form);
        } else if (status == E_OK) {
            wrefresh(win);
        }
    }
void frefresh(FORM *form) {
    form_driver(form, REQ_DEL_PREV);
}

Moved the cleaning code to a separate function. The cursor returns to the incorrectly entered character.

enter image description here


Solution

  • It was possible to implement processing of spaces and hiding passwords behind spaces. Thus, it was possible to check data during input and hide the entered data.

    enter image description here

    enter image description here

    In the future, correction of incorrect input using other keys is necessary.

    C language:

    #include <form.h>
    #include <stdio.h>
    
    #define SIZEPASS 20
    
    int main() {
        initscr();
        raw();
        noecho();
        curs_set(2);
        WINDOW *win = newwin(5, 40, 10, 10);
        keypad(win, TRUE);
        box(win, 0, 0);
        wrefresh(win);
    
        FIELD *fields[2];
        fields[0] = new_field(1, SIZEPASS, 2, 2, 0, 0);
        fields[1] = NULL;
        set_field_type(fields[0], TYPE_REGEXP, "^\\\\*[0-9A-Za-z*]* *$");
        set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
        set_field_back(fields[0], A_UNDERLINE);
    
        FORM *form = new_form(fields);
        set_form_win(form, win);
        set_form_sub(form, derwin(win, 3, 38, 1, 1));
        post_form(form);
        wrefresh(win);
    
        char password[SIZEPASS] = {};
        int ch, status, count = 0, stop = 0;
    
        while (!stop && (ch = wgetch(win)) != KEY_F(2)) {
            switch (ch) {
                case KEY_BACKSPACE:
                    form_driver(form, REQ_DEL_PREV);
                    if (count)
                        password[--count] = '\0';
                    break;
                case 32:
                    break;
                case 10:
                case KEY_ENTER:
                    stop = 1;
                    break;
                default:
                    status = form_driver(form, ch);
                    if( status == E_OK ) {
                        status = form_driver(form, REQ_VALIDATION);
                    }
                    if (status == E_INVALID_FIELD) {
                        form_driver(form, REQ_DEL_PREV);
                    } else {
                        password[count++] = (char)ch;
                        password[count] = '\0';
                        form_driver(form, REQ_DEL_PREV);
                        form_driver(form, '*');
                    }
            }
        }
    
        unpost_form(form);
        free_form(form);
        free_field(fields[0]);
        endwin();
    
        printf("Password: %s\n", password);
    
        return 0;
    }
    

    D language:

    module source.app;
    
    import std.conv;
    import std.string;
    import std.stdio;
    
    public import deimos.ncurses;
    public import deimos.form;
    public import core.stdc.locale;
    
    int main(string[] args) {
        setlocale(LC_CTYPE,"");
        initscr();
        raw();
        noecho();
        curs_set(2);
        WINDOW *win = newwin(5, 40, 10, 10);
        keypad(win, TRUE);
        box(win, 0, 0);
        wrefresh(win);
    
        FIELD*[2] fields;
        fields[0] = new_field(1, 20, 2, 2, 0, 0);
        fields[1] = null;
        set_field_type(fields[0], TYPE_REGEXP, `^\**[0-9A-Za-z*]* *$`.ptr);
        set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
        set_field_back(fields[0], A_UNDERLINE);
    
        FORM *form = new_form(cast(FIELD**)fields);
        set_form_win(form, win);
        set_form_sub(form, derwin(win, 3, 38, 1, 1));
        post_form(form);
        wrefresh(win);
    
        string password;
        bool stop = false;
        int ch, status;
    
        while (!stop && (ch = wgetch(win)) != KEY_F(2)) {
            switch (ch) {
                case KEY_BACKSPACE:
                    form_driver(form, REQ_DEL_PREV);
                    if (password.length)
                        password = password[0 .. $ - 1];
                    break;
                case 32:
                    break;
                case 10:
                case KEY_ENTER:
                    stop = true;
                    break;
                default:
                    status = form_driver(form, ch);
                    if( status == E_OK ) {
                        status = form_driver(form, REQ_VALIDATION);
                    }
                    if (status == E_INVALID_FIELD) {
                        form_driver(form, REQ_DEL_PREV);
                    } else {
                        password ~= ch.to!char;
                        form_driver(form, REQ_DEL_PREV);
                        form_driver(form, '*'.to!int);
                    }
                    break;
            }
        }
    
        unpost_form(form);
        free_form(form);
        free_field(fields[0]);
        endwin();
    
        writeln("Password: " ~ password);
    
        return 0;
    }
    

    Implementation of wide characters in C (maybe it will be useful for someone searching).

    D language (wide char, unicode):

    module source.app;
    
    import std.conv;
    import std.string;
    
    import std.stdio;
    
    public import deimos.ncurses;
    public import deimos.form;
    public import core.stdc.locale;
    
    int main(string[] args) {
        setlocale(LC_ALL,"");
        initscr();
        raw();
        noecho();
        curs_set(2);
        WINDOW *win = newwin(5, 40, 10, 10);
        keypad(win, TRUE);
        box(win, 0, 0);
        wrefresh(win);
    
        FIELD*[2] fields;
        fields[0] = new_field(1, 20, 2, 2, 0, 0);
        fields[1] = null;
        set_field_type(fields[0], TYPE_REGEXP, `^\**[0-9A-Za-zА-Яа-я*]* *$`.ptr);
        set_field_opts(fields[0], O_VISIBLE | O_PUBLIC | O_EDIT | O_ACTIVE);
        set_field_back(fields[0], A_UNDERLINE);
    
        FORM *form = new_form(cast(FIELD**)fields);
        set_form_win(form, win);
        set_form_sub(form, derwin(win, 3, 38, 1, 1));
        post_form(form);
        wrefresh(win);
    
        dstring password;
        bool stop = false;
    
        int status;
    
        dchar ch;
        int ret;
    
        while (!stop) {
            ret = wget_wch(win, &ch);
            switch (ret) {
                case KEY_CODE_YES:
                    break;
                case OK:
                    switch (ch) {
                        case KEY_BACKSPACE:
                            form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                            if (password.length)
                                password = password[0 .. $ - 1];
                            break;
                        case 32:
                            break;
                        case 10:
                        case KEY_ENTER:
                            stop = true;
                            break;
                        default:
                            status = form_driver_w(form, OK, ch);
                            if( status == OK ) {
                                status = form_driver_w(form, KEY_CODE_YES, REQ_VALIDATION);
                                if (status == OK) {
                                    password ~= ch.to!dchar;
                                    form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                                    form_driver_w(form, OK, '*'.to!int);
                                } else {
                                    status = form_driver_w(form, KEY_CODE_YES, REQ_DEL_PREV);
                                }
                            }
                    }
                    break;
                default:
                    break;
            }
        }
    
        unpost_form(form);
        free_form(form);
        free_field(fields[0]);
        endwin();
    
        writefln("Password: %s\n", password);
    
        return 0;
    }