Экспертная система Delphi.int.ru

Сообщество программистов
Общение, помощь, обмен опытом

Логин:
Пароль:
Регистрация | Забыли пароль?

Delphi.int.ru Expert

Другие разделы портала

Переход к вопросу:

#   

Статистика за сегодня:  


Лучшие эксперты

Подробнее »



Вопрос # 1 805

/ вопрос открыт /

Всем привет!
Наверняка многие пользуются Lingvo - довольно популярный словарь-переводчик. Так вот, в нём есть такая удивительная возможность: если зажать Ctrl и навести курсор на какой-либо текст, то появится окошко с переводом. Вопрос в следующем: как он это делает? Он читает текст практически отовсюду: из любого окна, любого элемента окна, заголовка окна - да откуда угодно. Как это реализовано? Как сделать нечто подобное? Кроме как распознавания скриншота части экрана ничего в голову не приходит. Но это очень сложный вариант и вряд ли там сделано именно так. Может у кого-то есть идеи?

Sunshine Вопрос ожидает решения (принимаются ответы, доступен мини-форум)

Вопрос задал: Sunshine (статус: Посетитель)
Вопрос отправлен: 7 августа 2008, 10:17
Состояние вопроса: открыт, ответов: 0.


Мини-форум вопроса

Всего сообщений: 7; последнее сообщение — 28 октября 2008, 18:28; участников в обсуждении: 3.
Вадим К

Вадим К (статус: Академик), 7 августа 2008, 11:25 [#1]:

там используются хуки. а в тако случае длл для хука находиться внутри каждого запущенного процесса. А если находишся внутри процесса, то это заметно упрощает задачу - теперь стают доступны многие функции (ваша длл стаёт как бы частью каждой программы).
После этого задача своиться к простым действиям
- узнать, что за окно под курсором,
- с помощью GetText или аналогов узять текст (для некоторых окон могут быть варианты. кнопка - это ведь в понимании Windows тоже окно).
- по координатам рассчитать какое именно слово выделил пользователь. В некоторых случаях это можно сделать только узнав размер шрифта и сделав ручную прорисовку в памяти. это самая сложная часть с всего этого (ну кроме собственно перевода)
Галочка "подтверждения прочтения" - вселенское зло.
Sunshine

Sunshine (статус: Посетитель), 7 августа 2008, 12:03 [#2]:

А хуки на что именно?
Порядок запуска ведь не важен - можно сначала запустить браузер, потом Lingvo и всё равно будет работать. Как можно dll подцепить к работающей программе? Да и вообще я не совсем понял об этом "нахождении внутри процесса" - это уже получается внедрение в чужую память. Можно поподробнее?
Вадим К

Вадим К (статус: Академик), 7 августа 2008, 12:16 [#3]:

именно через хук и можно подцепить.
да, в результате длл будет находиться в каждом процессе. она может обращаться к памяти процесса. Но тут и проблема - на самом деле получается, что одновременно код длл исполняется в каждом процессе. И для того, что бы обмениваться данными между ними, надо уже использовать специальные средства.
Галочка "подтверждения прочтения" - вселенское зло.
Sunshine

Sunshine (статус: Посетитель), 7 августа 2008, 19:42 [#4]:

Как я понимаю, воплотить это самостоятельно практически нереально?
Вадим К

Вадим К (статус: Академик), 7 августа 2008, 23:50 [#5]:

всё реально. Просто взять текст с текущего элемента (окна, если корректней) просто. Сделаю маленький презентик. попробуйте следующий код.
type
// *********************************************************************//
// Interface: IAccessible
// Flags:     (4432) Hidden Dual OleAutomation Dispatchable
// GUID:      {618736E0-3C3D-11CF-810C-00AA00389B71}
// *********************************************************************//
  IAccessible = interface(IDispatch)
    ['{618736E0-3C3D-11CF-810C-00AA00389B71}']
    function Get_accParent: IDispatch; safecall;
    function Get_accChildCount: Integer; safecall;
    function Get_accChild(varChild: OleVariant): IDispatch; safecall;
    function Get_accName(varChild: OleVariant): WideString; safecall;
    function Get_accValue(varChild: OleVariant): WideString; safecall;
    function Get_accDescription(varChild: OleVariant): WideString; safecall;
    function Get_accRole(varChild: OleVariant): OleVariant; safecall;
    function Get_accState(varChild: OleVariant): OleVariant; safecall;
    function Get_accHelp(varChild: OleVariant): WideString; safecall;
    function Get_accHelpTopic(out pszHelpFile: WideString; varChild: OleVariant): Integer; safecall;
    function Get_accKeyboardShortcut(varChild: OleVariant): WideString; safecall;
    function Get_accFocus: OleVariant; safecall;
    function Get_accSelection: OleVariant; safecall;
    function Get_accDefaultAction(varChild: OleVariant): WideString; safecall;
    procedure accSelect(flagsSelect: Integer; varChild: OleVariant); safecall;
    procedure accLocation(out pxLeft: Integer; out pyTop: Integer; out pcxWidth: Integer; 
                          out pcyHeight: Integer; varChild: OleVariant); safecall;
    function accNavigate(navDir: Integer; varStart: OleVariant): OleVariant; safecall;
    function accHitTest(xLeft: Integer; yTop: Integer): OleVariant; safecall;
    procedure accDoDefaultAction(varChild: OleVariant); safecall;
    procedure Set_accName(varChild: OleVariant; const pszName: WideString); safecall;
    procedure Set_accValue(varChild: OleVariant; const pszValue: WideString); safecall;
    property accParent: IDispatch read Get_accParent;
    property accChildCount: Integer read Get_accChildCount;
    property accChild[varChild: OleVariant]: IDispatch read Get_accChild;
    property accName[varChild: OleVariant]: WideString read Get_accName write Set_accName;
    property accValue[varChild: OleVariant]: WideString read Get_accValue write Set_accValue;
    property accDescription[varChild: OleVariant]: WideString read Get_accDescription;
    property accRole[varChild: OleVariant]: OleVariant read Get_accRole;
    property accState[varChild: OleVariant]: OleVariant read Get_accState;
    property accHelp[varChild: OleVariant]: WideString read Get_accHelp;
    property accHelpTopic[out pszHelpFile: WideString; varChild: OleVariant]: Integer read Get_accHelpTopic;
    property accKeyboardShortcut[varChild: OleVariant]: WideString read Get_accKeyboardShortcut;
    property accFocus: OleVariant read Get_accFocus;
    property accSelection: OleVariant read Get_accSelection;
    property accDefaultAction[varChild: OleVariant]: WideString read Get_accDefaultAction;
  end;
 
function AccessibleObjectFromPoint(Pt: TPoint; var Acc: IAccessible; var Child: Variant): HRESULT;
stdcall; external 'OleAcc.dll' name 'AccessibleObjectFromPoint';
 
var
OldPoint: TPoint;
 
procedure TForm1.Timer1Timer(Sender: TObject);
var
 P: TPoint;
 A: IAccessible;
 V: Variant;
begin
 if GetCursorPos(P) and ((P.X <> OldPoint.X) or (P.Y <> OldPoint.Y)) then
 begin
   OldPoint := P;
   if Succeeded(AccessibleObjectFromPoint(P, A, V)) then begin
     Memo1.Lines.Text := A.accName[V];
     Caption := A.accDescription[V];
   end
   else
     Memo1.Lines.Text := ''
 end
end;
Изучите код, у него есть большой потенциал.
Галочка "подтверждения прочтения" - вселенское зло.
Sunshine

Sunshine (статус: Посетитель), 12 августа 2008, 11:31 [#6]:

Да, действительно, довольно мощный код! Забирает текст из многих мест. Большое спасибо! Это уже многое!
lzt

lzt (статус: Посетитель), 28 октября 2008, 18:28 [#7]:

а не подскажите, как определить координаты и длинну/высоту, элемента, из которого берется текст.
то есть. взять эти величины и расчитать над какой БУКВОЙ находиться курсор.

Чтобы оставлять сообщения в мини-форумах, Вы должны авторизироваться на сайте.

Версия движка: 2.6+ (26.01.2011)
Текущее время: 22 февраля 2025, 11:39
Выполнено за 0.03 сек.