Как узнать, существует ли каре [в опере]?

Я пытаюсь решить следующую задачу: у меня есть браузер OPERA, и я хочу узнать, существует ли каретка (текстовый курсор) в любое время. Например, я нажимаю на адресную строку, и я хочу знать, что каретка сейчас мигает. Затем я нажимаю на пустое место на странице и знаю, что курсора нет.

Другими словами, я хочу определить, что какой-то текстовый элемент сейчас находится в фокусе.

Я знаю, как решить эту задачу во многих приложениях, некоторые из них используют стандартные элементы управления Windows, такие как Edit, поэтому я могу получить сфокусированное окно и проверить его класс с помощью WinApi.

В других приложениях, где элементы управления отображаются без собственных окон, я могу получить это с помощью пользовательского интерфейса автоматизации.

Но, к моему сожалению, Opera имеет только одно главное окно и не предоставляет доступа к технологии автоматизации пользовательского интерфейса.

Итак, кто-нибудь знает, как приблизиться к моей цели?)

РЕДАКТИРОВАТЬ:

Спасибо за Эрика Брауна, это решение проблемы:

// ConsoleForMSAA.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <OleAcc.h>
#include <iostream>

#pragma comment (lib, "oleacc.lib")

void ProcessCaretPos(HWND hwnd);

int _tmain(int argc, _TCHAR* argv[])
{

    for (;;)
    {
        // active toplevel window
        HWND hwnd = GetForegroundWindow();

        // current thread
        DWORD currentThreadId = GetCurrentThreadId();

        DWORD targetThreadId, targetProcessId;

        // target process and thread
        targetThreadId = GetWindowThreadProcessId(hwnd, &targetProcessId); 

        // attach current thread to target thread messaging queue
        BOOL attached = AttachThreadInput(currentThreadId, targetThreadId, true);

        // что это даст? Мы участвуем в обработке сообщений того потока
        // и все сис. вызовы, которые мы сделаем, будут посланы от имени того потока.
        if (attached)
        {
            try
            {
                // get focused window handle (focused child that of toplevel window)
                HWND targetWindow = GetFocus();

                // some procedure 
                ProcessCaretPos(targetWindow);
            }
            catch(...) {;}

            AttachThreadInput(currentThreadId, targetThreadId, false);
        }

        Sleep(1000);
    }
    return 0;
}

// 
void ProcessCaretPos(HWND hwnd)
{
    IAccessible *pAccCaret = NULL;

    VARIANT varCaret;
    RECT rcCaret;
    varCaret.vt = VT_I4;
    varCaret.lVal = CHILDID_SELF;

    if (SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_CARET, IID_IAccessible, (void **)&pAccCaret)))
    {
        HRESULT hr = pAccCaret->accLocation( &rcCaret.left, &rcCaret.top, &rcCaret.right, &rcCaret.bottom, varCaret);

        if (!hr)
        {
            std::cout << "caret positon: " << rcCaret.left << " " << rcCaret.top << " " << rcCaret.right << " " << rcCaret.bottom << "\n";
        }
        else
            std::cout << "there is nothing carets" << "\n"; 

        pAccCaret->Release();
    }
}

person Alex141    schedule 09.08.2013    source источник


Ответы (1)


Вам наверное не повезло. Однако, если Opera использует системный знак вставки (чего может и не быть, например, в IE), вы можете попробовать использовать MSAA для запроса местоположения системного знака вставки:

IAccessible *pAccCaret = NULL;

VARIANT varCaret;
RECT rcCaret;
varCaret.vt = VT_I4;
varCaret.lVal = CHILDID_SELF;

if (SUCCEEDED(AccessibleObjectFromWindow(hwnd, OBJID_CARET, IID_IAccessible, (void **)&pAccCaret)))
{
     hr = pAccCaret->accLocation( &rcCaret.left, &rcCaret.top, &rcCaret.right, &rcCaret.bottom, varCaret);

     pAccCaret->Release();
}
person Eric Brown    schedule 10.08.2013
comment
Эрик Браун, спасибо! Попробовал в опере, работает! Кроме того, я попробовал этот код для IE Explorer, и он тоже сработал! Но в случае IE и многих других программ мне нужно было получить сфокусированный элемент окна верхнего уровня, прежде чем я смогу использовать этот код. - person Alex141; 11.08.2013
comment
GetGuiThreadInfo вернет окно верхнего уровня переднего плана. - person Eric Brown; 11.08.2013
comment
Извините, что не было вопроса) Я использовал функции GetForeground(), GetWindowProcessThreadId(), AttachToThread() и GetFocus(). Я думаю, что функция GetGuiThreadInfo не подходит для моей цели, потому что я хочу сначала получить ThreadId из mainWindow, а затем получить сфокусированный элемент, используя присоединение к основанному threadId. - person Alex141; 11.08.2013
comment
Эрик, спасибо за совет, но есть видео очень плохого качества, поэтому я не могу понять, почему использование AttachThreadInput - это плохой способ. Можешь сказать мне? P.S. Я попробовал GetGuiThreadInfo, и он работает, но мне не нравится, что ему нужно заполнить поле CbSize по размеру (эта структура). Поэтому мне приходится писать небезопасную конструкцию или писать магические цифры типа 48 )) - person Alex141; 13.08.2013
comment
Если оба потока не знают, что очереди подключены, использование AttachThreadInput имеет тенденцию вызывать взаимоблокировки и зависания, как описано в связанном сообщении. Что касается GetGuiThreadInfo, что не так с Marshal.SizeOf()? - person Eric Brown; 24.08.2013