IMEの入力値を取得するには

解決


まつやま  2002-01-10 07:09:34  No: 436  IP: [192.*.*.*]

住所録を登録する画面で名前を入力すると自動的に名前のよみがなを編集したい。
IMEの入力値がとる方法がしりたい。
名前:松山    名前のふりがな:まつやま
Delphi6Pro

編集    削除
にしの  2002-01-10 08:05:06  No: 437  IP: [192.*.*.*]

immユニットを使います。

Form1に、Edit1とButton1とListBox1をおき、Button1のOnClickに次のような定義をすれば、とり方はわかると思います。

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
  imc: HIMC;
  kl: HKL; // キーボードレイアウト
  Dst: PCandidateList;
  sz: integer; // サイズ
  tmppchar: PChar;
begin
  Edit1.SetFocus;
  ListBox1.Clear;
  imc := ImmGetContext(Handle);
  kl := GetKeyboardLayout(0);
  sz := ImmGetConversionList(kl, imc, PChar(Edit1.Text), nil, 0, GCL_REVERSECONVERSION);
  GetMem(Dst, sz);
  ImmGetConversionList(kl, imc, PChar(Edit1.Text), Dst, sz, GCL_REVERSECONVERSION);
  for i := 0 to Dst.dwCount - 1 do
  begin
    tmppchar := PChar(DWORD(Dst) + Dst.dwOffset[i]);
    ListBox1.Items.Add(String(tmppchar));
  end;
  FreeMem(Dst);
  ImmReleaseContext(Handle, imc);
end;

編集    削除
松山  2002-01-10 22:51:40  No: 438  IP: [192.*.*.*]

にしのさん  お返事ありがとうございます。
早速、試してみましたがうまくいきません。教えてください。
Edit1とButton1とListBox1を配置して
お返事のコードをButton1.OnClickに貼り付けで実行しました。
エラーになったのでUses に  immを追加して実行しました。
これで動作はするのですがListBoxにはなにも表示されなかったり
ゴミのようなものが出たりです。
操作はEDIT1に松山(まつやまで変換して確定後)と入力して
Button1をクリックしています。
あとEDIT1になにも入力がないときは異常のようです。
今はDelphi4ですが、まずいですか?
よろしくお願いします。

編集    削除
にしの  2002-01-11 06:04:19  No: 439  IP: [192.*.*.*]

うちの環境はDelphi5です。
予想ですが、HandleをApplication.Handleにしてはどうですか?
僕も、最初これを作るときにEdit1.SetFocusしないでIMEコンテキストを取得したらエラーになりましたから。
ちなみに、手元の資料(Windows98 APIバイブル)では、Editからメッセージを飛ばして、そのメッセージの処理内で取得しているようです。

imc(IMEコンテキスト)がきちんと取得できているか、kl(キーボードレイアウト)が取得できているか、ImmGetConversionListの戻り値(CandidateListのサイズ)が正常か、確かめてみてください。

編集    削除
にしの  2002-01-11 07:55:30  No: 440  IP: [192.*.*.*]

間違えてました。
dwOffsetは、[1..1]と定義されているので、[0]や[2]以降を参照しても意味がありません。
# [2]以降は意味があるかもしれませんが、どうせ#0区切りの文字列なので。
それと、Dstはポインタで、内部を参照するには逆参照しなければならないですね。
# Delphi5ではもしかしたら勝手にやってくれてたのかも
なので、var に offset:DWORD;と、idx: integer;を用意して、for文以下を

  tmppchar := PChar(DWORD(Dst) + Dst^.dwOffset[1]);
  offset := 0;
  for i := 0 to Dst^.dwCount - 1 do
  begin
    tmppchar := PChar(DWORD(tmppchar) + offset); 
    idx := ListBox1.Items.Add(String(tmppchar));
    offset := Length(ListBox1.Items[idx]) + 1;
  end;
  FreeMem(Dst);

のように変えてください。

編集    削除
松山  2002-01-12 00:56:26  No: 441  IP: [192.*.*.*]

にしのさんお返事ありがとうございます。
指示とおり、修正したのですがLISTBOXには意味不明の文字が
表示されます。
コーディングは以下のとおり。(Delphi4.0j  Pro)

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
  imc: HIMC;
  kl: HKL; // キーボードレイアウト
  Dst: PCandidateList;
  sz: integer; // サイズ
  tmppchar: PChar;
  offset:DWORD;
  idx: integer;
begin
  Edit1.SetFocus;
  ListBox1.Clear;
  imc := ImmGetContext(Handle);
  kl := GetKeyboardLayout(0);
  sz := ImmGetConversionList(kl, imc, PChar(Edit1.Text), nil, 0, GCL_REVERSECONVERSION);
  GetMem(Dst, sz);
  ImmGetConversionList(kl, imc, PChar(Edit1.Text), Dst, sz, GCL_REVERSECONVERSION);
//  showmessage(inttostr(Dst.dwCount));
  tmppchar := PChar(DWORD(Dst) + Dst^.dwOffset[1]);
  offset := 0;
  for i := 0 to Dst^.dwCount - 1 do
    begin
    tmppchar := PChar(DWORD(tmppchar) + offset);
    idx := ListBox1.Items.Add(String(tmppchar));
    offset := Length(ListBox1.Items[idx]) + 1;
    end;
   FreeMem(Dst);
  ImmReleaseContext(Handle, imc);

end;

編集    削除
にしの  2002-01-12 01:11:00  No: 442  IP: [192.*.*.*]

今の環境にDelphiがないため、確かめられません。
家に帰ったら確かめますね。
一応念のため、OSとIMEは何をお使いですか?
うちは、WindowsXP Pro+IME2002です。

それと、HandleはEdit1.Handleかもしれません。
うちだと、HandleでもEdit1.Handleでもうまくいきました。
# SetFocusしないとエラーになりました

編集    削除
にしの  2002-01-12 09:12:21  No: 443  IP: [192.*.*.*]

動きましたよ。
やはり、OS、IMEの組み合わせでしょうか。
それともD4とD5の違いでしょうか。
これ以上はちょっとわかりません。

編集    削除
便乗くん  2002-01-12 12:15:58  No: 444  IP: [192.*.*.*]

Delphi6、Win98、IME98 では、
Edit1が「松山」で、
ListBox1の表示は
「"gq¥」の1行です。

Edit1が「1」(半角)の場合、
ListBox1の表示は、

いっ
ひと
の3行です。

WindowsXP Pro+IME2002では、
Edit1が「松山」の場合、ListBox1の表示は
何と表示されるんでしょうか?

編集    削除
にしの  2002-01-12 22:10:11  No: 445  IP: [192.*.*.*]

Delphi5,WindowsXP Pro+IME2002では、
ListBox1の表示は
まつやま
が8行表示されます。
半角の1の場合、
ListBox1の表示は
1
だけです。
空欄ではエラーが発生します。

編集    削除
松山  2002-01-13 01:27:10  No: 446  IP: [192.*.*.*]

ListBox1には「〜gq\」と表示されます。
今の環境はWinMe+IME2000+Delphi6.0Proです。
IME周りで参考になる本をご存知なら教えてください。

編集    削除
便乗くん  2002-01-13 09:21:38  No: 447  IP: [192.*.*.*]

IMEの違いではなくて、OS(Win9XかNT系か)の違いが
影響するんですかね〜(@_@)
AnsistringとUnicodeの問題かな〜でも、
ImmGetConversionListA()
ImmGetConversionListW()
でやってもうまくいかないし…

編集    削除
にしの  2002-01-13 14:43:20  No: 448  IP: [192.*.*.*]

参考になるかどうかわかりませんが、
Windows98 APIバイブル
シェル/シェルユーティリティ/印刷/IME/追加関数 編
有限会社ガリバー著
長谷川勝規 監修
販売元 翔泳社
ISBN4-88135-734-4
定価5800円+税
これに、IME関連の関数や定数(値は出ていません)、構造体などが出ています。
サンプルはVisualC++で書かれています。

UnicodeかSJISかですが、特に記述はありませんでした。

編集    削除
便乗くん  2002-01-14 09:45:35  No: 449  IP: [192.*.*.*]

ここに解説がありました。
ナントIME98、IME2000のバグだったとは(-_-;)
いまだ未解決のようですね。困ったもんだ。(-_-メ)

http://www.microsoft.com/japan/support/kb/articles/J059/3/78.asp

編集    削除
にしの  2002-01-14 10:11:58  No: 450  IP: [192.*.*.*]

http://hp.vector.co.jp/authors/VA009883/
の、Yomiというツールだとうまく変換できますよね?
# 対応がIME98以降となっているので
これにはDLLが含まれていて、.htaファイル(WSHすぷりぷと)で読み込んでDLLを呼び出しているので、このDLLの使用許可が出れば読み仮名取得が簡単にできそうです。

たしか、IME97以降には、別の方法で読み仮名を取得する方法があったはずなんですが、思い出せません。

編集    削除
便乗くん  2002-01-14 15:19:11  No: 451  IP: [192.*.*.*]

「Yomi」というツールでは確かにIME98でも漢字の読みが表示されますね。
う〜ん、どうやっているんだろう。

中に入っている'comuni.Yomi.dll'を
次のように呼び出してみましたが、
「欠陥エクスポートにリンクされています」という
エラーが出てしまいます。
このDLLは Delphiでは使えないんでしょうか。(T_T)

const comuniYomi  = 'comuni.Yomi.dll';

function getYomi(inStr: LPSTR): LPSTR; stdcall;
external comuniYomi name 'getYomi';

procedure TForm1.Button1Click(Sender: TObject);
begin
 Edit1.Text := getYomi('明日');
end;

編集    削除
にしの  2002-01-15 02:48:27  No: 452  IP: [192.*.*.*]

TLIBIMPで、
tlibimp comuni.Yomi.dll
とすると、
YOMILib_TLB.pas
YOMILib_TLB.dcr
が吐かれます。
これを使えばたぶんできると思います。
# 要はCOMオブジェクトです

それで、uses節にYOMILib_TLBを加えて、次のようにすれば取れます。

procedure TForm1.Button3Click(Sender: TObject);
var
  yomi: IYomiImpl;
  tmpstr : string;
begin
  yomi := CoYomiImpl.Create;

  tmpstr := yomi.getYomi(WideString(Edit1.Text));

  ListBox1.Items.Clear;
  ListBox1.Items.Add(tmpstr);

end;

CreateComObjectしたオブジェクトの廃棄の仕方はわかりませんでした。
ヘルプを見ると、複数作るときはクラスファクトリを使用したほうがよいと勝てあるので、実際には、単一のオブジェクトにするかクラスファクトリを使うとよいです。

編集    削除
松山  2002-01-15 08:11:00  No: 453  IP: [192.*.*.*]

もう少しじっくりテストします。
みなさま、ご協力ありがとうございました。

編集    削除
便乗くん  2002-01-15 08:26:39  No: 454  IP: [192.*.*.*]

Delphi6Personal には TLIBIMP.exe がありません。(T_T)
これはお手上げですね。

編集    削除
にしの  2002-01-16 06:48:15  No: 455  IP: [192.*.*.*]

tlibimp、ありませんか。
これで動きませんか?
Delphi5で通ります。
http://www.geocities.co.jp/AnimalPark/1770/YOMILib_TLB.lzh
どうでしょうか。
.dcrはいらないと思いますが。
コンポーネントと同じように、パッケージを作成してインストールしてみてください。

編集    削除
便乗くん  2002-01-16 10:03:08  No: 456  IP: [192.*.*.*]

解凍したYOMILib_TLB.pasをプロジェクトのフォルダに入れて、
uses節にYOMILib_TLBを加えると動きました。\(^○^)/
WideStringのキャストは無くても問題ないようです。

色々な人名の読みテストしてみると、妙な変換がされましたが、
IMEのプロパティで初期変換モードを「人名/地名」にすることで
ほぼ的確な読み変換が出てきました。
ありがとうございました。m(__)m

編集    削除