Entwickler-Ecke

Windows API - STRG+C an fremde Anwendung senden / markierten Text kopieren


N8Falter74 - Mo 06.03.06 12:57
Titel: STRG+C an fremde Anwendung senden / markierten Text kopieren
Hallo Forum,

bevor jetzt wieder einige auf die Suche verweisen, die habe ich jetzt mehr als 30 min benutzt und noch nicht den richtigen tipp gefunden.

Also folgendes Problem:

Ich möchte mit einem kleinen Tool auf ein bestimmtes HotKey reagieren (STRG+S) und dann eine Datenbanksuche ausführen.
Das klappt auch soweit schon. Der Suchbegriff soll das aktuell markierte Wort/Satz usw. in der aktiven Anwendung sein.
Beispiel: In einer eMail markiere ich eine Telefonnummer und mit STRG+S sucht meine Anwendung zB. den Namen des Inhabers raus.

Zuerst habe ich das so versucht:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
procedure FindActiveControl;
var hWindow: HWND;
    Pid1, Pid2: Cardinal;
begin
  Pid1 := GetWindowThreadProcessId(Application.Handle);
  Pid2 := GetWindowThreadProcessId(GetForeGroundWindow);
  if AttachThreadInput(Pid1, Pid2, True) then
  begin
    hWindow := GetFocus;
    SendMessage(hWindow, WM_COPY, 00);
    memo1.PasteFromClipboard;
  end;
  AttachThreadInput(Pid1, Pid2, False);
end;


Doch leider reagieren nur Edits und Comboboxen auf die Windows Message WM_COPY. Ich könnte jetzt natürlich alle Controls extra behandeln, aber das ist ja nie vollständig. Deshalb möchte lieber ein STRG+C an das Control senden, das ist zwar nicht so richtig professionell aber jedes Control das STRG+C unterstützt, sollte dann funktionieren.

Ich habe dann das SendMessage(hWindow, WM_COPY, 0, 0); durch folgendes ersetzt:


Delphi-Quelltext
1:
2:
3:
4:
    SendMessage(hWindow, WM_KEYDOWN, VK_CONTROL, 0);
    SendMessage(hWindow, WM_KEYDOWN, Ord('C'), 0);
    SendMessage(hWindow, WM_KEYUP, Ord('C'), 0);
    SendMessage(hWindow, WM_KEYUP, VK_CONTROL, 0);


Das funktioniert aber so nicht. Hat jemand eine Idee warum? Oder wie ich das eleganter lösen kann? :gruebel:

grüße
Sebastian


digi_c - Mo 06.03.06 15:03

Die werden doch nacheinander gesendet und nicht STRG+C gleichzeit, oder?


N8Falter74 - Mo 06.03.06 15:44

user profile icondigi_c hat folgendes geschrieben:
Die werden doch nacheinander gesendet und nicht STRG+C gleichzeit, oder?


Sorry aber wie meinst du das :?:

Wenn ich einen Text irgendwo markiere und möchte den in die Zwischenablage kopieren, dann muß ich doch STRG drücken, dann dazu die Taste 'C' und dann beide loslassen. Oder?

Das wollte ich jedenfalls so simulieren.

Ich bin beim googlen darauf gestoßen, dass die KeyDown und KeyUp Messages nur als Reaktion auf einen Tastendruck in die Message Queue gestellt werden, das Fenster/Control selber reagiert aber nicht auf diese Messages. Ob das so richtig ist, habe ich leider auch nicht feststellen können. Das Platform SDK ist jedenfalls nicht gerade einfach zu lesen :-)

Es gibt auch noch eine WM_HOTKEY Message, aber diese bringt auch nicht die gewünschte Reaktion. Weder auf das Handle des Applications Fenster noch auf das Fensterhandle des Controls. :-(

Man kann wohl auch per SendInput direkt in den Tastaturpuffer schreiben, aber das wollte ich nur als letzte Möglichkeit verwenden, da man dabei nicht mehr das empfangende Fenster festlegen kann.

Hat jemand noch eine idee?

grüße
Sebastian


N8Falter74 - Mo 06.03.06 17:07

Ich hab eine Lösung gefunden:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
procedure FindActiveControl;
var hWindow: HWND;
    Pid1, Pid2: Cardinal;
    lParam: LongInt;
    ksNew, ksOld: TKeyboardState;
begin
  // PIDs von Quell und Zielanwendung finden
  Pid1 := GetWindowThreadProcessId(Application.Handle);
  Pid2 := GetWindowThreadProcessId(GetForeGroundWindow);
  
  // beide Thread-Message-Queues zusammenschalten
  if AttachThreadInput(Pid1, Pid2, True) then
  begin
    // aktives Fenster/Control finden
    hWindow := GetFocus;  
    // lParam mit Virtuellen Tastencode 'c' vorbereiten
    lParam := MakeLong(0, MapVirtualKey($430));
    // Neuen Keyboardstate STRG-gedrückt vorbereiten
    ksNew[VK_CONTROL] := $80;
    // alten Keyboardstate sichern
    GetKeyboardState(ksOld);
    // neuen Keyboardstate setzen
    SetKeyboardState(ksNew);
    // Taste 'C' wurde gedrückt - senden
    PostMessage(hWindow, WM_KEYDOWN, $43, lParam);
    // Taste 'C' wurde losgelassen - senden ($C0000000 setzt auch diesen Status für lParam)
    PostMessage(hWindow, WM_KEYUP, $43, lParam or $C0000000);
    // Anwendung soll Message-Queue verarbeiten
    Application.ProcessMessages;
    // zur Sicherheit nochmal 100ms warten (kann ggf. entfernt werden)
    Sleep(100);
    // Zwischenablage in Memo-Kopieren
    memo1.PasteFromClipboard;
    // alten Keyboardstate wiederherstellen
    SetKeyboardState(ksOld);
  end;
  // Threads-Messages-Queues wieder trennen
  AttachThreadInput(Pid1, Pid2, False);
end;


Hab ich natürlich nicht komplett alleine gefunden ;-) Dank dem Board, dem Platform SDK und diesem Link http://www.delphi-forum.de/viewtopic.php?t=36449&highlight=sendmessage war es dann doch ganz einfach :grin:

grüße
Sebastian