void tst_QQuickAccessible::hitTest()
{
    QQuickView *window = new QQuickView;
    window->setSource(testFileUrl("hittest.qml"));
    window->show();

    QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window);
    QVERIFY(windowIface);
    QAccessibleInterface *rootItem = windowIface->child(0);
    QRect rootRect = rootItem->rect();

    // check the root item from app
    QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp);
    QVERIFY(appIface);
    QAccessibleInterface *itemHit = appIface->childAt(rootRect.x() + 200, rootRect.y() + 50);
    QVERIFY(itemHit);
    QCOMPARE(itemHit->rect(), rootRect);

    QAccessibleInterface *rootItemIface;
    for (int c = 0; c < rootItem->childCount(); ++c) {
        QAccessibleInterface *iface = rootItem->child(c);
        QString name = iface->text(QAccessible::Name);
        if (name == QLatin1String("rect1")) {
            // hit rect1
            QAccessibleInterface *rect1 = iface;
            QRect rect1Rect = rect1->rect();
            QAccessibleInterface *rootItemIface = rootItem->childAt(rect1Rect.x() + 10, rect1Rect.y() + 10);
            QVERIFY(rootItemIface);
            QCOMPARE(rect1Rect, rootItemIface->rect());
            QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect1"));

            // should also work from top level (app)
            QAccessibleInterface *app(QAccessible::queryAccessibleInterface(qApp));
            QAccessibleInterface *itemHit2(topLevelChildAt(app, rect1Rect.x() + 10, rect1Rect.y() + 10));
            QVERIFY(itemHit2);
            QCOMPARE(itemHit2->rect(), rect1Rect);
            QCOMPARE(itemHit2->text(QAccessible::Name), QLatin1String("rect1"));
        } else if (name == QLatin1String("rect2")) {
            QAccessibleInterface *rect2 = iface;
            // FIXME: This is seems broken on OS X
            // QCOMPARE(rect2->rect().translated(rootItem->rect().x(), rootItem->rect().y()), QRect(0, 50, 100, 100));
            QAccessibleInterface *rect20 = rect2->child(0);
            QVERIFY(rect20);
            QCOMPARE(rect20->text(QAccessible::Name), QLatin1String("rect20"));
            QPoint p = rect20->rect().bottomRight() + QPoint(20, 20);
            QAccessibleInterface *rect201 = rect20->childAt(p.x(), p.y());
            QVERIFY(rect201);
            QCOMPARE(rect201->text(QAccessible::Name), QLatin1String("rect201"));
            rootItemIface = topLevelChildAt(windowIface, p.x(), p.y());
            QVERIFY(rootItemIface);
            QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect201"));

        }
    }

    delete window;
    QTestAccessibility::clearEvents();
}
void tst_QQuickAccessible::hitTest()
{
    QQuickView *window = new QQuickView;
    window->setSource(testFileUrl("hittest.qml"));
    window->show();

    QAccessibleInterface *windowIface = QAccessible::queryAccessibleInterface(window);
    QVERIFY(windowIface);
    QAccessibleInterface *rootItem = windowIface->child(0);
    QRect rootRect = rootItem->rect();

    // check the root item from app
    QAccessibleInterface *appIface = QAccessible::queryAccessibleInterface(qApp);
    QVERIFY(appIface);
    QAccessibleInterface *itemHit(appIface->childAt(rootRect.x() + 200, rootRect.y() + 50));
    QVERIFY(itemHit);
    QCOMPARE(rootRect, itemHit->rect());

    // hit rect1
    QAccessibleInterface *rect1(rootItem->child(0));
    QRect rect1Rect = rect1->rect();
    QAccessibleInterface *rootItemIface = rootItem->childAt(rect1Rect.x() + 10, rect1Rect.y() + 10);
    QVERIFY(rootItemIface);
    QCOMPARE(rect1Rect, rootItemIface->rect());
    QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect1"));

    // should also work from top level (app)
    QAccessibleInterface *app(QAccessible::queryAccessibleInterface(qApp));
    QAccessibleInterface *itemHit2(topLevelChildAt(app, rect1Rect.x() + 10, rect1Rect.y() + 10));
    QVERIFY(itemHit2);
    QCOMPARE(itemHit2->rect(), rect1Rect);
    QCOMPARE(itemHit2->text(QAccessible::Name), QLatin1String("rect1"));

    // hit rect201
    QAccessibleInterface *rect2(rootItem->child(1));
    QVERIFY(rect2);
    // FIXME: This is seems broken on mac
    // QCOMPARE(rect2->rect().translated(rootItem->rect().x(), rootItem->rect().y()), QRect(0, 50, 100, 100));
    QAccessibleInterface *rect20(rect2->child(0));
    QVERIFY(rect20);
    QAccessibleInterface *rect201(rect20->child(1));
    QVERIFY(rect201);

    QRect rect201Rect = rect201->rect();
    rootItemIface = windowIface->childAt(rect201Rect.x() + 20, rect201Rect.y() + 20);
    QVERIFY(rootItemIface);
    QCOMPARE(rootItemIface->rect(), rect201Rect);
    QCOMPARE(rootItemIface->text(QAccessible::Name), QLatin1String("rect201"));

    delete window;
    QTestAccessibility::clearEvents();
}
 static jint hitTest(JNIEnv */*env*/, jobject /*thiz*/, jfloat x, jfloat y)
 {
     QAccessibleInterface *root = interfaceFromId(-1);
     if (root) {
         QAccessibleInterface *child = root->childAt((int)x, (int)y);
         QAccessibleInterface *lastChild = 0;
         while (child && (child != lastChild)) {
             lastChild = child;
             child = child->childAt((int)x, (int)y);
         }
         if (lastChild)
             return QAccessible::uniqueId(lastChild);
     }
     return -1;
 }
Exemple #4
0
/*
  IAccessible

IAccessible::accHitTest documents the value returned in pvarID like this:

| *Point location*                                       | *vt member* | *Value member*          |
+========================================================+=============+=========================+
| Outside of the object's boundaries, and either inside  | VT_EMPTY    | None.                   |
| or outside of the object's bounding rectangle.         |             |                         |
+--------------------------------------------------------+-------------+-------------------------+
|  Within the object but not within a child element or a | VT_I4       | lVal is CHILDID_SELF    |
|  child object.                                         |             |                         |
+--------------------------------------------------------+-------------+-------------------------+
| Within a child element.                                | VT_I4       | lVal contains           |
|                                                        |             | the child ID.           |
+--------------------------------------------------------+-------------+-------------------------+
| Within a child object.                                 | VT_DISPATCH | pdispVal is set to the  |
|                                                        |             | child object's IDispatch|
|                                                        |             | interface pointer       |
+--------------------------------------------------------+-------------+-------------------------+
*/
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
{

    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
    if (child == 0) {
        // no child found, return this item if it contains the coordinates
        if (accessible->rect().contains(xLeft, yTop)) {
            (*pvarID).vt = VT_I4;
            (*pvarID).lVal = CHILDID_SELF;
            return S_OK;
        }
    } else {
        QWindowsAccessible* wacc = new QWindowsAccessible(child);
        IDispatch *iface = 0;
        wacc->QueryInterface(IID_IDispatch, (void**)&iface);
        if (iface) {
            (*pvarID).vt = VT_DISPATCH;
            (*pvarID).pdispVal = iface;
            return S_OK;
        }
    }

    // Did not find anything
    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
/*
  IAccessible

IAccessible::accHitTest documents the value returned in pvarID like this:

| *Point location*                                       | *vt member* | *Value member*          |
+========================================================+=============+=========================+
| Outside of the object's boundaries, and either inside  | VT_EMPTY    | None.                   |
| or outside of the object's bounding rectangle.         |             |                         |
+--------------------------------------------------------+-------------+-------------------------+
|  Within the object but not within a child element or a | VT_I4       | lVal is CHILDID_SELF    |
|  child object.                                         |             |                         |
+--------------------------------------------------------+-------------+-------------------------+
| Within a child element.                                | VT_I4       | lVal contains           |
|                                                        |             | the child ID.           |
+--------------------------------------------------------+-------------+-------------------------+
| Within a child object.                                 | VT_DISPATCH | pdispVal is set to the  |
|                                                        |             | child object's IDispatch|
|                                                        |             | interface pointer       |
+--------------------------------------------------------+-------------+-------------------------+
*/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessibleInterface *child = accessible->childAt(xLeft, yTop);
    if (child == 0) {
        // no child found, return this item if it contains the coordinates
        if (accessible->rect().contains(xLeft, yTop)) {
            (*pvarID).vt = VT_I4;
            (*pvarID).lVal = CHILDID_SELF;
            return S_OK;
        }
    } else {
        IAccessible *iface = QWindowsAccessibility::wrap(child);
        if (iface) {
            (*pvarID).vt = VT_DISPATCH;
            (*pvarID).pdispVal = iface;
            return S_OK;
        }
    }

    // Did not find anything
    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
/*
  IAccessible
*/
HRESULT STDMETHODCALLTYPE QWindowsAccessible::accHitTest(long xLeft, long yTop, VARIANT *pvarID)
{
    showDebug(__FUNCTION__, accessible);
    if (!accessible->isValid())
        return E_FAIL;

    int control = accessible->childAt(xLeft, yTop);
    if (control == -1) {
        (*pvarID).vt = VT_EMPTY;
        return S_FALSE;
    }
    QAccessibleInterface *acc = 0;
    if (control)
        accessible->navigate(Child, control, &acc);
    if (!acc) {
        (*pvarID).vt = VT_I4;
        (*pvarID).lVal = control;
        return S_OK;
    }

    QWindowsAccessible* wacc = new QWindowsAccessible(acc);
    IDispatch *iface = 0;
    wacc->QueryInterface(IID_IDispatch, (void**)&iface);
    if (iface) {
        (*pvarID).vt = VT_DISPATCH;
        (*pvarID).pdispVal = iface;
        return S_OK;
    } else {
        delete wacc;
    }

    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
QAccessibleInterface *topLevelChildAt(QAccessibleInterface *iface, int x, int y)
{
    QAccessibleInterface *child = iface->childAt(x, y);
    if (!child)
        return 0;

    QAccessibleInterface *childOfChild;
    while ( ( childOfChild = child->childAt(x, y)) ) {
        child = childOfChild;
    }
    return child;
}
void ScreenReader::processTouchPoint()
{
    if (m_activateCalled) {
        return;
    }

    if (m_rootInterface == 0) {
        return;
    }

    QAccessibleInterface * currentInterface = m_rootInterface;

    int hit = -2;
    int guardCounter = 0;
    const int guardMax = 40;
    while (currentInterface != 0) {
        ++guardCounter;
        if (guardCounter > guardMax) {
            qDebug() << "touchPoint exit recursion overflow";
            return; // outside
        }

        QAccessibleInterface * hit = currentInterface->childAt(m_currentTouchPoint.x(), m_currentTouchPoint.y());
        if (!hit)
            break;
        currentInterface = hit;
    }

    m_selectedInterface = currentInterface;
    if (m_selectedInterface->object())
        emit selected(m_selectedInterface->object());
    if (m_optionsWidget->enableTextToSpeach())
        speak(m_selectedInterface->text(QAccessible::Name)
              /*+ "," + translateRole(m_selectedInterface->role(0)) */);

//    qDebug() << "touchPoint exit found" << m_selectedInterface->text(QAccessible::Name, 0) << m_selectedInterface->object() << m_selectedInterface->rect(0);
}