将宽字符写入某些屏幕位置时,ncurses出现异常情况

时间:2019-02-20 21:11:33

标签: c++ linux unicode terminal ncurses

我正在使用ncurses编写一个应用程序,并希望在其中使用方框图字符,特别是u / 2550和u / 2551(到目前为止)。我有for循环设置,可以根据我在其他地方确定的屏幕尺寸在终端的两侧绘制条形。

无论出于何种原因,要水平绘制任何unicode字符(在屏幕底部,但可以在任何行上进行此操作),它将从精细打印字符到打印垃圾'P'。这有点难以解释,所以我有一些图片显示了当我先绘制6个字符然后绘制7个或更多字符时会发生什么情况。

With 6 characters

With 7 characters

代码中负责绘制这些字符的部分是这样的,请注意,最后一个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));
}

我正在链接ncursesw软件包,并且具有正确设置的语言环境。以竖线绘制的其他字符也可以,但此处不行。我正在使用在Alacritty终端会话中的Linux上运行的,用g ++编译的C ++。

这与盒子绘制功能或特定的终端功能无关,终端完全支持所有宽字符,并且可以在终端的其他部分中使用。这将根据我连续绘制的数量而发生,其他框字符也将发生。

1 个答案:

答案 0 :(得分:4)

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调用中使用的语言环境不同。 manual page

  

该库使用调用程序已初始化的语言环境。   通常使用 setlocale

     

setlocale(LC_ALL, "");

     

如果未初始化语言环境,则库将假定字符   可以按照 ISO-8859-1 进行打印,以与某些旧版程序配合使用。   您应该初始化语言环境,而不要依赖于   尚未设置语言环境的库。

由于调用 setlocale 是在 initscr 之后而不是之前,因此ncurses假定数据为ISO-8859-1,并且遇到意外情况。在addwstr等其他地方,ncurses会检查数据是否有效wchar_t,但在这些地方,它使用的是 current 语言环境。在这种情况下,它与它必须以这种方式处理的功能相距很远(它渲染已处理的数据)。库中的比较允许使用 repeat_char 功能进行处理,但可以进行改进,但是实际的错误在示例程序中。