DOBON.NET DOBON.NETプログラミング掲示板過去ログ

ime制御したときにテキストボックスに文字が出ない

環境/言語:[windows7 C#2010Express]
分類:[.NET]

お世話になります。

以下のコードを下記URLを参考に作成しましたが、

http://yonaizumi.dip.jp/weblog/cappe/2010/06/cime.html

子フォームのテキストボックスに文字を入力しても表示されません。
ただ、親フォームでは入力した文字が取得できます。

子フォームのソースは以下の通りです。
ご指導をお願いいたします。

namespace Project2
{
public partial class Form1 : Form
{
frmtest f0;
public Form1(frmtest f)
{
f0 = f;
InitializeComponent();
}

[DllImport("Imm32.dll", EntryPoint = "ImmGetContext")]
private extern static IntPtr APIImmGetContext(IntPtr hWnd);

[DllImport("Imm32.dll", EntryPoint = "ImmNotifyIME")]
private extern static bool APIImmNotifyIME(IntPtr hIMC, NI dwAction, CPS dwIndex, uint dwValue);

[DllImport("Imm32.dll", EntryPoint = "ImmReleaseContext")]
private extern static bool APIImmReleaseContext(IntPtr hWnd, IntPtr hIMC);

private enum NI : uint
{
OPENCANDIDATE = 0x0010,
CLOSECANDIDATE = 0x0011,
SELECTCANDIDATESTR = 0x0012,
CHANGECANDIDATELIST = 0x0013,
FINALIZECONVERSIONRESULT = 0x0014,
COMPOSITIONSTR = 0x0015,
SETCANDIDATE_PAGESTART = 0x0016,
SETCANDIDATE_PAGESIZE = 0x0017,
IMEMENUSELECTED = 0x0018,
}

private enum CPS : uint
{
COMPLETE = 0x0001,
CONVERT = 0x0002,
REVERT = 0x0003,
CANCEL = 0x0004,
}

// ボタンを押下するとフォームを閉じる
// 親フォームは xxClass.textBox1.Text からそのテキストボックスの値を取得する
private void textBox1_Click(object sender, EventArgs e)
{
this.textBox1.Focus();
IntPtr hIMC = APIImmGetContext(this.Handle);
bool INI = APIImmNotifyIME(hIMC, NI.COMPOSITIONSTR, CPS.COMPLETE, 0);
bool IRC = APIImmReleaseContext(this.Handle, hIMC);
Application.DoEvents();
f0.txtSomeOne.Text = this.textBox1.Text;
this.Close();
}

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{

case Keys.F3:
this.button1.Focus();
this.button1.PerformClick();
break;
}
}


}
}
2011/10/05(Wed) 18:58:39 編集(投稿者)

■No29154に返信(sueくんさんの記事)
> お世話になります。
>
> 以下のコードを下記URLを参考に作成しましたが、
>
> http://yonaizumi.dip.jp/weblog/cappe/2010/06/cime.html
>
> 子フォームのテキストボックスに文字を入力しても表示されません。
> ただ、親フォームでは入力した文字が取得できます。
>
> 子フォームのソースは以下の通りです。
> ご指導をお願いいたします。


テキストボックスに文字を入力しても表示されないと書かれていますが、

1.IME表示中で候補確定前にボタンクリックしても候補確定するはずの文字がtextboxに表示されない

2.一切の文字入力が表示されない。なんの制御もできない。

1.2どちらでしょうか?


それと

// ボタンを押下するとフォームを閉じる
// 親フォームは xxClass.textBox1.Text からそのテキストボックスの値を取得する
private void textBox1_Click(object sender, EventArgs e)

と書かれていますがtextBoxClick、buttonClickどちらなんですか?
itiさんお世話になります。
ご連絡ありがとうございます。

■No29159に返信(itiさんの記事)
> 2011/10/05(Wed) 18:58:39 編集(投稿者)
>
> ■No29154に返信(sueくんさんの記事)
>>お世話になります。
>>
>>以下のコードを下記URLを参考に作成しましたが、
>>
>>http://yonaizumi.dip.jp/weblog/cappe/2010/06/cime.html
>>
>>子フォームのテキストボックスに文字を入力しても表示されません。
>>ただ、親フォームでは入力した文字が取得できます。
>>
>>子フォームのソースは以下の通りです。
>>ご指導をお願いいたします。
>
>
> テキストボックスに文字を入力しても表示されないと書かれていますが、
>
> 1.IME表示中で候補確定前にボタンクリックしても候補確定するはずの文字がtextboxに表示されない
>
> 2.一切の文字入力が表示されない。なんの制御もできない。
>
> 1.2どちらでしょうか?
>

--> 2.一切の文字入力が表示されない。なんの制御もできない。

>
> それと
>
> // ボタンを押下するとフォームを閉じる
> // 親フォームは xxClass.textBox1.Text からそのテキストボックスの値を取得する
> private void textBox1_Click(object sender, EventArgs e)
>
> と書かれていますがtextBoxClick、buttonClickどちらなんですか?

  ->buttonClick

よろしくお願いいたします。
itiさん
お世話になります。
ご連絡ありがとうございます。

一部誤りがありましたので訂正いたします。

■No29159に返信(itiさんの記事)
> 2011/10/05(Wed) 18:58:39 編集(投稿者)
>
> ■No29154に返信(sueくんさんの記事)
>>お世話になります。
>>
>>以下のコードを下記URLを参考に作成しましたが、
>>
>>http://yonaizumi.dip.jp/weblog/cappe/2010/06/cime.html
>>
>>子フォームのテキストボックスに文字を入力しても表示されません。
>>ただ、親フォームでは入力した文字が取得できます。
>>
>>子フォームのソースは以下の通りです。
>>ご指導をお願いいたします。
>
>
> テキストボックスに文字を入力しても表示されないと書かれていますが、
>
> 1.IME表示中で候補確定前にボタンクリックしても候補確定するはずの文字がtextboxに表示されない
>
> 2.一切の文字入力が表示されない。なんの制御もできない。
>
> 1.2どちらでしょうか?
>
  -> 1.英数字は表示されますが、日本語が表示されません。

>
> それと
>
> // ボタンを押下するとフォームを閉じる
> // 親フォームは xxClass.textBox1.Text からそのテキストボックスの値を取得する
> private void textBox1_Click(object sender, EventArgs e)
>
> と書かれていますがtextBoxClick、buttonClickどちらなんですか?

  ->buttonClick

よろしくお願いいたします。
■No29163に返信(sueくんさんの記事)

>   -> 1.英数字は表示されますが、日本語が表示されません。

>   ->buttonClick
>
> よろしくお願いいたします。

やはり1でしたか...。こちらでもその挙動は確認できました。
何故か最初の一回目のボタンクリックでは候補確定が行われないんです。
textbox_clickのthis.closeをコメントアウトし、何度か


入力 → スペース(候補表示) → 候補確定せずボタンクリック


を繰り返してみてください。多分2〜3回目で意図した動きになると思います。
また、フォームロードの際にbuttonにフォーカスを当てておくと何故か成功しました。
これらの原因は今のところわかりません。


解決策は何個か考えられます。

1.この実装そのものを見直す。(空文字ならフォームを閉じさせないとかに変更するなど)
2.不具合覚悟でこのままいく。
3.System.Windows.Forms.NativeWindowを派生させて実装。WM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOWあたりを補足し対処。(かなり面倒くさそうです。)
4.Buttonを継承した新たなButtonコントロールを作りコンストラクタに
this.SetStyle(ControlStyles.Selectable, false);を記述し実装。これを使う(こちらでは常に成功しました。)

ボタンフォーカスに対する制約がないなら簡単な4を私はお勧めします。
2011/10/07(Fri) 21:31:41 編集(投稿者)

追加補足です。

3.System.Windows.Forms.NativeWindowを派生させて実装。WM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOWあたりを補足し対処。(かなり面倒くさそうです。)


と書きましたがWM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOWではなく、textboxのWM_KILLFOCUSをキャッチしてIME強制確定するとうまくいきました。

不思議なことに
textbox入力 → 候補表示 → 確定前にボタンクリック

ではIME表示が消えているのにも関わらずWM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOW、WM_IME_ENDCOMPOSITIONどれも捉えられません。その上textboxは空となります。
(まぁこれ以上深く掘り下げて調べようとは現時点では思いませんが。)

というわけでbuttonにフォーカスが必要で常に意図したとおりに動かしたい場合は

・ System.Windows.Forms.NativeWindowを派生させて実装。WM_KILLFOCUSをキャッチしてIME強制確定。

でやってみてください。

(訂正:今回の問題を解決するだけならNativeWindowでやる必要はありません。派生textbox内でWndprocオーバーライドしWM_KILLFOCUSをキャッチしてIME強制確定で問題ありません。こちらのほうが簡単です。)
itiさん

詳しく調べていただきありがとうございます。
どの方法にするか検討し、対応したいと思います。
ありがとうございました。
this closeをコメントアウトしてボタンクリックすると
表示されたのは、確認できました。


■No29170に返信(itiさんの記事)
> 追加補足です。
>
> 3.System.Windows.Forms.NativeWindowを派生させて実装。WM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOWあたりを補足し対処。(かなり面倒くさそうです。)
>
>
> と書きましたがWM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOWではなく、textboxのWM_KILLFOCUSをキャッチしてIME強制確定するとうまくいきました。
>
> 不思議なことに
> textbox入力 → 候補表示 → 確定前にボタンクリック
>
> ではIME表示が消えているのにも関わらずWM_IME_NOTIFY、IMN_CLOSECANDIDATE、IMN_CLOSESTATUSWINDOW、WM_IME_ENDCOMPOSITIONどれも捉えられません。その上textboxは空となります。
> (まぁこれ以上深く掘り下げて調べようとは現時点では思いませんが。)
>
> というわけでbuttonにフォーカスが必要で常に意図したとおりに動かしたい場合は
>
> ・ System.Windows.Forms.NativeWindowを派生させて実装。WM_KILLFOCUSをキャッチしてIME強制確定。
>
> でやってみてください。
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板