You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

启用宽字符支持导致ncurses菜单显示异常的解决求助

问题:ncursesw宽字符模式下菜单显示截断,需同时支持宽字符输入与正常菜单显示

背景

开发带基础TUI的Ada程序,因ncursesada绑定无法使用,采用C语言接口调用ncurses。为实现法语输入功能,添加ncursesw宽字符支持:

  • 在initscr前调用setlocale(LC_ALL, "")
  • 定义NCURSES_WIDECHAR为1
  • 使用指定的编译/链接参数

目前宽字符输入功能正常,但菜单显示被截断。排查setlocale配置、参考ncurses Unicode相关文档后问题仍未解决;移除宽字符相关设置后,菜单显示恢复正常。需求是同时支持宽字符输入与正常菜单显示,未找到合适的C替代库,C++因Ada接口问题无法使用,特此求助。

编译/链接参数

  • 编译器参数:-I/usr/include/ncursesw -D_DEFAULT_SOURCE -D_XOPEN_SOURCE_EXTENDED=600
  • 链接器参数:-Wl,-Bsymbolic-functions -lncursesw -ltinfo

最小复现代码

编译命令

gcc ncurses_external.c -I/usr/include/ncursesw -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -o main -lmenu -Wl,-Bsymbolic-functions -lncursesw -ltinfo

ncurses_external.h

#include <ncurses.h>
#include <menu.h>

#define INVISIBLE 0
#define VISIBLE 1
#define ENTER_CODE 10
#define SENTENCE 0
#define FILE_STR 1

char* Choices[] = {
   "Traduire (FR->NO)",
   "Traduire (NO->FR)",
   "Quitter"
};

int InitScr_Wrp ();

void Refresh_Wrp ();

void Colored_Line (char Line[], short Color, int y);

int Menu (int y);

wint_t* Get (int type, int y);
// the wint_t errors (underlined in an IDE) are IDE's specific error. Program
// compile.

int main (int argc, char *argv[]);

void EndScr_Wrp ();

// private in regards to Ada

ITEM** Allocate_List (int N, char* choices[]);

void Free (int N, ITEM** List, MENU* menu);

ncurses_external.c

#include "ncurses_external.h"
#include <ncursesw/ncurses.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>

#define NCURSES_WIDECHAR 1

int InitScr_Wrp () {

   setlocale (LC_ALL, "");

   initscr ();

   if (has_colors () == FALSE) {
      endwin ();
      return -1;
   }

   curs_set (INVISIBLE);
   cbreak ();
   noecho ();
   start_color ();
   keypad (stdscr, TRUE);

   return 0;
}

void Refresh_Wrp () {
   refresh ();
}

void Colored_Line (char Line[], short Color, int y) {

   init_pair (y, Color, COLOR_BLACK);
   attron (COLOR_PAIR (y));
   mvwprintw (stdscr, y - 1, 0, "%s", Line);
   attroff (COLOR_PAIR (y));
}


ITEM** Allocate_List (int N, char* choices[]) {

   ITEM** List;

   List = (ITEM**)calloc (N + 1, sizeof (ITEM*));
   for (int i = 0; i < N; ++i) {
      List[i] = new_item (choices[i], "");
   }

   return List;
}

void Free (int N, ITEM** List, MENU* menu) {

   unpost_menu (menu);
   free_menu (menu);
   for (int i = 0; i < N; i++) {
      free_item (List[i]);
   }
}

int Menu (int y) {

   ITEM** Item_List;

   WINDOW* menu_win;
   MENU* Option_Menu;

   menu_win = newwin (16, 50, y, 0);
   keypad (menu_win, TRUE);

   int N = sizeof (Choices) / sizeof (Choices[0]);
   Item_List = Allocate_List (N, Choices);
   Option_Menu = new_menu (Item_List);

   set_menu_win (Option_Menu, menu_win);
   set_menu_sub (Option_Menu, menu_win);
   post_menu (Option_Menu);

   wrefresh (menu_win);

   int character;
   int Choosen_Option = 0;

   menu_driver (Option_Menu, REQ_FIRST_ITEM);
   do {

      character = wgetch (menu_win);

      switch (character) {

      case KEY_UP:
         Choosen_Option = Choosen_Option > 0 ? Choosen_Option - 1 : 0;
         menu_driver (Option_Menu, REQ_UP_ITEM);
         break;

      case KEY_DOWN:
         Choosen_Option = Choosen_Option < N ? Choosen_Option + 1 : N;
         menu_driver (Option_Menu, REQ_DOWN_ITEM);
         break;
      }

   } while (character != ENTER_CODE);

   Free (N, Item_List, Option_Menu);
   wclear (menu_win);
   wrefresh (menu_win);

   delwin (menu_win);

   return Choosen_Option;

}

wint_t* Get (int type, int y) {

   if (type == SENTENCE) {
      mvwprintw (stdscr, y, 0, "Entrer une phrase à traduire :");
   }
   else {
      mvwprintw (stdscr, y, 0, "Entrer un fichier à décoder :");
   }

   mvwprintw (stdscr, y + 1, 0, "> ");
   wrefresh (stdscr);
   curs_set (VISIBLE);
   echo ();

   wint_t* response = NULL;
   size_t N = 0;
   size_t curr_end_size = 255;
   size_t Block = 16;

   response = (wint_t*)realloc (NULL, sizeof (*response) * curr_end_size);

   if (!response) return response;

   wint_t character;
   do {

      get_wch (&character);

      response[N] = character;
      N++;

      if (N == curr_end_size) {
         curr_end_size += Block;
         response = (wint_t*)realloc (response, sizeof (*response) * curr_end_size);
         if (!response) return response;
      }

   } while (character != ENTER_CODE);

   return response;

}

void EndScr_Wrp () {
   endwin ();
}

int main (int argc, char *argv[]) {


   int y1 = 10;
   int option;

   InitScr_Wrp ();
   option = Menu (y1);

   switch (option) {

   case (SENTENCE):
      Get (SENTENCE, y1);
      break;

   case (FILE_STR):
      Get (FILE_STR, y1);
      break;

   }

   EndScr_Wrp ();
}

内容的提问来源于stack exchange,提问作者Akutchi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:32:07