お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"WMIME_CHAR. WM_CHAR @ Windows2000"







【 WM_CHAR メッセージハンドラでの2バイト文字取得サンプル】

参考 url 2001/06/27 現在。改行御免
http://www.microsoft.com/japan/developer/windows2000/
technologies/ac-win2kcompat/ac-win32apichanges.asp

Windows2000 上では、WM_KEYDOWN から WM_KEYUP までの間、メッ
セージのデータ WParam, LParam をちょ〜してはいけないというお
話です。(ちょ〜す=データを更新する=値を代入する)

上記 url の記述の通り、Windows2000 から手書認識、音声認識を
サポートする SendInput API が実装され、この API によってポス
トされたキーデータの WParam の HiWord にそのデータが入ってい
て、TranslateMessage API もこのデータをサポートしている。だ
から、途中で WParam を更新するといかんぜということらしいです。

【その1】文字入力時のTMemo が受け取るメッセージ

TMemo に「あ」$82A0 を入力した時に TMemo が受け取るメッセー
ジを示します。

#1
MessageID:WParam:LParam
WM_IME_CHAR:000082A0:00000001
WM_CHAR:00000082:00000001

以下は win32.hlp WM_IME_CHAR からの引用です。

>Remarks
>
>If the WM_IME_CHAR message includes a double-byte character, 
>the DefWindowProc function converts this message into two 
>WM_CHAR messages, each containing one byte of the double-byte character. 
>

2バイト文字を含む WM_IME_CHAR は2個の WM_CHAR に変換されま
す。実際には1バイト文字も1個の WM_CHAR に変換されます。こ
こで、変換されたメッセージは、メッセージキューに溜まります。
メッセージキューについては、Delphi CD-ROM にある Api32wh.
slp の「メッセージとメッセージ キューの概要」のトピックを参
照してください。
  #1の結果は上記記述と違い、1個の WM_CHAR しか来ていませ
ん。何故だ?

【その2】とりあえず WM_IME_CHAR で「あ」文字を取得し 
WParam を $A0 に更新してみると Windows95, 98 ではそれらしく
動作するが、Windows2000 でその下記コードを利用する人のメッ
セージキューは、身に覚えのない WM_CHAR メッセージに襲われる
現象発生。以下サンプルコード

procedure TEditor.WMImeChar(var Msg: TMessage);
var
  S: String;
  C: Char;
begin
  if Msg.wParam > 255 then
  begin
    // 2バイト文字
    C := Chr(Msg.wParam);
    Msg.wParam := Msg.wParam shr 8; // 更新
    S := Chr(Msg.wParam) + C;
  end
  else
    // 1バイト文字
    if TWMChar(Msg).CharCode in [$20..$7E, $A0..$FF] then
      S := Chr(Msg.wParam);
  // Windows の DefWindowProc により WM_CHAR がポストされる
  inherited; 
end;

【3.TMemo の探求】
つまり、WM_IME_CHAR で IME 文字を取得後 WParam をちょすのは
御法度であります。ではどうするかということで、TMemo をいじめ
てみます。

  SendMessage(Memo1.Handle, WM_IME_CHAR, $8E8E, 0); // 試
  SendMessage(Memo1.Handle, WM_CHAR, $8F, 0);

TMemo には「試」$8E8E ではなく「庶」$8F8E が表示されます。

【4.ミソ】
  SendMessage(Memo1.Handle, WM_IME_CHAR, $8E8E, 0); // 試
この時、WParam が $8E の WM_CHAR が2個メッセージキューにポ
ストされます。メッセージキューに溜まったメッセージは、アプリ
ケーションが暇になるまで放置されますので、この時点では、ウィ
ンドプロシージャで処理されません。
  SendMessage(Memo1.Handle, WM_CHAR, $8F, 0);
これが実行された時点で、Memo1 は WParam が $8F の WM_CHAR を
受け取ります。この時、TMemo の WM_CHAR メッセージハンドラ
(=Windows の標準コントロールの WM_CHAR メッセージハンド
ラ)は、メッセージキューに溜まっているだろう次の2バイト目を
キューから取り出し、$8F に加え2バイト文字として処理します。
つまり「庶」が表示されます。

  実験してみましょう
  フォームにメモを1個貼って、その OnClick イベントハンドラ
を以下のように記述します。

procedure TForm1.Memo1Click(Sender: TObject);
var
  I: Integer;
begin
  // 念のため、メッセージキューを空にする
  Application.ProcessMessages;
  // 「あいうえお」の下位バイトだけをメッセージキューに
  // 溜める
  PostMessage(Memo1.Handle, WM_CHAR, $A0, 0);
  PostMessage(Memo1.Handle, WM_CHAR, $A2, 0);
  PostMessage(Memo1.Handle, WM_CHAR, $A4, 0);
  PostMessage(Memo1.Handle, WM_CHAR, $A6, 0);
  PostMessage(Memo1.Handle, WM_CHAR, $A8, 0);
  // 「あいうえお」の上位バイトだけをウィンドプロシージャに
  // 送りつける
  for I := 0 to 4 do
    SendMessage(Memo1.Handle, WM_CHAR, $82, 0);
  // 改行
  SendMessage(Memo1.Handle, WM_CHAR, $0D, 0);    
end;

  あいうえお改行とメモに表示されます。Windows2000 上でもだい
じょぶだそうです。
  
【5.本日のお題 WM_CHAR による2バイト文字取得サンプル】

procedure THoge.WMChar(var Message: TWMKey);
var
  CH, CL: Char;
  M: TMsg;
  S: String;
begin
  if Message.CharCode in [$20..$7E, $A0..$FF] then
    // 1バイト文字
    S := Chr(Message.CharCode)
  else
  begin
    // 2バイト文字
    CH := Chr(Message.CharCode);
    if (CH in LeadBytes) and
       PeekMessage(M, Handle, 0, 0, PM_NOREMOVE) and
       (M.Message = WM_CHAR) and
       (M.wParam in [$40..$FF]) and
       PeekMessage(M, Handle, 0, 0, PM_REMOVE) then
    begin
      CL := Chr(M.wParam);
      S := CH + CL;
    end;
  end;
end;

**** 本田勝彦 http://member.nifty.ne.jp/~katsuhiko/ ****
 



Original document by 本田勝彦        氏 ID:(VYR01647)


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum