Wysyłanie dwóch klawiszy z klawiatury do aplikacji

0

Witam.

Chciałbym wiedzieć jak wysyłać dwa klawisze z klawiatury do aplikacji (np. ctrl+przycisk w dół). Chodzi o to, by było to wciśnięte w tym samym czasie.
Próbowałem dużo, ale wygląda na to, że pierw wysyłana jest wiadomość z controlem, później z klawiszem w dół.

Mam taki kod:

function twokeys(x :string): string;
var
  i : integer;
  z : integer;
begin
  i := 0;
  z:= 0;
begin

if x = 'twokeys' then
i := 17;
z := 40;


SendMessage(h, WM_KEYdown, i, 0);
SendMessage(h, WM_KEYdown, z, 0);
SendMessage(h, WM_KEYUP, z, 0);
SendMessage(h, WM_KEYUP, i, 0);
end;
end;

Kombinowałem jeszcze tak:

var
Inputs:array[0..3] of tagInput;
ProcessID: Cardinal;

begin

GetWindowThreadProcessId(FindWindow('notepad',Nil), @ProcessID);
ZeroMemory(@Inputs, sizeof(Inputs));

Inputs[0].Itype:=INPUT_KEYBOARD;
Inputs[0].ki.wVK:=VK_LCONTROL;

Inputs[1].Itype:=INPUT_KEYBOARD;
Inputs[1].ki.wVK:=VK_DOWN;


SendInput(length(Inputs), Inputs[0], sizeof(Inputs[0]));

end;

Niby działa, ale nie konkretnie w aplikacji, lecz wszędzie... Da się zrobić tak, by to tylko do aplikacji wysyłało te czynności?

0

Niby działa, ale nie konkretnie w aplikacji, lecz wszędzie...

działa wszędzie ponieważ :
"The SendInput function inserts the events in the INPUT structures serially into the keyboard or mouse input stream."

0

Tutaj masz przykład z SendInputhttps://stackoverflow.com/a/15853761
Tutaj przykład z PostMessagehttps://stackoverflow.com/a/11251976 (+ ostatni komentarz pod tym postem).

0
begin
PostMessage(h, WM_SYSKEYDOWN, VK_LCONTROL, 0);
PostMessage(h, WM_KEYDOWN, ord('S'), 0);
PostMessage(h, WM_KEYUP, ord('S'), 0);
PostMessage(h, WM_SYSKEYUP, VK_LCONTROL, 0);
end;

Nie działa mi to.

PostMessage(h, WM_KEYUP, ord('S'), $C0000000)
PostMessage(h, WM_SYSKEYUP, VK_MENU, $C0000000)

To też nie.

0

a co masz pod zmienną h ?
być może wysyłasz komunikaty w kosmos zamiast do aplikacji
h musi być uchwytem obiektu do którego adresujesz komunikat

0
procedure Hook;
begin;
H := FindWindow( 'App', nil );
if H < 1 then
begin
application.Title:='ERROR';
Form1.Timer1.Enabled := false;
ShowMessage( 'Run App first!' );
application.Terminate;
end else begin
Form1.Timer1.Enabled := true;
end;
end;
```
To akurat działa, bo jak chcę wysłać jeden przycisk np. chcę, by napisało mi samo 's' to mi je napisze. Jak zrobię żeby mi go wysłało 10 x to też go tyle razy wyśle. Niestety nie działa to jak chcę wysłać ctrl + s na raz.
0

Rozumiem, ale formatuj kod zamieszczany w postach. Nikt nie będzie śledził które begin domyka się z end

procedure Hook;
begin
  H := FindWindow('App', nil);
  if H < 1 then
  begin
    application.Title := 'ERROR';
    Form1.Timer1.Enabled := false;
    ShowMessage('Run App first!');
    application.Terminate;
  end
  else
  begin
    Form1.Timer1.Enabled := true;
  end;
end;
1

Do "wciśnięcia" klawiszy Ctrl, Alt, Shift możesz użyć funkcji SetKeyboardState w przykładzie Ctrl + A , Handle to uchwyt okna do którego wysyłamy kombinację klawiszy.

var
  KeybState: array [0..1] of TKeyboardState;
  Key: Word;
  lParam: Longint;
begin
  FillChar(KeybState[0], SizeOf(TKeyboardState), 0); //wyczerowac pamiec
  GetKeyboardState(KeybState[1]); //zapamietac stary stan klawiatury

  Key:= Ord('A'); // A
  KeybState[0][VK_CONTROL]:= $80; // CTRL

  SetKeyboardState(KeybState[0]); //wcisniety CTRL

  lParam:= MakeLong(0, MapVirtualKey(Key, 0));
  PostMessage(Handle, WM_KEYDOWN, Key, lParam);  //wyslanie klawisza
  PostMessage(Handle, WM_KEYUP, Key, lParam);

  Application.ProcessMessages; //WAŻNE program musi przetworzyc kolejkę a jak do innej apki to SendMessage chyba bedzie lepsze

  SetKeyboardState(KeybState[1]); //przywrócenie starego stanu klawiatury
end;
0

Dobra może tak. Zrobiłem nowy projekt i chcę, by w notatniku zamiast "s" robiło się shift + s tak, żeby była to wielka literka "S".

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  h, edit:hwnd;

implementation

{$R *.dfm}

procedure Hook;
begin

  H := FindWindow('notepad', nil);
  edit := FindWindowEx(h, FindWindow('Edit', nil), nil, nil);


  if H < 1 then
  begin
    application.Title := 'ERROR';
    ShowMessage('Run App first!');
    application.Terminate;
  end;
end;




Procedure TwoKeys;
var
  KeybState: array [0..1] of TKeyboardState;
  Key: Word;
  lParam: Longint;
begin
  FillChar(KeybState[0], SizeOf(TKeyboardState), 0); //wyzerowac pamiec
  GetKeyboardState(KeybState[1]); //zapamietac stary stan klawiatury

  KeybState[0][VK_Shift]:= $80; // CTRL
  Key:= Ord('S'); // S


  SetKeyboardState(KeybState[0]); //wcisniety CTRL

  lParam:= MakeLong(0, MapVirtualKey(Key, 0));
  PostMessage(Edit, WM_KEYDOWN, Key, lParam);  //wyslanie klawisza
  PostMessage(Edit, WM_KEYUP, Key, lParam);

  Application.ProcessMessages; //WAŻNE program musi przetworzyc kolejkę a jak do innej apki to można dac  troche czasu (np Sleep(200));

  SetKeyboardState(KeybState[1]); //przywrócenie starego stanu klawiatury
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  hook;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin

end;


procedure TForm1.Button2Click(Sender: TObject);
begin
TwoKeys;
end;


end.

Sami zobaczcie jak to działa.

0

Znajdzie się jakiś tęgi umysł, który podoła?

4

Myślałem że ktoś się wcześniej zgłosi ale skoro dalej bez odpowiedzi to proszę, lubię wyzwania.
Tu jest wszystko http://www.swissdelphicenter.ch/en/showcode.php?id=220
a tutaj clue zagadki

 * NOTE:
 *  Setting the keyboard state will not work across applications
 *  running in different memory spaces on Win32 unless AttachThreadInput
 *  is used to connect to the target thread first.
Procedure TwoKeys;
var
  KeybState: array [0..1] of TKeyboardState;
  Key: Word;
  lParam: Longint;
  FAppThreadID : Cardinal;
begin
  FAppThreadID := GetWindowThreadProcessId(edit, nil);
  AttachThreadInput(GetCurrentThreadId, FAppThreadID, True);

  FillChar(KeybState[0], SizeOf(TKeyboardState), 0); //wyzerowac pamiec
  GetKeyboardState(KeybState[1]); //zapamietac stary stan klawiatury

  KeybState[0][VK_Shift]:= $80; // CTRL
  Key:= Ord('S'); // S

  SetKeyboardState(KeybState[0]); //wcisniety CTRL

  lParam:= MakeLong(0, MapVirtualKey(Key, 0));

  PostMessage(Edit, WM_KEYDOWN, Key, lParam);  //wyslanie klawisza
  PostMessage(Edit, WM_KEYUP, Key, lParam or $C0000000);

  Application.ProcessMessages; //WAŻNE program musi przetworzyc kolejkę a jak do innej apki to można dac  troche czasu (np Sleep(200));

  SetKeyboardState(KeybState[1]); //przywrócenie starego stanu klawiatury
end;

Niestety rozwiązanie bardziej wygooglowane niż wymyślone ale sklecone na podstawie 3 stron i działa :)

0

Po dodaniu jednego sleepu działa idealnie. Dziękuję bardzo. Temat można zamknąć, bo jest on już rozwiązany.

1 użytkowników online, w tym zalogowanych: 0, gości: 1