喫茶XRAYトップページ


[13008] キー押下のエミュレート返信 削除
2019/7/29 (月) 20:31:30 Mr.XRAY
[ 仮想キーコードの送信方法 ]
http://madia.world.coocan.jp/cgi-bin/DelphiBBS/wwwlng.cgi?print+201907/19070005.txt

>エンターキーは送信されません。

キーコードは送信されています.
Enter キーの押下としては機能していないだけです.
以下で確認できます.

//=============================================================================
//  SendMessage でキーコードを送る
//=============================================================================
procedure TReceivForm.Button1Click(Sender: TObject);
begin
  Memo1.Clear;

  SendMessage(Memo1.Handle, WM_KEYDOWN, VK_RETURN, 0);
  SendMessage(Memo1.Handle, WM_KEYUP,   VK_RETURN, 0);

  SendMessage(Memo1.Handle, WM_KEYDOWN, VK_Shift, 0);
  SendMessage(Memo1.Handle, WM_KeyDown, VK_LEFT,  0);
  SendMessage(Memo1.Handle, WM_KEYUP,   VK_LEFT,  0);
  SendMessage(Memo1.Handle, WM_KEYUP,   VK_Shift, 0);
end;

//=============================================================================
//  PostMessage でキーコードを送る
//  PostMessage はメッセージキューにポストする
//  この場合はキーの情報をポストする
//=============================================================================
procedure TReceivForm.Button2Click(Sender: TObject);
begin
  Memo1.Clear;

  PostMessage(Memo1.Handle, WM_KEYDOWN, VK_RETURN, 0);
  PostMessage(Memo1.Handle, WM_KEYUP,   VK_RETURN, 0);

  PostMessage(Memo1.Handle, WM_KEYDOWN, VK_Shift, 0);
  PostMessage(Memo1.Handle, WM_KeyDown, VK_LEFT,  0);
  PostMessage(Memo1.Handle, WM_KEYUP,   VK_LEFT,  0);
  PostMessage(Memo1.Handle, WM_KEYUP,   VK_Shift, 0);
end;

//=============================================================================
//  Memo1 の OnKeyDown イベント処理
//=============================================================================
procedure TReceivForm.Memo1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  Memo1.Lines.Add('OnKeyDown  $' + IntToHex(Key, 4));
end;

//=============================================================================
//  Memo1 の OnKeyup イベント処理
//=============================================================================
procedure TReceivForm.Memo1KeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  Memo1.Lines.Add('OnKeyUp  $' + IntToHex(Key, 4));
end;

//=============================================================================
//  ApplicationEvents1 の OnMessage イベント処理
//  WM_KEYDOWN, WM_KEYUP 等はメッセージキューにポストされた値を取得する
//  メッセージキューにポストするには PostMessage を使用する
//  SendMessage はメッセージキューにはポストしない
//=============================================================================
procedure TReceivForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  Ltext : string;
begin
  if Msg.hwnd = Memo1.Handle then begin
    if Msg.message = WM_KEYDOWN then begin
      Ltext := 'WM_KEYDON  $'
             + IntToHex(Msg.wParam, 4)
             + '  $' + IntToHex(Msg.lParam, 4);;
      Memo1.Lines.Add(Ltext);
    end else
    if Msg.message = WM_KEYUP then begin
      Ltext := 'WM_KEYUP  $'
             + IntToHex(Msg.wParam, 4)
             + '  $' + IntToHex(Msg.lParam, 4);;
      Memo1.Lines.Add(Ltext);
    end;
  end;
end;


[13009] Re:キー押下のエミュレート返信 削除
2019/7/29 (月) 20:33:10 Mr.XRAY
WM_KEYDOWN 等は lParam の指定がないと単にキーコードを送信するだけです.
キーイベントとするには lParam の値を設定します.
Shift キー等の組み合わせの時はその情報を lParam に格納しておきます.
WM_KEYDOWN 等メッセージを受信した時に Shift キー等を検出するコードを書くことがあります.
そのことを思い出してください.
送信には PostMessage を使用します.

以下の ZIP ファイルは昔テストしたコードを整備したものです.
Swiss Delphi Center に掲載されていたコードを利用しています.
Swiss Delphi Center です.懐かしいと思う方がいるかも.
今日現在も記事が存在することを確認しました.

http://mrxray.on.coocan.jp/Delphi/zip/QandA_20190728_Emulate_KeyEvent.zip
(EXE + ソースコード.説明なし)

某掲示板の場合は以下のようになります.

//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := '日本語 ABC テスト XYZ';
  Memo1.SelStart := 7;
end;

//=============================================================================
//  PostMessage でキー操作を実行
//  単なるキーコードのポストではない
//=============================================================================
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  PostKeyExHWND(Memo1.Handle, VK_RETURN, [], False);
  Memo1.SelStart := 7;
end;

//=============================================================================
//  PostMessage でキー操作を実行
//  単なるキーコードのポストではない
//=============================================================================
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  PostKeyExHWND(Memo1.Handle, VK_LEFT, [ssShift], False);
end;

正直なところ,keybd_event 関数を使用した方が簡単で確実です.
と思います.個人的には.


[13010] Re2:キー押下のエミュレート返信 削除
2019/7/29 (月) 20:35:35 Mr.XRAY
▼ Mr.XRAYさん

>  送信には PostMessage を使用します.

今回提示した程度のコードであれば SendMessage でも問題が発生することはないと思います.


[13011] Re2:キー押下のエミュレート返信 削除
2019/7/30 (火) 07:49:30 Mr.XRAY
> 某掲示板の場合は以下のようになります.

このサンプル (ZIP 書庫内の 02_Emulate_KeyEvent) は自アプリの TMemo に対する操作です.
プロセス超えの通信では正常に機能しません.
つまり,他のアプリに対して WM_KEYDOWN, WM_KEYUP メッセージを使用しての
キー押下エミュレートはできません (コード内にもコメントがあります).
これが可能であれば,以下のような方法を使わなくても済みます.

[670] [ 06_メモ帳へのコマンド送信 ]
http://mrxray.on.coocan.jp/Delphi/plSamples/670_SendTextThreadAttach.htm#06

ということで,

> keybd_event 関数を使用した方が簡単で確実です.

ということでございます.
他のアプリの操作というのは難しいのです.

[ 他のアプリへ文字列送信と取得 ]
http://mrxray.on.coocan.jp/Delphi/plSamples/670_SendTextThreadAttach.htm#00

ということです.


[13012] Re3:キー押下のエミュレート返信 削除
2019/7/30 (火) 12:03:05 Mr.XRAY
> プロセス超えの通信では正常に機能しません.

キー操作の情報はキーバッファに格納されます.
このバッファはメモリです.
他のアプリ,つまり他のプロセスから見れば送信側のプロセスのメモリです.
したがって,他のアプリからはキー押下としての情報処理が正しくできないことがあります.
キーコードそのものは他のアプリでも取得できます.

このことから SendMessage ではキー押下としての処理ができないことがあります.

http://chokuto.ifdef.jp/urawaza/message/WM_KEYDOWN.html

に lParam の詳しい説明がありますが,この説明にしたがって lParam の値を設定すれば
キー押下としての情報がバッファに格納されるわけではありません.
PostKeyExHWND 関数のコードのように,意図的にバッファに情報を格納する必要があります.


[13013] Re4:キー押下のエミュレート返信 削除
2019/7/31 (水) 09:37:49 Mr.XRAY
>http://mrxray.on.coocan.jp/Delphi/zip/QandA_20190728_Emulate_KeyEvent.zip
>(EXE + ソースコード.説明なし)


ものはついてですので keybd_event 関数を使用したサンプルを追加しておきました.


//=============================================================================
//  フォーム生成時の処理
//=============================================================================
procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Text := '日本語 ABC テスト XYZ';
  Memo1.SelStart := 7;
end;

//=============================================================================
//  keybd_event 関数を使用したキー操作のエミュレート
//  [Enter]
//=============================================================================
procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  Memo1.SetFocus;

  keybd_event(VK_RETURN, 0, 0, 0);
  keybd_event(VK_RETURN, 0, KEYEVENTF_KEYUP, 0);
end;

//=============================================================================
//  keybd_event 関数を使用したキー操作のエミュレート
//  [Shift] + [←]
//=============================================================================
procedure TForm1.SpeedButton2Click(Sender: TObject);
begin
  Memo1.SetFocus;

  keybd_event(VK_SHIFT, 0, 0, 0);
  keybd_event(VK_LEFT,  0, KEYEVENTF_EXTENDEDKEY, 0);
  keybd_event(VK_LEFT,  0, KEYEVENTF_EXTENDEDKEY or KEYEVENTF_KEYUP, 0);
  keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
end;


[13014] 他のアプリへのキー操作を送信返信 削除
2019/7/31 (水) 12:38:19 Mr.XRAY
受信側のアプリも自分で開発する場合であれば,
他のアプリにフォーカスを移動しないで,
他のアプリへキー操作を送信する方法が全くないわけではありません.

[650] [02_レコード型の場合]
http://mrxray.on.coocan.jp/Delphi/plSamples/650_SendText.htm#02

のサンプルの方法が使用できます.
送信側は例えば以下のようします.
テータを受け取ったアプリ側では,このデータを元に WM_KEYDOWN, WM_KEYUP メッセージを
目的のコントロールに PostMessage します.
これも UP した ZIP 書庫に追加しておきました.


type
  TKeyDataInfo = record
    Key  : Byte;
    shift: TShiftState
  end;

//=============================================================================
//  キー押下データの送信
//  [Enter]
//=============================================================================
procedure TSenderForm.Button1Click(Sender: TObject);
var
  LKeyData  : TKeyDataInfo;
  LCopyDS   : TCopyDataStruct;
  LhWindow  : HWND;
begin
  LKeyData.Key   := VK_RETURN;
  LKeyData.shift := [];

  //受取る側のウィンドウハンドル
  LhWindow := FindWindow('TReceivForm', nil);
  if LhWindow = 0 then exit;

  LCopyDS.dwData := 1234; //適当な値
  LCopyDS.cbData := SizeOf(LKeyData);
  LCopyDS.lpData := Addr(LKeyData);

  SendMessage(LhWindow, WM_COPYDATA, Handle, LPARAM(Addr(LCopyDS)));
end;

//=============================================================================
//  キー押下データの送信
//  [Shft] + [←]
//=============================================================================
procedure TSenderForm.Button2Click(Sender: TObject);
var
  LKeyData  : TKeyDataInfo;
  LCopyDS   : TCopyDataStruct;
  LhWindow  : HWND;
begin
  LKeyData.Key   := VK_LEFT;
  LKeyData.shift := [ssShift];

  //受取る側のウィンドウハンドル
  LhWindow := FindWindow('TReceivForm', nil);
  if LhWindow = 0 then exit;

  LCopyDS.dwData := 1234; //適当な値
  LCopyDS.cbData := SizeOf(LKeyData);
  LCopyDS.lpData := Addr(LKeyData);

  SendMessage(LhWindow, WM_COPYDATA, Handle, LPARAM(Addr(LCopyDS)));
end;


[13019] Re:キー押下のエミュレート返信 削除
2019/8/6 (火) 17:45:50 Mr.XRAY
[ 仮想キーコードの送信方法 ]
http://madia.world.coocan.jp/cgi-bin/DelphiBBS/wwwlng.cgi?print+201907/19070005.txt

>※キー送信の合間に別の処理を挟みたいので、PostMessageの使用は考えて
> おりません。(処理の順番が狂ってしまうため)


だから SendNessage を使うということてすが,
これはちょっと違うというか,違和感があります.本人の思い込みでしょう.
そのような問題が発生するとすれば,それはコーディングも問題でしょう.

その内容だけとつまらないので,記事構成を考え付いたらサンプルを作成して UP
したいと思っています.

※ 当然ですが WM_KEYDOWN, WM_KEYUP で SendMessage を使用することは考えられません.


[13031] サンプル記事UPしました返信 削除
2019/8/10 (土) 12:33:26 Mr.XRAY
> その内容だけとつまらないので,記事構成を考え付いたらサンプルを作成して UP
> したいと思っています.


以下のサンプルを追加しました.

[ 671_他のアプリへキー操作を送信 ]
http://mrxray.on.coocan.jp/Delphi/plSamples/671_EmulateKeyPress.htm

[ 702_PostMessage 関数と SendMessage 関数 ]
http://mrxray.on.coocan.jp/Delphi/plSamples/702_PostMessage_SendMessage.htm


> ※キー送信の合間に別の処理を挟みたいので、PostMessageの使用は考えて
> おりません。(処理の順番が狂ってしまうため)


という問題ではないということです.

> Keybd_eventの使用は考えておりません。

ということは他のアプリのキー送信のエミュレートはできないということになります.


※ サンプル記事の追加により,以下のファイルは削除しました.
  http://mrxray.on.coocan.jp/Delphi/zip/QandA_20190728_Emulate_KeyEvent.zip


[13032] Re:サンプル記事UPしました返信 削除
2019/8/12 (月) 14:22:27 Mr.XRAY
> という問題ではないということです.

PostMessage を使用すべきメッセージは PostMessage を使用しないと
正常な動作は期待できないという意味です.
処理待ちにしたいから SendMessage を使用するという問題ではありません.

ただし,WM_APP のユーザ定義のメッセージは特別です.
自分で処理コードを作成するのですからどうにでもなります.


INCM/CMT
Cyclamen v3.82