ncurses сходит с ума при записи широкого символа в определенные места на экране

Я пишу приложение с использованием ncurses и хочу использовать в нем символы рисования прямоугольников, в частности u/2550 и u/2551 (на данный момент). У меня есть настройка циклов, чтобы рисовать полосы с двух сторон терминала, исходя из размера экрана, который я определяю в другом месте.

По какой-то причине, когда дело доходит до рисования любых символов Юникода по горизонтали (здесь, в нижней части экрана, но это происходит в любой строке), он перейдет от печати символов в порядке к печати мусора «P». Это немного сложно объяснить, поэтому у меня есть несколько рисунков, показывающих, что происходит, когда я рисую 6 символов, а затем 7 или более символов.

С 6 символами

С 7 символами

Часть кода, отвечающая за отрисовку этих символов, как таковая, обратите внимание, что последний цикл for — это то, что рисует эти символы, и итератор должен идти дальше, чем просто 7, но он делает это здесь и где-либо еще.

void drawBorder(){ //draw the border graphics
                attron(COLOR_PAIR(3));
        for(int i = 1; i < screenSizeY - 1; i++){ //draw left side
                mvaddwstr(i, 0, L"║");
        }
        for(int i = 1; i < screenSizeY - 1; i++){ //draw right side
                mvaddwstr(i, screenSizeX - 1, L"\u2551");
        }
        for(int i = 0; i < 7; i++){ //draw bottom
                mvaddwstr(screenSizeY - 1, i, L"\u2550");
        }
                attroff(COLOR_PAIR(3));
}

Я связываюсь с пакетом ncursew и у меня правильно настроена локаль. Другие символы, нарисованные вертикальными линиями, работают нормально, но не здесь. Я использую C++, скомпилированный с помощью g++, работающий в Linux в сеансе терминала Alacritty.

Это не имеет ничего общего с функциями рисования прямоугольников или специфическими возможностями терминала, все широкие символы отлично поддерживаются терминалом и работают в других частях терминала. Это произойдет в зависимости от того, сколько из них я нарисую подряд, а также для других символов коробки.


person Ampera    schedule 20.02.2019    source источник
comment
Возможный дубликат Границы не отображаются должным образом, когда окно имеет более 8 столбцов   -  person Thomas Dickey    schedule 21.02.2019
comment
Независимо от того, моя проблема не имеет ничего общего с возможностями моего терминала, хотя, как ни странно, цвет ncurses кажется полностью нарушенным на xterm и mate-terminal, что мне еще предстоит выяснить. Это связано с тем, что широкие символы не отображаются должным образом в зависимости от определенного положения экрана. Это может быть даже ошибка в ncurses, но я недостаточно доверяю себе, чтобы отправить отчет об ошибке для чего-то, что все еще может быть ошибкой пользователя.   -  person Ampera    schedule 21.02.2019
comment
Возможно, управляющая последовательность ECMA-48 REP (повторяющийся символ) не работает с широкими символами. Значение ASCII для «P» равно 0x50, младшему биту вашего символа широкой рамки.   -  person 1201ProgramAlarm    schedule 21.02.2019
comment
Я тоже заметил этот бит, но мне кажется странным, что он отлично работает с меньшим количеством символов, но не дольше.   -  person Ampera    schedule 21.02.2019


Ответы (1)


OP прислал более полный пример, который показывает проблему:

#include <ncurses.h>
#include <string>
#include <iostream>

using namespace std;

int main(){

    initscr();
    setlocale(LC_ALL, "");
    raw();
    keypad(stdscr, TRUE);
    noecho();

    for(int i = 0; i < 10; i++){
        mvaddwstr(0, i, L"\u2550");
    }
    for(int i = 0; i < 6; i++){
        mvaddwstr(1, i, L"\u2550");
    }
    refresh();
    getch();
    endwin();

    return 0;

}

Проблема в том, что библиотека инициализируется с другой локалью, чем та, которая используется в вызовах mvaddwstr. На странице руководства говорится

Библиотека использует локаль, которую инициализировала вызывающая программа. Обычно это делается с помощью setlocale:

setlocale(LC_ALL, "");

Если локаль не инициализирована, библиотека предполагает, что символы можно печатать, как в ISO-8859-1, для работы с некоторыми устаревшими программами. Вы должны инициализировать локаль и не полагаться на конкретные детали библиотеки, если локаль не настроена.

Поскольку вызов setlocale происходит после initscr, а не перед ним, ncurses предполагает, что данные соответствуют стандарту ISO-8859-1, и возникает неожиданный сценарий. В других местах, таких как addwstr, ncurses проверяет правильность данных wchar_t, но в них используется текущая локаль. В этом случае он далек от функций, которые, как известно, должны обрабатываться таким образом (это рендеринг данных, которые уже были обработаны). Сравнение в библиотеке, которое позволяет обрабатывать это с помощью возможности repeat_char, может быть улучшено, но фактическая ошибка находится в примере программы.

person Thomas Dickey    schedule 25.02.2019
comment
Большое спасибо за это, я знал, что это должно быть что-то простое, и объяснение имеет смысл. Да, я должен был сделать лучший пример в начале, но я часто не знаю, что добавить в эти вещи, и заканчиваю тем, что добавляю фрагменты программы, в которой работает проблема, вместо того, чтобы создавать совершенно новые примеры программ, которые я следует начать делать. - person Ampera; 26.02.2019
comment
Образец программы всегда помогает, потому что его можно протестировать (чтение фрагмента этого сделать не может). - person Thomas Dickey; 26.02.2019
comment
Да, я понимаю. Я новичок в серьезном программировании, и почти все, что я делаю, для меня впервые. - person Ampera; 26.02.2019