Форум: "WinAPI";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Внизкак получить выделенный текст из активного окна? Найти похожие ветки
← →
Павел (2009-12-03 15:47) [0]Приветствую.
Есть приложение (моё). Допустим, оно свёрнуто в трей и дожидается нажатия горячей клавиши. Есть окно какого-то другого приложения. Пользователь выделяет текст в этом окне и нажимает горячую клавишу, после чего моё приложение должно получить выделенный текст.
Вот, собственно, и вопрос: как получить этот текст?
Подскажите, в какую сторону думать :)
← →
Игорь Шевченко © (2009-12-03 15:51) [1]две тонны баксов хочешь ? ;)
способ один - посылать окну WM_COPY, читать из Clipboard то, что туда скопировалось.
способ два - посылать окну назатия клавиш Ctrl+C, читать из Clipboard то, что туда поместилось
способ три - присоединять поток активного окна к себе, читать из активного текст любым нравящимся способом.
Найдешь работающее решение - выложи сюда
← →
Павел (2009-12-03 16:47) [2]при чем тут две тыщи?
← →
Leonid Troyanovsky © (2009-12-03 17:51) [3]
> Игорь Шевченко © (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.
← →
Leonid Troyanovsky © (2009-12-03 18:02) [4]
> Павел (03.12.09 15:47)
> Вот, собственно, и вопрос: как получить этот текст?
Из произвольного контрола не получить.
OCR только.
--
Regards, LVT.
← →
Павел (2009-12-03 18:13) [5]Может быть, действительно работать с буфером обмена?
Ведь если текст можно выделить, то и скопировать, как правило можно... :)
Уточню: мне нужен лишь голый текст, безо всякого форматирования. Буфер обмена для этих целей мне кажется наиболее подходящим пока.
← →
DVM © (2009-12-03 18:46) [6]
> Из произвольного контрола не получить.
Если произвольный контрол использует DrawText или TextOut, то не все так безнадежно, мне кажется. Но все равно непросто.
← →
Игорь Шевченко © (2009-12-03 19:58) [7]Павел (03.12.09 16:47) [2]
> при чем тут две тыщи?
Предлагали за подобную задачу
← →
Игорь Шевченко © (2009-12-03 20:00) [8]Leonid Troyanovsky © (03.12.09 17:51) [3]
Надо для любого окна, в котором можно выделить текст (например, на странице, открытой в произвольном браузере).
Я сделал в свое время для Edit/Richedit, через OpenOffice не прорвался, ну и через произвольный браузер тоже :)
← →
Павел (2009-12-04 13:31) [9]Вот есть такой вот вариантик, и даже работает:
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 ); //Send the C key (43 is "C")
keybd_event ($43, 0, KEYEVENTF_KEYUP, 0);
keybd_event (VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);// "Left Control Up
sleep(300);
ClipBoard:=TClipBoard.Create;
ShowMessage(ClipBoard.AsText);
ClipBoard.Destroy;
end;
End;
Очень странно, что без двух вызовов sleep не работает, буфер пуст.
Такое чувство, что буфер формируется далеко не быстро (считайте сами: 300+300=600 миллисекунд)
Кто-нибудь поделится мыслями, отчего так?
← →
clickmaker © (2009-12-04 13:33) [10]> Очень странно, что без двух вызовов sleep не работает, буфер
> пуст.
буфер-то заполняется в другом потоке и даже в другом процессе.
Вполне вероятно, что твой поток успевает проскочить до ClipBoard.AsText
← →
Игорь Шевченко © (2009-12-04 16:05) [11]
> Кто-нибудь поделится мыслями, отчего так?
SendMessageTimeout (чужое_окно, WM_NULL, ...) не поможет засинхронизироваться ? (Сам не пробовал, на уровне предположений)
← →
Павел (2009-12-06 19:27) [12]Я не понимаю, как оно может тут помочь? :)
← →
Игорь Шевченко © (2009-12-06 20:27) [13]Павел (06.12.09 19:27) [12]
Ну вроде как ты ждешь, пока другое окно не среагирует на твое сообщение. То есть, подразумевается, что на комбинацию клавиш "запихнуть в клипбоард" оно к тому времени уже среагировало
← →
Павел (2009-12-07 00:50) [14]Игорь, поясните, пожалуйста, на примере, как тут можно применить SendMessageTimeout. Я реально не понимаю :)
Если что, хэндл чужого окна у меня есть.
← →
Игорь Шевченко © (2009-12-07 02:03) [15]
> Игорь, поясните, пожалуйста, на примере, как тут можно применить
> SendMessageTimeout.
Не помогает (я все-таки попробовал). А Sleep помогает
← →
Eraser © (2009-12-07 18:12) [16]можно подвязать синхронизация на clipboard change notifications. и для защиты добавить выход, если событие не пришло в течение, допустим, 3 секунд.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.067 c