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; }
/* 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); }