IMEでの未確定文字をボタンにより確定するには – プログラミング – Home

IMEでの未確定文字をボタンにより確定...
 
通知
すべてクリア

[解決済] IMEでの未確定文字をボタンにより確定するには


ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

ミミと申します。よろしくお願いします。

ダイアログに、エディットボックスと「確定」ボタンを設け、
IME2000で日本語を入力し、変換する前の未確定文字列を
「確定」ボタンにより確定させたいと思っています。
(Enterキーを押せば早い話なのですが、「確定」ボタンも同じ処理をさせたいのです)

「確定」ボタンを押下した時、ダイアログに対して、
PostMessage(m_hWnd,WM_IME_KEYDOWN, (WPARAM)VK_RETURN, 0);
をやってみましたが「確定」ボタンを押した瞬間にエディットボックスから未確定文字列が
失われてしまいます。

メモ帳を開いて日本語を入力(未確定状態)し、同時にIME2000の「IMEパット」を開き、
IMEパットに表示される[Enter]で、メモ帳の日本語が確定される事と同じ事をしたいのです
が、
アドバイスを頂戴できないでしょうか?

環境は、VC6とMFCを使っています。


引用未解決
トピックタグ
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

ボタンを押してしまうとフォーカスがボタンに移ってしまうと
思います。この場合、入力途中の文字は一旦消えてしまうと
思います。入力していたエディットボックスにフォーカスを戻して
keybd_eventを使ってみてはどうでしょうか?
検証はしていないので御自分で確認してみてください。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

エディットボックスにフックを引っ掛けて、IME 関係のメッセージをごにょごにょ…で
できそうな気もします。試してませんが。


返信引用
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

PATIOさん、シャノンさん、情報ありがとうございます。

とりあえずこれで私が実現したい事はできました。

OnButton1()
{
 m_edcEdit1.SetFocus(); // ※1
 ::keybd_event(VK_RETURN, 0,0,0); // ※2
// ※3
}

※2で文字が確定される為、※3の位置に
UpdateData(TRUE);
MessageBox(m_edEdit1, 入力された内容, MB_OK);
と入れました。
ですが、一瞬メッセージボックスが表示されるだけで
※2までの処理が無効になってしまいます。

※2までの2行だけなら上手くいくという事より、
やはり、一度Windowsのメッセージループに制御を戻さなければならないのでしょうか?

>エディットボックスにフックを引っ掛けて
すみません、「フック」って何ですか?
私にはわかりませんでした。


返信引用
aetos
(@aetos)
Noble Member
結合: 5年前
投稿: 1480
 

ウィンドウ(エディットボックスもウィンドウの一種です)は、メッセージというもの
を受け取ることで様々な処理を行います。
このメッセージを処理するルーチンを「ウィンドウ・プロシージャ」と言います。
フックとは(この場合は)「メッセージ・フック」の略で、ウィンドウ・プロシージャ
を自作のものに置き換えて、流れてくるメッセージに対して特殊な処理を行うことで
す。
「ウィンドウのサブクラス化」とも言います。

エディットボックスに文字を入力するときは、エディットボックスのウィンドウ・プロ
シージャに様々なメッセージが飛んできます。
以前、これを利用して、「エディットボックスに入力した文字列のフリガナを取得」と
いうことをしたことがあります。
似たようなことが今回も出来ないかな、と思ったのですが…


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

>UpdateData(TRUE);
>MessageBox(m_edEdit1, 入力された内容, MB_OK);
>と入れました。
>ですが、一瞬メッセージボックスが表示されるだけで
>※2までの処理が無効になってしまいます。

>※2までの2行だけなら上手くいくという事より、
>やはり、一度Windowsのメッセージループに制御を戻さなければならないのでしょうか?

そうなると思います。
SetFocusにしろ、keybd_eventしろ結局はメッセージキューにメッセージをつんでいる
だけで処理しているわけではないと思います。
UpdateData(TRUE);を行った段階ではまだ確定して無いと思います。
それに途中にMessageBoxを入れてしまうとそちらにフォーカスを奪われてしまうので
うまく行かなくなるのでしょう。多分、keybd_eventはMessageBoxへ取られていると
思います。だから直ぐに消えてしまうわけです。
キーボードイベントを起こして擬似的に操作する方法では困るのであれば、
IMEを直接コントロールする方法を取らないといけないと思います。
Imm系の関数を調べてみれば、何か出てくるかもしれません。


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

補足。
SetFocusの実装を確認していないのでSendMessageを使っているのか
PostMessageを使っているのかによって挙動が変わりますね。
その辺は確認しないとはっきりいえないです。
keybd_eventについては、OSのメッセージキューにメッセージを積んでいるだけだと
思います。ですから、その時フォーカスがあるウインドウに対してメッセージが
ディパッチされます。
MessegeBoxの場合はまさにそれが起こっています。

今回の処理はボタンを押すことによってIMEがまだ持っている文字列を取得したいと
いう事だと思うので、エディットコントロール側で如何こうしなくても、
IMEから該当する文字列の取り込みが出来れば、エディットコントロールにセットする
事は可能ではないかと思います。
私も詳しく調べていないのでImm系の関数で解決する確証はないのですが、
逆変換をしたりする事も出来たと思うので直接取得する事もできるのではと
考えました。
外しているかもしれませんが、一度調べてみてください。


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

SetFocusってAPIのSetFocusを呼んでいたのね。
ってことで取り敢えず、SetFocusの件は置いといて。

ダイアログ上のコントロールでフォーカスの移動をする場合は、
CDialog::GotoDlgCtrlを使ったほうが良いです。
ダイアログ内で管理しているカレントコントロールとの対応がずれてしまいます。


返信引用
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

ミミです。
PATIOさん、シャノンさん、詳しくご説明してくださいましてありがとうございます。

>自作のものに置き換えて、流れてくるメッセージに対して特殊な処理を行うこと
フックというのは、MFCでは例えば、WM_INITDIALOG通知時のOnInitDialog()、
WM_TIMER通知時のOnTimer()の事なのですね。勉強になりました。

今回はどうもIME関係のAPIを使わなければダメなのかなと思い、
あれから過去ログなどを調べて以下の様なコーディングにしました。

OnButton1()
{
HIMC hIMC = ImmGetContext(m_hWnd);

DWORD cb = 0;
cb = ::ImmGetCompositionString(hIMC, GCS_COMPREADATTR, NULL, 0);

ImmReleaseContext(m_hWnd,hIMC);

if(cb>0){
// 未確定文字がある時に「確定」より一度確定させる
// (仮変換された状態ではそのまま確定、変換前では無変換確定)
GetDlgItem(IDC_EDIT1)->SetFocus();
::keybd_event(VK_RETURN, 0,0,0);
return;
}

// 未確定文字がない時に「確定」押された時の処理を以降に記述
MessageBox(未確定文字列はありません,",MB_OK)



}

とりあえず、これで私が意図する動きは実現できたようです。
ただ、cbに関してはDWORD型の構造体みたいで、その詳しい見方がまだよくわかっていません。
未確定文字がない時→ ==0
未確定文字がある時→ >0
の様なので、とりあえずは if(cb>0) のような聞き方をしています。

>keybd_eventしろ結局はメッセージキューにメッセージをつんでいるだけ
私はVC++暦がまだ浅いので、どうも普通のDOS時代のBASICの様な考え方をしてしまう悪いクセ
があるみたいです。
API等も「すぐ実行するものだ」という考え方が頭のどこかに残っているみたいですね。
一度Windowsに処理を戻さなければいけないという事を再認識しました。

Imm関係の関数はVC6のMSDNでは全て英語で理解に苦しみましたので、
Webでも探してどうにかここまでたどり着きました。

皆様、本当にありがとうございました。


返信引用
PATIO
(@patio)
Famed Member
結合: 4年前
投稿: 2660
 

一点だけ。

GetDlgItem(IDC_EDIT1)->SetFocus();はやめて

GotoDlgCtrl(GetDlgItem(IDC_EDIT1));を使いましょう。

CDialogクラス内の情報との不整合が起こりますので。


返信引用
ミミ
 ミミ
(@ミミ)
ゲスト
結合: 24年前
投稿: 63
Topic starter  

ミミです。

PATIOさん>
アドバイスありがとうございます。
GotoDlgCtrl(GetDlgItem(IDC_EDIT1));
に変更しました。

>ダイアログ内で管理しているカレントコントロールとの対応がずれてしまいます。

折角教えていただいたのに、先に私が掲載した際には見落としていました。
申し訳ありません。

今までフォーカスを移動させるには、
 (1)GetDlgItem(IDC_EDIT1)->SetFocus();か、
 (2)CEdit m_edcEdit1; m_edcEdit1.SetFocus()
のいずれかでコーディングしていました。

フォーカスに関しては、以後 GotoDlgCtrl(GetDlgItem(IDC_EDIT1));
にします。

貴重な情報ありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました