-
Приветствую. Есть приложение (моё). Допустим, оно свёрнуто в трей и дожидается нажатия горячей клавиши. Есть окно какого-то другого приложения. Пользователь выделяет текст в этом окне и нажимает горячую клавишу, после чего моё приложение должно получить выделенный текст. Вот, собственно, и вопрос: как получить этот текст? Подскажите, в какую сторону думать :)
-
две тонны баксов хочешь ? ;)
способ один - посылать окну WM_COPY, читать из Clipboard то, что туда скопировалось. способ два - посылать окну назатия клавиш Ctrl+C, читать из Clipboard то, что туда поместилось способ три - присоединять поток активного окна к себе, читать из активного текст любым нравящимся способом.
Найдешь работающее решение - выложи сюда
-
при чем тут две тыщи?
-
> Игорь Шевченко © (03.12.09 15:51) [1] > Найдешь работающее решение - выложи сюда
Я когда-то похожим пользовался. Ну, конечно, это только для EDIT, а, скажем, RICHEDIT не пройдет, бо "новые" контролы не маршаллят всякие EM_GETSEL. В ярлыке делал горячую клавишу, f.e., ctrl-alt-z, функция м.б. любой (я перекодировку делал).
program prfxline;
uses
Windows,
Messages;
const
buflen = $FFFF;
procedure InsertPrefixToLines(EditHandle: HWND; const prefx: String);
var
i, idx : Longint;
Source : array [0..buflen] of Char;
Dest: array [0..buflen] of Char;
Sel, Len : DWord;
StartSel, EndSel: Word;
begin
Len := SendMessage( EditHandle,
WM_GETTEXT,
SizeOf(Source),
LParam(PChar(@Source[0])));
Sel := SendMessage( EditHandle,
EM_GETSEL,
0,
0);
StartSel := LoWord(Sel);
EndSel := HiWord(Sel);
if (StartSel = 0) and (EndSel = -1) then
EndSel:= Len;
if StartSel = -1 then
Exit;
move(prefx[1], Dest[0], Length(prefx));
idx := Length(prefx);
i:= StartSel;
while i < EndSel do
begin
case Source[i] of
#13:
begin
Dest[idx] := #13;
Dest[idx+1] := #10;
move(prefx[1], Dest[idx+2], Length(prefx));
inc(idx, Length(prefx)+2);
inc(i);
if Source[i] = #10 then
inc(i);
end;
else
begin
Dest[idx] := Source[i];
inc(idx);
inc(i);
end;
end;
end;
SendMessage(EditHandle, EM_REPLACESEL, WParam(True), LParam(PChar(@Dest[0])));
end;
const
prefix: String = ' ';
var
happ: HWND;
tid : DWord;
handles: array [0..0] of THandle;
begin
happ:= GetForegroundWindow;
tid := GetWindowThreadProcessID(happ, nil);
if ParamCount > 0 then
prefix := ParamStr(1);
MsgWaitForMultipleObjects(0, handles, false, 0, QS_POSTMESSAGE);
AttachThreadInput(tid, GetCurrentThreadID, true);
try
InsertPrefixToLines(GetFocus, prefix);
finally
AttachThreadInput(tid, GetCurrentThreadID, false);
end;
end.
-- Regards, LVT.
-
> Павел (03.12.09 15:47)
> Вот, собственно, и вопрос: как получить этот текст?
Из произвольного контрола не получить. OCR только.
-- Regards, LVT.
-
Может быть, действительно работать с буфером обмена? Ведь если текст можно выделить, то и скопировать, как правило можно... :) Уточню: мне нужен лишь голый текст, безо всякого форматирования. Буфер обмена для этих целей мне кажется наиболее подходящим пока.
-
> Из произвольного контрола не получить.
Если произвольный контрол использует DrawText или TextOut, то не все так безнадежно, мне кажется. Но все равно непросто.
-
Павел (03.12.09 16:47) [2]
> при чем тут две тыщи?
Предлагали за подобную задачу
-
Leonid Troyanovsky © (03.12.09 17:51) [3]
Надо для любого окна, в котором можно выделить текст (например, на странице, открытой в произвольном браузере).
Я сделал в свое время для Edit/Richedit, через OpenOffice не прорвался, ну и через произвольный браузер тоже :)
-
Вот есть такой вот вариантик, и даже работает: Procedure TRuForm.WMHotkey( Var msg: TWMHotkey );
var happ: HWND;
Begin
if msg.HotKey=2 then
begin
sleep(300);
keybd_event(VK_CONTROL,0,0,0);
keybd_event ($43, 0, 0, 0 ); keybd_event ($43, 0, KEYEVENTF_KEYUP, 0);
keybd_event (VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
sleep(300);
ClipBoard:=TClipBoard.Create;
ShowMessage(ClipBoard.AsText);
ClipBoard.Destroy;
end;
End; Очень странно, что без двух вызовов sleep не работает, буфер пуст. Такое чувство, что буфер формируется далеко не быстро (считайте сами: 300+300=600 миллисекунд) Кто-нибудь поделится мыслями, отчего так?
-
> Очень странно, что без двух вызовов sleep не работает, буфер > пуст.
буфер-то заполняется в другом потоке и даже в другом процессе. Вполне вероятно, что твой поток успевает проскочить до ClipBoard.AsText
-
> Кто-нибудь поделится мыслями, отчего так?
SendMessageTimeout (чужое_окно, WM_NULL, ...) не поможет засинхронизироваться ? (Сам не пробовал, на уровне предположений)
-
Я не понимаю, как оно может тут помочь? :)
-
Павел (06.12.09 19:27) [12]
Ну вроде как ты ждешь, пока другое окно не среагирует на твое сообщение. То есть, подразумевается, что на комбинацию клавиш "запихнуть в клипбоард" оно к тому времени уже среагировало
-
Игорь, поясните, пожалуйста, на примере, как тут можно применить SendMessageTimeout. Я реально не понимаю :)
Если что, хэндл чужого окна у меня есть.
-
> Игорь, поясните, пожалуйста, на примере, как тут можно применить > SendMessageTimeout.
Не помогает (я все-таки попробовал). А Sleep помогает
-
можно подвязать синхронизация на clipboard change notifications. и для защиты добавить выход, если событие не пришло в течение, допустим, 3 секунд.
|