Search code examples
google-chromedelphidelphi-xe2notepadwindows-messages

SendMessage WM_COPY not working when sent to chrome window DELPHI


I've been trying to resolve this for weeks now. I'm trying to create an app in Delphi that runs in the background and catches any hot key and executes Ctrl + c. So what I did is I catch the hot key for example ALT + right arrow then simulate Ctrl + c and throw the command to the current window.

What I noticed is that when I try sending commands to Firefox like below:

SendMessage(FireFoxHandle, WM_COPY, 0, 0);
sleep(250);
CopiedText := ClipBoard.AsText;

Copying was successful and I get the expected text. But once I used the same line of codes to other windows like chrome(chrome_widget_1) or notepad, I can't get anything. So what I tried is get the child window of the chrome and notepad and try to send the command to the child window.

  1. Got "Chrome Legacy Window" as child of "chrome_widget_1" window but when i try to select a text in the tab, simulate the Ctrl + c, still not working.

  2. Found an example here in stackoverflow for sending wm_copy to notepad's child window which is an edit like the code below:

ParentWindw := FindWindow('Notepad',nil);
if ParentWindow <> 0 then
begin
  ChildWindow := FindWindowEx(ParentWindow, 0, 'Edit', nil);
  SendMessage(ChildWindow, WM_COPY, 0, 0);
  sleep(250);
  CopiedText := ClipBoard.AsText;
end;

The code works but is there any dynamic way to determine the child window that i need to use for the wm_copy command? I'm asking not only for the notepad window but for all possible window that can be used.

Or is there anyway where I can copy the highlighted text in any window Programmatically in Delphi specifically in xe2?

I already researched already like sendinput, keyevents and tried them but no luck. I'm running out of option how to make it work.

Thanks for any help in advance.


Solution

  • The MouseAndKeyInput code you presented in your accepted answer is just a wrapper for SendInput() on Windows, which I told you in comments to use 3 days ago. You can (and should) get rid of those 5 .pas files completely and replace those 3 separate KeyInput method calls with 1 call to SendInput(). It can send all 4 key inputs (Ctrl down, C down, C up, Ctrl up) atomically at 1 time (which is important to ensure other events don't get inter-mixed with your events), eg:

    var
      Inputs: array[0..3] of TInput;
    begin
      ZeroMemory(@Inputs, SizeOf(Inputs));
    
      Sleep(250);
    
      Inputs[0].type := INPUT_KEYBOARD;
      Inputs[0].ki.wVk := VK_CONTROL;
    
      Inputs[1].type := INPUT_KEYBOARD;
      Inputs[1].ki.wVk := Ord('C');
    
      Inputs[2].type := INPUT_KEYBOARD;
      Inputs[2].ki.wVk := Ord('C');
      Inputs[2].ki.dwFlags := KEYEVENTF_KEYUP;
    
      Inputs[3].type := INPUT_KEYBOARD;
      Inputs[3].ki.wVk := VK_CONTROL;
      Inputs[3].ki.dwFlags := KEYEVENTF_KEYUP;
    
      SendInput(4, Inputs, SizeOf(TInput));
    
      Sleep(250);
    
      Memo1.Lines.Add(Clipboard.AsText);
    end;
    

    Calling SendInput() with its cInputs parameter set to 1 (as KeyInput and MouseInput do) is almost always a bug in practice, and should only be done in rare situations.