- ベストアンサー
C言語とWin32APIで全角のカタカナの文字を取得、表示する方法
- C言語とWin32APIを用いて、全角のカタカナの文字を取得し、表示する方法について教えてください。
- 具体的な手順として、ウィンドウを作成し、その中に全角のカタカナを入力し、入力した文字を描画する方法についてお聞きしたいです。
- また、カタカナ以外の文字が入力された場合はエラーメッセージを表示し、クライアント領域には何も描画しないようにしたいです。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
う~~~~む 現在、IsKKANAがFALSEを返した場合のみ flag = 0; が適用されることになっていますが 実際には if(!flag && IsDBCSLeadByte((BYTE)wp)){ に対する elseで確実にflag = 0; としないとまずい可能性があるので flag = 0; を一つ外に出してみてください。 以下はそれでも無理な場合です。 ///////////////////// それ以外の個所に問題があるとすると、これは想像以上の難問かもしれません。 原因がちょっと分かりません。 私の環境では出来るために、コンパイラの違いによって何か予想外のことがが起きているか、あるいはまだ見落としてる裏仕様がありそうな気がします。 BCC5.5.1には公式のユーザーフォーラムとかはないのでしょうか? 面倒ではあるでしょうが もし本当にどうにもならないならVisualStudioの方を検討してみてはいかがでしょうか?(Express Editionなら無償です) http://www.microsoft.com/japan/msdn/vstudio/express/ HackHackさんが使用しているC言語の規格はC99ではないようなので VC++なら全部そのまま使えるはずです。 また、VisualStudioならば色々調べたりするのも簡単な可能性がより高いと思いますし、MSDNフォーラムという場も提供されています。 http://social.msdn.microsoft.com/Forums/ja-JP/categories BCC5.5.1でなければならないならば、それに詳しい人がいる場所を探し出して質問してみてください。
その他の回答 (4)
- LongSecret
- ベストアンサー率68% (22/32)
>何度もコードを見直し、間違いがないか確認し、 >濁点、半濁点の文字を入力してみたのですが、やはり"カタカナ以外のメッセージボックス"が出現します。 これはコンパイルできているということだと思うので、IsKKANA関数は実際には上で定義されているか、前方宣言されていますよね? という前提で 私の環境だとこれでも出来てしまうので 原因はよく分かりませんが 再提示していただいたコードだと No.3の注意事項を満たしていません(フラグがありません) ので、そこで失敗している可能性はありませんか? とりあえず、No.3のとおりに変数を一つ追加しつつ判定を万全に整えて あとはこれは関係ないと思いますが、念には念のため WM_PAINT内での index = 0; を取り払ってみてください。 それでもできなかったら、 一端No.1に書いた、カタカナ一文字でない、普通に一気に表示される、という方法が正常に出来ることを確認した後 問題の発生している現在のコードをデバッグしてみて、どの行でどうなるのか、一行一行追って行って、原因と思われる行はどれかを絞り込んでください。
補足
LongSecretさんご回答頂き誠にありがとうございます。 このトピックに関して、5日間程、自分で調べたのですが、 どうしてもバグが発生している箇所がわかりません。。。 デバッグしようにも、Turbo Debugger5.5が手元に無いのもあり、 ネットで探してもありませんでした。 ご提示して頂いた通り、コードも修正し直しました。 No1のコードがうまく走るのも確認致しました。 しかし、一文字目に濁点、半濁点の文字を入力しても、 "カタカナ以外の文字が入力されました。"のメッセージボックスが出現します。 二文字目以降に濁点、半濁点の文字を入力した際は、 メッセージボックスが出現しません。 以下に訂正した、コードを提示させて頂きます。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; static char buf[BUFSIZ] = {0}; static int index = 0; static BOOL flag = 0; switch(msg){ case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 30, buf, strlen(buf)); EndPaint(hWnd, &ps); break; case WM_CHAR: if(!flag && IsDBCSLeadByte((BYTE)wp)){ index = 0; buf[index++] = (char)wp; flag = 1; } else{ buf[index++] = (char)wp; if(!IsKKANA(buf)){ buf[index = 0] = 0; MessageBox(hWnd, "カタカナ以外の文字が入力されました。", "エラー", 0); flag = 0; } } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wp, lp); } return 0; } BOOL IsKKANA(const char *p_buf) { static const WORD sci[] = { 'ヴ', 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'べ', 'ボ', 'パ', 'ピ', 'プ', 'ぺ', 'ポ' }; WORD w[10]; int i; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE3, p_buf, -1, w); if(w[0] == (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ return TRUE; } for(i = sizeof(sci) / sizeof(sci[0]);i--;){ if((WORD(p_buf[0] << 8) | p_buf[i]) == sci[i]){ return TRUE; } } return FALSE; } 本当に申し訳ございませんが、LongSecretさんしか頼る方がいません。 どうかご協力お願い致します。 再度、アドバイス宜しくお願い致します。 ご迷惑お掛けして申し訳ございません。
- LongSecret
- ベストアンサー率68% (22/32)
もうひとつ重要な情報を見つけました。 http://bbs.wankuma.com/index.cgi?mode=al2&namber=3522&KLOG=12 ということだから IsDBCSLeadByte だけでは不足ですね。 変数の型が分からなかったのでうやむやになって読み解ききれませんでしたが、おそらく miswaki7Zさんが値を保存していた理由はここにあると理解しました。 (ですよね?) というわけで、下記コード上で最短表記すると プロシージャ内に static BOOL flg=0; を増やし if(IsDBCSLeadByte((BYTE)wp) ){ から始まる部分を if( !flg && IsDBCSLeadByte((BYTE)wp) ){ /* その他 */ flg = 1; }else{ /* その他 */ flg=0; } といった風に書き加える作業も必要ではないかと思います。 これで、上のブロック内に入るのは確実に最初のバイト、ということになるのではないかと(少なくとも今回の場合は) …まだ穴があるかもしれませんが、リンク先のサイトの記述をみるとたぶんOKだと思います。 ただし、IsDBCSLeadByteはあくまで ダブルバイト文字セット用の関数なので、それ以外の文字が入ってくると無理かもしれません。
補足
LongSecretさんには、本当にお世話になり、ご丁寧にご教授頂き、誠にありがとうございます。 早速、ご提示されたコードと解説を元にプログラミングに励んでみます。 心より感謝申し上げます。
- LongSecret
- ベストアンサー率68% (22/32)
カタカナ限定、ということならば (その予定ではあまりなかったのであんまりまともなコードを書いてません。というより、文字コードが絡むと状況に依存するコードになりやすいと思うので、なるべくそういうコードを書かないようにしてきたので、そんなに詳しく知りません。ただ) それについては間違いなくGetStringTypeEx周りが絡んでいます。 濁点や半濁点の数値を確認してみてください。 私の環境では文字コードの正確な規格(バージョンとか?)は分かりませんが 後ろのバイトが濁点だと1多くて半濁点だと2多かったです。 しかし、そういう風にコーディングするのは知り尽くしてない限り(確実にそのことが保証されてるかどうか分かってないと)その都度ちゃんと文字コードを調べないといけません。 かといって、WindowsAPIだと実装が見えないので、MSDN見ても分からないような見えないバグとの格闘が出てくるかも。 対象とする文字コードを限定していただければ、そういうことに詳しい方に答えていただけるかもしれません。(重要) ここでは仮に「GetStringTypeExが、濁音と半濁音に対応できない、のならば」という前提での話をします。 また、カタカナが2バイトで、かつマルチバイトで、かつリトルエンディアンである限り安全なはず と思うコードです。 if(w[0] != (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ の行を if(!IsKKANA(c)){ に変えてください。(その場合static WORD w[10];は不要です) そしてこの関数はこのように定義しておきます。 BOOL IsKKANA(const char* c){ static const WORD sci[]={ 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド' //以下略・・・ }; WORD w[10]; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE3, c, -1, w); if(w[0] == (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)) return 1; for ( int i=sizeof(sci)/sizeof(sci[0]); i--; ) if ((WORD(c[0]<<8)|c[1])==sci[i]) return 1; return 0; } その他、必要な文字を付け足します。 もしここに全て入れてしまえばGetStringTypeExは不要です。 対処療法的ではありますが、上記前提中でさらにcに渡されるアドレスがあってさえいれば問題はないと思います。 ただ、ここまで書いておいてなんですが タイピングソフトなら、日本語入力OFF状態を確定させておいて、半角アルファベットで判定した方が制御もコーディングもかなり楽だと思います。
補足
ご回答頂き、誠に感謝申し上げます。 自分の環境で文字コードを調べてみたところ(Shift-JISです) ヴは0x8394でパは0x8370でした。 そして提示して頂いた、コードを元に自分のコードを修正してみました。 以下に記述させて頂きます。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; static char buf[BUFSIZ] = {0}; static int index = 0; switch(msg){ case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 30, buf, strlen(buf)); index = 0; EndPaint(hWnd, &ps); break; case WM_CHAR: if(IsDBCSLeadByte((BYTE)wp)){ index = 0; buf[index++] = (char)wp; } else{ buf[index++] = (char)wp; if(!IsKKANA(buf)){ buf[index = 0] = 0; MessageBox(hWnd, "カタカナ以外の文字が入力されました。", "エラー", 0); } } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wp, lp); } return 0; } BOOL IsKKANA(const char *p_buf) { static const WORD sci[] = { 'ヴ', 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', 'バ', 'ビ', 'ブ', 'べ', 'ボ', 'パ', 'ピ', 'プ', 'ぺ', 'ポ' }; WORD w[10]; int i; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE3, p_buf, -1, w); if(w[0] == (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ return TRUE; } for(i = sizeof(sci) / sizeof(sci[0]);i--;){ if((WORD(*p_buf << 8) | *(p_buf + 1)) == sci[i]){ return TRUE; } } return FALSE; } 以上です。 何度もコードを見直し、間違いがないか確認し、 濁点、半濁点の文字を入力してみたのですが、やはり"カタカナ以外のメッセージボックス"が出現します。 以上、ご確認の程、お忙しい中申し訳ございませんが、ご教授よろしくお願い致します。
- LongSecret
- ベストアンサー率68% (22/32)
確か本来の目的はタイピングソフトの機能を実現する、という感じでしたよね? おそらく「一文字」にこだわるほうが難しいと思うのですが、入力したのを全部受け取って一気に表示してはダメなのでしょうか? もしそれでOKなら static char c[100]={0}; static int Index=0; static HDC hdc; static PAINTSTRUCT ps; これらをプロシージャ先頭で用意しておいて WM_CHAR側は case WM_CHAR: c[Index++]=(char)wParam; c[Index]=0; if (Index==99) Index=0; InvalidateRect(hWnd,NULL,TRUE); return 0; これぐらいやれば確認には十分と思います。 あとは書くだけですが、それについては重要なのはTextOutやDrawText一文だけです。 case WM_PAINT: hdc=BeginPaint(hWnd,&ps); TextOut(hdc,0,30,c,strlen(c)); EndPaint(hWnd,&ps); return 0; などなど 一気に入力してOKならば、これだけで出来ると思います。 応用として バックスペース押したら戻るとかも上記 case WM_CHAR:の直後に if (VK_BACK==wParam) { if (Index) --Index; c[Index]=0; InvalidateRect(hw,0,1); return 0; } とか書き加えておけば出来ます (もちろん、ANSI前提のコードなので、その文字が一バイトでなければもうちょっとまともに判定を作らないと中途半端に消したとき変な文字が出るでしょうが) もしやはり「カタカナ一文字」でなければならないなら 前の質問でmiswaki7Zさんが回答していらっしゃるコードを少しいじればC準拠になるかと思いますが 今回の題意に沿わせると・・・ 相当削ってもWM_CHARで case WM_CHAR: if ( IsDBCSLeadByte((BYTE)wp) ) { Index=0; c[Index++]=(char)wp; } else { c[Index++]=(char)wp; WORD w[10]; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT , CT_CTYPE3 , (LPCTSTR)c , -1 , w); if(w[0] != (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ c[Index=0]=0; MessageBox(0,"カタカナ以外の文字が入力されました","",0); } } InvalidateRect(hWnd,NULL,TRUE); return 0; これくらいは必要になるんじゃないかな? …んでもこのコードだとまだ特定の状況に対処できていないため、もっとまともにやるならもうちょい増えるだろうし…
補足
再度、ご質問したのにも関わらず、ご親切、丁寧にご回答頂き、誠に感謝もうしあげます。 今回LongSecretさんのアドバイスの元、下記のコードを記述し、 無事にカタカナ1文字だけを取得し、表示するコードを作成することが出来ました。 LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { HDC hdc; PAINTSTRUCT ps; static char buf[BUFSIZ] = {0}; static int index = 0; static WORD w[10]; switch(msg){ case WM_PAINT: hdc = BeginPaint(hWnd, &ps); TextOut(hdc, 0, 30, buf, strlen(buf)); index = 0; EndPaint(hWnd, &ps); break; case WM_CHAR: if(IsDBCSLeadByte((BYTE)wp)){ index = 0; buf[index++] = (char)wp; } else{ buf[index++] = (char)wp; GetStringTypeEx(LOCALE_SYSTEM_DEFAULT, CT_CTYPE3, (LPCSTR)buf, -1, w); if(w[0] != (C3_ALPHA | C3_FULLWIDTH | C3_KATAKANA)){ buf[index = 0] = 0; MessageBox(hWnd, "カタカナ以外の文字が入力されました。", "エラー", 0); } } InvalidateRect(hWnd, NULL, TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wp, lp); } return 0; } しかし、"ド"、と入力すると、"カタカナ以外の文字が入力されました"のメッセージボックスが出現します。 以上、本当に申し訳ございませんが、再度、アドバイス宜しくお願い致します。
お礼
LongSecretさん、本当にお世話になり、誠に恐縮です。 ここまで、ご協力して頂いて、本当に心から感謝しています。 >flag = 0; >を一つ外に出してみてください。 ご提示して頂いた内容通りに、コードを改変しコンパイルしてみたのですが、やはり駄目でした。 LongSecretさんの仰る通り、別の開発環境での開発も考えてみます。 (今、勉強している"猫でもわかるWindowsプログラミング第2版"を全て読み終えてから環境を変えようと思っています。) 本当にここまでご教授頂き、誠にありがとうございます。 出来うる事なら、実際にお会いし、ありがとうございましたとお礼したいです。 何度もすいませんが、本当にありがとうございました。