Send keypresses to X-Plane 11(windows 10) lazarus / 67-Windows ---------------------------------------------------------------------- xardomain · 2020-01-08 03:59 Hi, trying to send simple keystrokes to X-Plane 11 but it is not working. I am able to send them to notepad but X-Plane does not work, it just ignores them. procedure TForm1.Button5Click(Sender: TObject); var XplaneWindowHWND : HWND; begin   XplaneWindowHWND := findwindow('notepad',nil);  // This works //XplaneWindowHWND := findwindow('X-System',nil);  // this "works"   if (XplaneWindowHWND <> 0) then   begin     XplaneWindowHWND := FindWindowEx(XplaneWindowHWND, FindWindow('Edit', nil), nil, nil); // this works   //XplaneWindowHWND := FindWindowEx(XplaneWindowHWND, FindWindow('X-System', nil), nil, nil);  // this doesn't, not sure what to specify for FindWindo     SendMessage(XplaneWindowHWND, WM_CHAR, word('g'), 0);     Memo1.Lines.Add('Focused and sent char')   end   else     Memo1.Lines.Add('Failed to find the window') end; The example using notepad looks for a window(child window?) named "Edit", X-plane does not have any child window so I don't know how/if to use findwindow. Now, a simple autohotkey is able to send the keypress 'g' without any problem (using CTRL+J for example): ^j:: Send, g return So it is possible. What prevents me to send the keystrokes to the simulator? I have tried KeyInput.Press but nothing, it works only for notepad TIA Giuseppe Marullo Lazarus 2.0.6 / FPC 3.0.4 ---------------------------------------------------------------------- balazsszekely · 2020-01-08 06:16 According to your screenshot, X-Plane 11 doesn't have any childwindow.  Your only option is to send the keystroke to the main window(X-System). Also replace SendMessage to PostMessage, the later is an asynchronous function, it won't block the message queue: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  XplaneWindowHWND : HWND;begin  XplaneWindowHWND := FindWindow('X-System', nil);  if (XplaneWindowHWND <> 0) then  begin  PostMessage(XplaneWindowHWND, WM_CHAR, Word('g'), 0);    Memo1.Lines.Add('Focused and sent char')  end  else    Memo1.Lines.Add('Failed to find the window')  A slightly improved version would be the following, first find "XPlane 11" process, then find the process main window. Like this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses JwaWindows, jwatlhelp32; function GetProcessMainWindow(const PID: DWORD; const wFirstHandle: HWND): HWND;var  wHandle: HWND;  ProcID: DWord;begin  Result := 0;  wHandle := GetWindow(wFirstHandle, GW_HWNDFIRST);  while wHandle > 0 do  begin    GetWindowThreadProcessID(wHandle, @ProcID);    if (ProcID = PID) and (GetParent(wHandle) = 0) and (IsWindowVisible(wHandle)) then    begin      Result := wHandle;      Break;    end;    wHandle := GetWindow(wHandle, GW_HWNDNEXT);  end;end; function FindProcessByName(const ProcName:string): DWORD;var  Proc: TPROCESSENTRY32;  hSnap: HWND;  Looper: BOOL;begin  Result := 0;  Proc.dwSize := SizeOf(Proc);  hSnap := CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);  Looper := Process32First(hSnap, Proc);  while Integer(Looper) <> 0 do  begin    if UpperCase(ExtractFileName(proc.szExeFile)) = UpperCase(ProcName) then    begin      Result:=proc.th32ProcessID;      Break;    end;    Looper := Process32Next(hSnap, Proc);  end;  CloseHandle(hSnap);end; procedure TForm1.Button1Click(Sender: TObject);var  PID: DWord;  XplaneWindow: THandle;begin  PID := FindProcessByName('XSystem.exe'); //change this to the appropriate value(see task manager)  if PID <> 0 then  begin    XplaneWindow := GetProcessMainWindow(PID, Form1.Handle);    if XplaneWindow <> 0 then      PostMessage(XplaneWindow, WM_CHAR, Word('g'), 0);  end;end; ---------------------------------------------------------------------- xardomain · 2020-01-08 11:18 Hi Getmem, many thanks for your answer. However, both solutions don't work for me. This is the code now: procedure TForm1.Button5Click(Sender: TObject); var XplaneWindowHWND : HWND;      PID : DWORD;      XplaneWindow: THandle; begin   // Wait 3s to allow manual switch if desired   Form1.Timer4.Enabled := TRUE;   while Timer4.Enabled do         Application.Processmessages;   PID := FindProcessByName('X-Plane.exe');   if (PID <> 0) then   begin     Memo1.Lines.Add('Process found. PID is %d',[PID])  ;     XplaneWindow := GetProcessMainWindow(PID, Form1.Handle);     if (XplaneWindow <> 0) then     begin       Memo1.Lines.Add('Main Window found. Handle is %d',[XplaneWindow]);       PostMessage(XplaneWindow, WM_CHAR, Word('g'), 0)     end     else       Memo1.Lines.Add('Main Window NOT found.')  ; No effect. BTW this doesn't even work for notepad. ---------------------------------------------------------------------- balazsszekely · 2020-01-08 12:31 Quotemany thanks for your answer.You're welcome. QuoteHowever, both solutions don't work for me.It works fine at my side. What is your OS? Windows 10 is the most restrictive windows version so far. Maybe you should run your program with elevated privileges. QuoteNo effect. BTW this doesn't even work for notepad.It wasn't meant to work with notepad, notepad has a childwindow. As a last attempt please try this(don't forget to set Timer1.Interval to 5000, Timer1.Enabled to False by default, and run your program as administrator): Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses JwaWindows; procedure TForm1.Button1Click(Sender: TObject);begin  Timer1.Enabled := True; //allow to switch to XPlane 11end; procedure TForm1.Timer1Timer(Sender: TObject);var  Input: array [0..1] of TInput;begin  Timer1.Enabled := False;   ZeroMemory(@Input, SizeOf(Input));  Input[0].type_      := INPUT_KEYBOARD;  Input[0].ki.dwFlags := KEYEVENTF_UNICODE;  Input[0].ki.wVk     := VKKeyScan('g');   Input[1].type_      := INPUT_KEYBOARD;  Input[1].ki.dwFlags := KEYEVENTF_KEYUP;  Input[1].ki.wScan   := VKKeyScan('g');  SendInput(2, @Input[0], SizeOf(TInput));end;