3

ncursesでいくつかの作業を試みると、ボックスの描画だけでなく、その他の目的でもワイド文字を使用する必要があり、タイルごとの制御が役立つ状況になりました。

ただし、次のコードを使用しようとすると、問題が発生します。

#define _XOPEN_SOURCE_EXTENDED

#include <locale.h>
#include <curses.h>
#include <stdlib.h>
#include <time.h>

#define ESC 27

int main() {
  setlocale(LC_CTYPE, "");

  initscr();
  keypad(initscr(),1);
  curs_set(9);
  nonl();

  cchar_t special;
  setcchar(&special, L"æ", 0, COLOR_PAIR(0), NULL);

  cchar_t speshul;
  setcchar(&speshul, L"朝", 0, COLOR_PAIR(0), NULL);

  int c=0;
  do {
    clear();

    mvadd_wch(3,6, &special);
    mvadd_wch(4,6,&speshul);

    refresh();

  } while ((ESC!=(c=getch())));

  endwin();
}

編集:

使用するコードを更新しましたsetcchar; 出力はがっかりします:

?

どこにあるべきかという単一の疑問符がspecialあり、どこにあるべきかは何もありspeshulません。

どちらの文字も期待どおりに表示されません。

問題はどこにあり、どうすれば修正できますか?

編集: Peteshに応じたいくつかの追加情報:

期待される結果は、文字「æ」とその下の朝の印刷です。MacOSXでTerminal.appを使用しています。Xcodeをコンパイルしています。

4

3 に答える 3

5

コードには他にも多くの「問題」があり、一部はワイド文字の問題に関連している可能性があります。


initscr();
keypad(initscr(),1);

initscr()理由もなく2回電話することは避けてください。最初の呼び出しの結果をWINDOWポインタに格納するか、組み込みのを使用しstdscrます。また、値の数値定数を避けbool、名前付き定数TRUEとを優先しますFALSE。セマンティクスはまったく異なります。

したがって、以下を使用します。

WINDOW *screen = initscr();
keypad(screen, TRUE);

また

initscr();
keypad(stdscr, TRUE);

curs_set(9);

9の有効な引数ではありませんcurs_set()。マニュアルから:「curs_setルーチンは、カーソルの状態を非表示、通常、または非常に表示に設定して、それぞれ0、1、または2に等しい可視性にします。 」


setcchar(&special, L"æ", 0, COLOR_PAIR(0), NULL);

の4番目の引数はsetcchar()ですshort color_pair属性マスク(に適用されることになっている)ではなく、カラーペア番号を想定しています。これは十分に文書化されていません、私は同意します。使用はペア0に対してのみ機能します。任意のペア、たとえばペアの場合、次を使用します。chtypeCOLOR_PAIR()4

setcchar(&special, L"æ", WA_NORMAL, 4, NULL);

また、WA_NORMALの代わりに使用し0ます。定数値に依存せず、名前付きの値を使用してください。


while ((ESC!=(c=getch())))

また、返品をテストする必要がありますERRc常に有効な文字コードが含まれているとは限りません。

while ((c=getch()) != ERR && c != ESC)

ESCまた、本当にループを壊すキャラクターとして使用したい場合は、について読む必要がありますESCDELAY。デフォルトでは、ユーザーがESCを押してから、そのキーがプログラムで使用できるようになるまでに、煩わしい1秒かかります。簡単に言うと、ESCはエスケープシーケンスの開始にも使用されるため、cursesは、ESCの後に他の制御文字が続くかどうかを確認してから、単独のキー押下であると判断する必要があります。したがって、遅延を回避することはできませんが、知覚しにくい時間、たとえば100msに短縮することはできます。これは、呪いを初期化する前に設定する必要があります!

setenv("ESCDELAY", 100, FALSE);

getch()また、ワイド文字の世界で使用する場合は注意が必要です。単純な「ESCまでのループ」の場合、これは問題ありget_wch()ませんが、実際にユーザー入力を解析する場合に置き換えてください。


最後に、ロケールをに設定する必要はありません"en_US.UTF-8"。これにより、ユーザーのロケールが上書きされます。端末が、以外の文字エンコードに設定されている場合UTF-8、または言語がそうでない場合はどうなりen_USますか?ユーザー環境で設定されているロケールを使用するようにプログラムを設定するだけです。

setlocale(LC_ALL, "");

これは、ロケールをまったく設定しないこととは大きく異なります。デフォルトでは、言語であるCは、ロケールがC7ビットASCII文字のみであると想定しているためです。そして、呪いはそれを尊重します。

于 2015-03-12T08:10:47.550 に答える
3

結局のところ、悪魔は細部にあります。

私の問題はロケールの呼び出しでした。

  setlocale(LC_CTYPE, "");

それは読むべきです:

  setlocale(LC_ALL, "en_US.UTF-8") // or similar

問題を修正する設定で、文字が正しく表示されるようになりました。

于 2012-06-10T00:34:31.053 に答える
0

次の質問をする必要があります。

  1. 期待される結果は何ですか(私のシステムで動作するため)
  2. 使用している端末は何ですか-つまり、OS(windows / etc)、アプリケーション
  3. コンパイルしているウィンドウでファイルを編集していますか
  4. 環境で正しく解釈されない場合は、コンパイル行で--encoding = UTF-8を試して、ファイルがUTF-8モードであると想定することをお勧めします。Windowsを使用している場合は、UCS-16をエンコーディングとして使用できる場合があります。
于 2012-06-10T00:14:53.533 に答える