Конференция "WinAPI" » как получить выделенный текст из активного окна?
 
  • Павел (03.12.09 15:47) [0]
    Приветствую.
    Есть приложение (моё). Допустим, оно свёрнуто в трей и дожидается нажатия горячей клавиши. Есть окно какого-то другого приложения. Пользователь выделяет текст в этом окне и нажимает горячую клавишу, после чего моё приложение должно получить выделенный текст.
    Вот, собственно, и вопрос: как получить этот текст?
    Подскажите, в какую сторону думать :)
  • Игорь Шевченко © (03.12.09 15:51) [1]
    две тонны баксов хочешь ? ;)

    способ один - посылать окну WM_COPY, читать из Clipboard то, что туда скопировалось.
    способ два - посылать окну назатия клавиш Ctrl+C, читать из Clipboard то, что туда поместилось
    способ три - присоединять поток активного окна к себе, читать из активного текст любым нравящимся способом.

    Найдешь работающее решение - выложи сюда
  • Павел (03.12.09 16:47) [2]
    при чем тут две тыщи?
  • Leonid Troyanovsky © (03.12.09 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 © (03.12.09 18:02) [4]

    > Павел   (03.12.09 15:47)  

    > Вот, собственно, и вопрос: как получить этот текст?

    Из произвольного контрола не получить.
    OCR только.

    --
    Regards, LVT.
  • Павел (03.12.09 18:13) [5]
    Может быть, действительно работать с буфером обмена?
    Ведь если текст можно выделить, то и скопировать, как правило можно... :)
    Уточню: мне нужен лишь голый текст, безо всякого форматирования. Буфер обмена для этих целей мне кажется наиболее подходящим пока.
  • DVM © (03.12.09 18:46) [6]

    > Из произвольного контрола не получить.

    Если произвольный контрол использует DrawText или TextOut, то не все так безнадежно, мне кажется. Но все равно непросто.
  • Игорь Шевченко © (03.12.09 19:58) [7]
    Павел   (03.12.09 16:47) [2]


    > при чем тут две тыщи?


    Предлагали за подобную задачу
  • Игорь Шевченко © (03.12.09 20:00) [8]
    Leonid Troyanovsky ©   (03.12.09 17:51) [3]

    Надо для любого окна, в котором можно выделить текст (например, на странице, открытой в произвольном браузере).

    Я сделал в свое время для Edit/Richedit, через OpenOffice не прорвался, ну и через произвольный браузер тоже :)
  • Павел (04.12.09 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 © (04.12.09 13:33) [10]
    > Очень странно, что без двух вызовов sleep не работает, буфер
    > пуст.

    буфер-то заполняется в другом потоке и даже в другом процессе.
    Вполне вероятно, что твой поток успевает проскочить до ClipBoard.AsText
  • Игорь Шевченко © (04.12.09 16:05) [11]

    > Кто-нибудь поделится мыслями, отчего так?


    SendMessageTimeout (чужое_окно, WM_NULL, ...) не поможет засинхронизироваться ? (Сам не пробовал, на уровне предположений)
  • Павел (06.12.09 19:27) [12]
    Я не понимаю, как оно может тут помочь? :)
  • Игорь Шевченко © (06.12.09 20:27) [13]
    Павел   (06.12.09 19:27) [12]

    Ну вроде как ты ждешь, пока другое окно не среагирует на твое сообщение. То есть, подразумевается, что на комбинацию клавиш "запихнуть в клипбоард" оно к тому времени уже среагировало
  • Павел (07.12.09 00:50) [14]
    Игорь, поясните, пожалуйста, на примере, как тут можно применить SendMessageTimeout. Я реально не понимаю :)

    Если что, хэндл чужого окна у меня есть.
  • Игорь Шевченко © (07.12.09 02:03) [15]

    > Игорь, поясните, пожалуйста, на примере, как тут можно применить
    > SendMessageTimeout.


    Не помогает (я все-таки попробовал). А Sleep помогает
  • Eraser © (07.12.09 18:12) [16]
    можно подвязать синхронизация на clipboard change notifications. и для защиты добавить выход, если событие не пришло в течение, допустим, 3 секунд.
 
Конференция "WinAPI" » как получить выделенный текст из активного окна?
Есть новые Нет новых   [134431   +16][b:0][p:0.003]