Delphiでキー入力を投げたい

このQ&Aのポイント
  • Delphiのプログラムでゲームコントローラに対応していないソフトウェアに入力を送信する方法を教えてください。
  • Delphiのプログラムでコントローラからの入力を受け取り、該当するウインドウにメッセージを送信する方法を教えてください。
  • Delphiでキー入力を送信する方法について教えてください。
回答を見る
  • ベストアンサー

Delphiでキー入力を投げたい

ゲームコントローラに対応していないソフトウェアを、コントローラに対応させるべくプログラムを組んでいます。 Delphiのプログラムでコントローラからの入力を受け取り、該当するウインドウにメッセージを送信すればこの仕組みが実現できると考えたのです。 まず、以下の関数を記述しました。 function CallBackTest(WH: HWND; LP: LParam): BOOL stdcall; var Buff: array [0..255] of Char; begin if IsWindowVisible(WH) then if GetWindowText(WH, Buff, 255) <> 0 then TListBox(LP).Items.AddObject(Buff, Pointer(WH)); Result := True; end; 次に、ListBoxを用意して、以下を実行しました。 EnumWindows(@CallBackTest, Longint(ListBox1)); ListBoxには実行中のウインドウタイトルが表示されます。そこで、目的のウインドウ名を選択して for i := 0 to (ListBox1.Items.Count - 1) do if ListBox1.Selected[i] then PostMessage(hwnd(listbox1.Items[i]), WM_KEYDOWN, 入力キー名, 0); end; こんな感じで投げられるかな?と思ったのですが、悲しいほど無反応。 なにか根本的にやり方を間違えているのでしょうか・・・?

質問者が選んだベストアンサー

  • ベストアンサー
  • SHIMAPEE
  • ベストアンサー率75% (154/203)
回答No.1

コードを試しました。WindowハンドルをAddObjectで記憶していますので下記は修正しました。 【修正前】PostMessage(hwnd(listbox1.Items[i]), WM_KEYDOWN, 入力キー名, 0); 【修正後】PostMessage(hwnd(listbox1.Items.Objects[i]), WM_KEYDOWN, {入力キー名} 48, 0); この修正を加えたら、秀丸エディタには文字0を入力できました。しかし、メモ帳やワードパッドには入力できませんでした。 ウィンドウとメッセージについて調べて試す必要があると思います。EnumWindowsはトップレベルのウィンドウしか探しません。目的のアプリケーションがトップレベルのウィンドウにWM_KEYDOWNを送って反応するものかどうか。子ウィンドウあるいは別のメッセージにしたらどうか、フォーカスをあてたらどうか、など。

その他の回答 (1)

  • SHIMAPEE
  • ベストアンサー率75% (154/203)
回答No.2

追加です。ウィンドウを前面にしてキー操作を一つ一つ送ってみてはどうでしょうか。メモ帳やワードパッドにも入力できました。 【変更前】 PostMessage(hwnd(listbox1.Items.Objects[i]), WM_KEYDOWN, {入力キー名} 48, 0); 【変更後】 var Key: Word; SetForegroundWindow(hwnd(listbox1.Items.Objects[i])); Key := VkKeyScan('0'); keybd_event(LoByte(Key), 0, 0, 0); // 文字0 keybd_event(LoByte(Key), 0, KEYEVENTF_KEYUP, 0); Key := VkKeyScan('a'); keybd_event(LoByte(Key), 0, 0, 0); // 文字a keybd_event(LoByte(Key), 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_SHIFT, 0, 0, 0); // shiftキー keybd_event(LoByte(Key), 0, 0, 0); // 文字A keybd_event(LoByte(Key), 0, KEYEVENTF_KEYUP, 0); keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

pythian
質問者

お礼

遅くなってすみません。ご指摘の通りObjectsで取り出したら正常にキー入力を送ることができました(基本的なところでしたね)。 トップレベルで運良く反応してくれたため、これをベースに実装していきたいと思います。ありがとうございました!

関連するQ&A

  • リストボックスのアイテムをマウスで並べ替えたいです

    リストボックスのアイテムをマウスのドラッグドロップで並べ替えたいのですが、 下のような感じで書いてみたのですが、 この状態だと、4番目のものを一番上に持ってくるという動作だけするのですが、 4番目から3番目に移動する場合や、1番目から3番目に移動する場合など 追加していくとIFが重なってきてすごくややこしくなってしまいます。 もっと分かりやすくて合理的な方法がありましたら、 大体でも良いですので、教えて頂けたら助かります。 よろしくおねがいいたします。 Private Sub Form1_Load(...略 ListBox1.Items.Add("AAA") ListBox1.Items.Add("BBB") ListBox1.Items.Add("CCC") ListBox1.Items.Add("EEE") End Sub Private Sub ListBox1_MouseDown(...略 SelectedSortFrom = ListBox1.SelectedIndex End Sub Private Sub ListBox1_MouseUp(...略 SelectedSortTo = ListBox1.SelectedIndex ListBox1Sort(SelectedSortFrom, SelectedSortTo) End Sub Private Function ListBox1Sort(ByVal From As Integer, ByVal Too As Integer) If From = -1 Then Exit Function If Too = -1 Then Exit Function Dim A(ListBox1.Items.Count) As String Dim B As Boolean For i As Integer = 0 To ListBox1.Items.Count - 1 A(i) = ListBox1.Items(i) Next For i As Integer = 0 To ListBox1.Items.Count - 1 If i = Too Then ListBox1.Items(i) = A(From) B = True Else ListBox1.Items(i) = A(i - 1) End If Next End Function

  • リストボックスからの入力をテキストに貼付

    下記コードではリストボックあ行選択しテキスト1~6に入力後、クリアボタンで消去したあと、か行選択しテキストに入力したら7~貼付けになるクリアボタンで消去後、改めてテキスト1~入力するコードがありますか。どなたか解る方よろしくお願いします。 Private Sub 実行_Click() Static cnt As Integer Dim i As Integer If Listbox.ListIndex = -1 Then Exit Sub For i = 0 To Listbox.ListCount - 1 If Listbox.Selected(i) Then cnt = cnt + 1 If cnt > 10 Then cnt = 1 Me.Controls("TextBox" & cnt).Text = Listbox.List(i) End If Next End Sub Private Sub クリア_Click() Dim tbCont As Control With Me.MultiPage1 For Each tbCont In .Pages(.Value).Controls If TypeName(tbCont) = "TextBox" Then tbCont.Value = Null End If Next tbCont End With End Sub

  • 文字列の取り出し方

    今、Visual Basic 2008を使用しています。 textbox2とtextbox3があり、textbox2に複数行にまたがる文字列があります。 この文字列の中で、listbox1の中にある項目の文字列が入ってる場合はカンマ区切りで文字列の後ろにつなげたいのですが、うまくいきません。 具体的には あいうえお あかさたな いろはにほ というtextbox2の内容について、listbox1内に あ い という2つの項目があった場合、 あいうえお,あ,い あかさたな,あ いろはにほ,い という結果をtextbox3に書き出すという内容です。 Dim addtag As String = "" Dim i As Integer For Each part As String In TextBox2.Text.Split(vbCrLf) If part <> "" Then For i = ListBox1.Items.Count - 1 To 0 Step -1 If part.Contains(ListBox1.Items(i)) = True Then addtag = addtag & "," & ListBox1.Items(i) End If Next part = part & addtag TextBox3.Text = TextBox3.Text & part & ControlChars.NewLine part = "" addtag = "" End If Next というプログラムを組んでいますが、どこが間違っているのかわからず、煮詰まってしまいました。 プログラムは初心者で、根本から違っていたら恥ずかしい限りですが、どうかよろしくお願いします。

  • Delphi6 ループ中にキー入力

    Delphi 6 です。 for next などのループの中で、stringgridのセルをEnterキーで選択させたい時、選択されるまで(キーが押されるまで)処理を進めたくない方法は、どうするんでしょうか? flg:=false; for i:=1 to 100 do begin ~諸々の処理で flg:=true; ~ if flg=true then x[i]:= stringgridの選択されたRow番号(はじめからフォーカスされている番号でなく) ~諸々の処理で flg:=false; ~ end;

  • win32 GetWindowLong

    GetWindowLongで別のプログラムのウインドウハンドルを取得してウィンドウプロシージャのアドレスを調べようと思ったのですが取得できません。他のウィンドウのウィンドウプロシージャのアドレスは取得できないのでしょうか? ------------------------------------------ #include <stdio.h> #include <string.h> #include <windows.h> struct cell{ HWND hWnd; char WindowName[256]; }; BOOL CALLBACK EnumWndProc( HWND hWnd, LPARAM lParam ) { char buff[256]=""; GetWindowText( hWnd,buff, sizeof(buff));//ウインドウの文字を取得して、 if(strcmp(buff,((cell*)lParam)->WindowName)==0){//名前が一致したら、 ((cell*)lParam)->hWnd = hWnd;//ウィンドウハンドルを渡す } return true; } int main(int argc, char* argv[]) { cell c; c.hWnd =NULL; strcpy(c.WindowName,"無題 - メモ帳");//検索するウィンドウの名前 EnumWindows( EnumWndProc, (LPARAM)&c); LONG wndproc, exstyle; if(c.hWnd != NULL){ //目的のウインドウハンドルが取得できました wndproc = GetWindowLong(c.hWnd, GWL_WNDPROC); //メモ帳のウィンドウプロシージャが取得できない exstyle = GetWindowLong(c.hWnd, GWL_EXSTYLE); } return 0; }

  • テキストボックス空欄への追加入力

    リストボックス1であ行の氏名項目を選択実行しテキストボックス1~8に入力された後にか行にリストボックス項目を変え氏名を選択実行した場合、下記のコードではテキストボックス1からまた上書きされる。テキストボックス空欄に続けて選択項目が入力される方法はあるのでしょうか。悩んでいます。どなたかコードがわかる方よろしくお願いします。 Private Sub 実行Cnd_Click() Dim cnt As Integer   Dim i As Integer If ListBox1.ListIndex = -1 Then Exit Sub cnt = 1 For i = 0 To ListBox1.ListCount - 1 If ListBox1.Selected(i) Then Me.Controls("TextBox" & cnt).Text = ListBox1.List(i) cnt = cnt + 1 End If Next End Sub

  • マクロでの次の実行マクロへの記述

    下記のマクロを記述しました。 一つのマクロ処理を終わらせて、次のマクロ(例:test)を動かしたいのですが何処に 記述したら良いかわかりません。 教えてください。 Sub Macro1() Dim i As Integer Dim buff As String i = 2 While 1 If Range("B" & i).Value = "" Then End End If buff = Range("B" & i).Value Range("B" & i).Value = Left(buff, 7) + " " + Mid(buff, 8, 5) + " " + Right(buff, 6) i = i + 1 Wend   Call test →ここに仮に記述したのですが、testのマクロに行きません。 End Sub 以上

  • WM_CLOSEで閉じれないウィンドウを閉じるには?

    以下にソースを張ります。 #include <stdio.h> #include <windows.h> BOOL CALLBACK EnumWindowProc(HWND hwnd, LPARAM lp) { static bool is_first = true; DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); DWORD dwPID; if ( ::IsWindow(hwnd) && ::IsWindowVisible(hwnd) && (style&WS_CAPTION) && !(style&WS_POPUP) ) { char buf[65536]; ::GetWindowText(hwnd, buf, 65535); GetWindowThreadProcessId( hwnd, &dwPID ); if ( buf[0] != '\0' ) { if ( is_first ) is_first = false; else //printf("%c\n", 1); printf("%s%d\n", buf,hwnd); } } return TRUE; } int main (void){ ::EnumWindows(EnumWindowProc, 0); HWND hWnd; printf("プロセスIDを入力:\n"); scanf("%d",&hWnd); if( hWnd != NULL ){ printf( "終了します。-- pause --\n" ); getchar(); PostMessage( hWnd, WM_CLOSE, 0, 0 ); }else{ printf( "起動してないウインドウズです。\n" ); } return 0; } これですとたとえばメモ帳を編集していたときに WM_CLOSE メッセージを送ったときに「変更を保存しますか?」のようなダイアログが出る アプリがあります。これをダイアログが出ずに強制終了するには どうしたらよいでしょか?よろしくお願いします。

  • リストボックスの文字比較

    コンボボックスで選択された文字列をリストボックスと比較して 対応する行のリストボックスの文字列を削除を行いたいのですが 何故か、リストボックスの最初の行と、最後の行の文字列しか 等しいとみなされず、処理ができません。(名前が間違っている わけではないです)また、最初の行と最後の行の名前を、試しに 他の行の名前と入れ替えてみたりしましたが、やはり比較を行う時に 最初の行と最後の行しか文字列が一致しません… 文字列の比較の方法に問題があるのでしょうか… ご存知の方がいらっしゃいましたらアドバイスをお願いします comb = ComboBox1.Text For i = 0 To ListBox1.Items.Count - 1 → If comb = ListBox1.Items(i) Then ListBox1.Items.RemoveAt(i) Exit For End If Next

  • ファイルコピーで更新日時が変わってしまう。

    XP pro + Visual Basic 2008 で、ファイルをバックアップするためのソフトを作ろうとしています。 ListViewを二つ用意して、それぞれに対象となるフォルダー内のファイルを表示、チェックリストにチェックしたファイルを、互いのフォルダーにコピーする。のようなものを作っています。 しかしListView1からListView2へコピーを行うと、どういうわけか更新日時が数秒づれてコピーされてしまいます。逆の場合はづれが起こらないようです。 原因&解決法を教えてください。 コードは以下の通りです。    Dim i As Integer    Dim response As MsgBoxResult    i = 0    response = MsgBox("リスト1の選択ファイルをコピーしますか?", MsgBoxStyle.YesNoCancel, "確認")    If response = MsgBoxResult.No Then       GoTo CopyRist2    ElseIf response = MsgBoxResult.Cancel Then       Exit Sub    End If    Do Until i >= ListView1.Items.Count       If ListView1.Items(i).Checked = True Then          My.Computer.FileSystem.CopyFile(フォルダ1のパス & "\" & ListView1.Items(i).Text, _             フォルダ2のパス & "\" & ListView1.Items(i).Text, True)          ListView1.Items.RemoveAt(i)       Else          i = i + 1       End If    Loop CopyRist2:    i = 0    response = MsgBox("リスト2の選択ファイルをコピーしますか?", MsgBoxStyle.YesNoCancel, "確認")    If response = MsgBoxResult.No Then       Exit Sub    ElseIf response = MsgBoxResult.Cancel Then       Exit Sub    End If    Do Until i >= ListView2.Items.Count       If ListView2.Items(i).Checked = True Then          My.Computer.FileSystem.CopyFile(フォルダ2のパス & "\" & ListView2.Items(i).Text, _             フォルダ1のパス & "\" & ListView2.Items(i).Text, True)          ListView2.Items.RemoveAt(i)       Else          i = i + 1       End If    Loop 以上です。 よろしくお願いします。

専門家に質問してみよう