Как да разбера дали каретката съществува [в opera]?

Опитвам се да реша следната задача: Имам браузър 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
Ако под AttachToThread() имате предвид AttachThreadInput, моля, спрете. GetGuiThreadInfo връща абсолютно същите данни и няма всякакви неочаквани изисквания. - person Eric Brown; 12.08.2013
comment
Ерик, благодаря ти за съвета, но има видео с много лошо качество, така че не мога да разбера защо използването на AttachThreadInput е лош начин. Можеш ли да ми кажеш? P.S. Опитах GetGuiThreadInfo и работи, но не ми харесва, че трябва да попълни полето CbSize от sizeof (тази структура). Така че трябва да напиша опасна конструкция или да напиша магически цифри като 48 )) - person Alex141; 13.08.2013
comment
Освен ако и двете нишки не знаят, че опашките са прикачени, използването на AttachThreadInput има тенденция да причинява блокирания и увисвания, както се описва в свързаното съобщение. Колкото до GetGuiThreadInfo, какво не е наред с Marshal.SizeOf()? - person Eric Brown; 24.08.2013