/*
  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;
}
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDescription(VARIANT varID, BSTR* pszDescription)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;


    QString descr;
    if (varID.lVal) {
        QAccessibleInterface *child = childPointer(accessible, varID);
        if (!child)
            return E_FAIL;
        descr = child->text(QAccessible::Description);
    } else {
        descr = accessible->text(QAccessible::Description);
    }
    if (descr.size()) {
        *pszDescription = QStringToBSTR(descr);
        return S_OK;
    }

    *pszDescription = 0;
    return S_FALSE;
}
/**************************************************************\
 *                                                             *
 *                        IUnknown                             *
 *                                                             *
 **************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVOID *iface)
{
    *iface = 0;

    QByteArray strIID = IIDToString(id);
    if (!strIID.isEmpty()) {
        QString ss;
        QDebug dbg(&ss);
        dbg << accessibleInterface();
        accessibleDebug("QWindowsIA2Accessible::QI() - IID:%s, iface:%s ", strIID.constData(), qPrintable(ss));
    }
    if (id == IID_IUnknown) {
        *iface = (IUnknown*)(IDispatch*)this;
    } else if (id == IID_IDispatch) {
        *iface = (IDispatch*)this;
    } else if (id == IID_IAccessible) {
        *iface = (IAccessible*)this;
    } else if (id == IID_IOleWindow) {
        *iface = (IOleWindow*)this;
    }

    if (*iface) {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accName(VARIANT varID, BSTR* pszName)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QString name;
    if (varID.lVal) {
        QAccessibleInterface *child = childPointer(accessible, varID);
        if (!child)
            return E_FAIL;
        name = child->text(QAccessible::Name);
        if (name.isEmpty()) {
            if (QAccessibleInterface *labelInterface = relatedInterface(child, QAccessible::Label)) {
                name = labelInterface->text(QAccessible::Name);
            }
        }
    } else {
        name = accessible->text(QAccessible::Name);
        if (name.isEmpty()) {
            if (QAccessibleInterface *labelInterface = relatedInterface(accessible, QAccessible::Label)) {
                name = labelInterface->text(QAccessible::Name);
            }
        }
    }
    if (name.size()) {
        *pszName = QStringToBSTR(name);
        return S_OK;
    }

    *pszName = 0;
    return S_FALSE;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accRole(VARIANT varID, VARIANT *pvarRole)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessible::Role role;
    if (varID.lVal) {
        QAccessibleInterface *child = childPointer(accessible, varID);
        if (!child)
            return E_FAIL;
        role = child->role();
    } else {
        role = accessible->role();
    }

    if (role != QAccessible::NoRole) {
        if (role >= QAccessible::LayeredPane) {
            // This block should hopefully only be entered if the AT client
            // does not support IAccessible2, since it should prefer IA2::role() then.
            if (role == QAccessible::LayeredPane)
                role = QAccessible::Pane;
            else
                role = QAccessible::Client;
        }
        (*pvarRole).vt = VT_I4;
        (*pvarRole).lVal = role;
    } else {
        (*pvarRole).vt = VT_EMPTY;
    }
    return S_OK;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accSelect(long flagsSelect, VARIANT varID)
{
    Q_UNUSED(flagsSelect);
    Q_UNUSED(varID);
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    bool res = false;

/*
  ### Check for accessibleTableInterface() or accessibleTextInterface()

  ### and if there are no ia2 interfaces we should do nothing??
    if (flagsSelect & SELFLAG_TAKEFOCUS)
        res = accessible()->doAction(SetFocus, varID.lVal, QVariantList());
    if (flagsSelect & SELFLAG_TAKESELECTION) {
        accessible()->doAction(ClearSelection, 0, QVariantList());
        res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList());
    }
    if (flagsSelect & SELFLAG_EXTENDSELECTION)
        res = accessible()->doAction(ExtendSelection, varID.lVal, QVariantList());
    if (flagsSelect & SELFLAG_ADDSELECTION)
        res = accessible()->doAction(AddToSelection, varID.lVal, QVariantList());
    if (flagsSelect & SELFLAG_REMOVESELECTION)
        res = accessible()->doAction(RemoveSelection, varID.lVal, QVariantList());
*/
    return res ? S_OK : S_FALSE;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accValue(VARIANT varID, BSTR* pszValue)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (varID.vt != VT_I4)
        return E_INVALIDARG;

    if (!accessible || !accessible->isValid() || varID.lVal) {
        return E_FAIL;
    }

    QString value;
    if (accessible->valueInterface()) {
        value = QString::number(accessible->valueInterface()->currentValue().toDouble());
    } else {
        value = accessible->text(QAccessible::Value);
    }
    if (!value.isNull()) {
        *pszValue = QStringToBSTR(value);
        return S_OK;
    }

    *pszValue = 0;
    accessibleDebug("return S_FALSE");
    return S_FALSE;
}
/**************************************************************\
 *                                                             *
 *                        IUnknown                             *
 *                                                             *
 **************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::QueryInterface(REFIID id, LPVOID *iface)
{
    *iface = 0;

    QByteArray strIID = IIDToString(id);
    if (!strIID.isEmpty()) {
        qCDebug(lcQpaAccessibility) << "QWindowsIA2Accessible::QI() - IID:"
                                    << strIID << ", iface:" << accessibleInterface();
    }
    if (id == IID_IUnknown) {
        *iface = (IUnknown*)(IDispatch*)this;
    } else if (id == IID_IDispatch) {
        *iface = (IDispatch*)this;
    } else if (id == IID_IAccessible) {
        *iface = (IAccessible*)this;
    } else if (id == IID_IOleWindow) {
        *iface = (IOleWindow*)this;
    }

    if (*iface) {
        AddRef();
        return S_OK;
    }

    return E_NOINTERFACE;
}
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChildCount(long* pcountChildren)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    *pcountChildren = accessible->childCount();
    return S_OK;
}
示例#10
0
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accDefaultAction(VARIANT varID, BSTR* pszDefaultAction)
{
    Q_UNUSED(varID);
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    *pszDefaultAction = 0;
    if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
        const QString def = actionIface->actionNames().value(0);
        if (!def.isEmpty())
            *pszDefaultAction = QStringToBSTR(def);
    }
    return *pszDefaultAction ? S_OK : S_FALSE;
}
示例#11
0
/*
  Properties and methods
*/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accDoDefaultAction(VARIANT varID)
{
    Q_UNUSED(varID);
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
        const QString def = actionIface->actionNames().value(0);
        if (!def.isEmpty()) {
            actionIface->doAction(def);
            return S_OK;
        }
    }
    return S_FALSE;
}
示例#12
0
/**************************************************************\
 *                         IOleWindow                          *
 **************************************************************/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::GetWindow(HWND *phwnd)
{
    *phwnd = 0;
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QWindow *window = QWindowsAccessibility::windowHelper(accessible);
    if (!window)
        return E_FAIL;

    QPlatformNativeInterface *platform = QGuiApplication::platformNativeInterface();
    Q_ASSERT(platform);
    *phwnd = (HWND)platform->nativeResourceForWindow("handle", window);
    accessibleDebug("QWindowsAccessible::GetWindow(): %p", *phwnd);
    return S_OK;
}
示例#13
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accParent(IDispatch** ppdispParent)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessibleInterface *acc = accessible->parent();
    if (acc) {
        if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
            *ppdispParent = iface;
            return S_OK;
        }
    }

    *ppdispParent = 0;
    return S_FALSE;
}
示例#14
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accChild(VARIANT varChildID, IDispatch** ppdispChild)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    if (varChildID.vt != VT_I4)
        return E_INVALIDARG;

    QAccessibleInterface *acc = childPointer(accessible, varChildID);
    if (acc) {
        *ppdispChild = QWindowsAccessibility::wrap(acc);
        return S_OK;
    }

    return E_FAIL;
}
示例#15
0
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *pszKeyboardShortcut)
{
    Q_UNUSED(varID);
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    *pszKeyboardShortcut = 0;
    if (QAccessibleActionInterface *actionIface = accessible->actionInterface()) {
        const QString def = actionIface->actionNames().value(0);
        if (!def.isEmpty()) {
            const QString keyBoardShortCut = actionIface->keyBindingsForAction(def).value(0);
            if (!keyBoardShortCut.isEmpty())
                *pszKeyboardShortcut = QStringToBSTR(keyBoardShortCut);
        }
    }
    return *pszKeyboardShortcut ? S_OK : S_FALSE;
}
示例#16
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accLocation(long *pxLeft, long *pyTop, long *pcxWidth, long *pcyHeight, VARIANT varID)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessibleInterface *acc = childPointer(accessible, varID);
    if (!acc || !acc->isValid())
        return E_FAIL;
    const QRect rect = acc->rect();

    *pxLeft = rect.x();
    *pyTop = rect.y();
    *pcxWidth = rect.width();
    *pcyHeight = rect.height();

    return S_OK;
}
示例#17
0
/*!
    \internal
    Can return:

  +-------------+------------------------------------------------------------------------------+
  | VT_EMPTY    | None. Neither this object nor any of its children has the keyboard focus.    |
  +-------------+------------------------------------------------------------------------------+
  | VT_I4       | lVal is CHILDID_SELF. The object itself has the keyboard focus.              |
  +-------------+------------------------------------------------------------------------------+
  | VT_I4       | lVal contains the child ID of the child element that has the keyboard focus. |
  +-------------+------------------------------------------------------------------------------+
  | VT_DISPATCH | pdispVal member is the address of the IDispatch interface for the child      |
  |             | object that has the keyboard focus.                                          |
  +-------------+------------------------------------------------------------------------------+
    moz: [important]
*/
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accFocus(VARIANT *pvarID)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    if (QAccessibleInterface *acc = accessible->focusChild()) {
        if (acc == accessible) {
            (*pvarID).vt = VT_I4;
            (*pvarID).lVal = CHILDID_SELF;
            return S_OK;
        } else {
            if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
                (*pvarID).vt = VT_DISPATCH;
                (*pvarID).pdispVal = iface;
                return S_OK;
            }
        }
    }
    (*pvarID).vt = VT_EMPTY;
    return S_FALSE;
}
示例#18
0
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accSelection(VARIANT *pvarChildren)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    int cc = accessible->childCount();
    QVector<int> sel(cc);
    int selIndex = 0;
    for (int i = 0; i < cc; ++i) {
        bool isSelected = false;
        QAccessibleInterface *child = accessible->child(i);
        if (child) {
            isSelected = child->state().selected;
        }
        if (isSelected)
            sel[selIndex++] = i+1;
    }
    sel.resize(selIndex);
    if (sel.isEmpty()) {
        (*pvarChildren).vt = VT_EMPTY;
        return S_FALSE;
    }
    if (sel.size() == 1) {
        (*pvarChildren).vt = VT_I4;
        (*pvarChildren).lVal = sel[0];
        return S_OK;
    }
    IEnumVARIANT *iface = new QWindowsEnumerate(sel);
    IUnknown *uiface;
    iface->QueryInterface(IID_IUnknown, (void**)&uiface);
    (*pvarChildren).vt = VT_UNKNOWN;
    (*pvarChildren).punkVal = uiface;

    return S_OK;
}
示例#19
0
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accHelp(VARIANT varID, BSTR *pszHelp)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QString help;
    if (varID.lVal) {
        QAccessibleInterface *child = childPointer(accessible, varID);
        if (!child)
            return E_FAIL;
        help = child->text(QAccessible::Help);
    } else {
        help = accessible->text(QAccessible::Help);
    }
    if (help.size()) {
        *pszHelp = QStringToBSTR(help);
        return S_OK;
    }

    *pszHelp = 0;
    return S_FALSE;
}
示例#20
0
// moz: [important]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::get_accState(VARIANT varID, VARIANT *pvarState)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessible::State state;
    if (varID.lVal) {
        QAccessibleInterface *child = childPointer(accessible, varID);
        if (!child)
            return E_FAIL;
        state = child->state();
    } else {
        state = accessible->state();
    }

    LONG st = 0;
    if (state.animated)
        st |= STATE_SYSTEM_ANIMATED;
    if (state.busy)
        st |= STATE_SYSTEM_BUSY;
    if (state.checked)
        st |= STATE_SYSTEM_CHECKED;
    if (state.collapsed)
        st |= STATE_SYSTEM_COLLAPSED;
    if (state.defaultButton)
        st |= STATE_SYSTEM_DEFAULT;
    if (state.expanded)
        st |= STATE_SYSTEM_EXPANDED;
    if (state.extSelectable)
        st |= STATE_SYSTEM_EXTSELECTABLE;
    if (state.focusable)
        st |= STATE_SYSTEM_FOCUSABLE;
    if (state.focused)
        st |= STATE_SYSTEM_FOCUSED;
    if (state.hasPopup)
        st |= STATE_SYSTEM_HASPOPUP;
    if (state.hotTracked)
        st |= STATE_SYSTEM_HOTTRACKED;
    if (state.invisible)
        st |= STATE_SYSTEM_INVISIBLE;
    if (state.linked)
        st |= STATE_SYSTEM_LINKED;
    if (state.marqueed)
        st |= STATE_SYSTEM_MARQUEED;
    if (state.checkStateMixed)
        st |= STATE_SYSTEM_MIXED;
    if (state.movable)
        st |= STATE_SYSTEM_MOVEABLE;
    if (state.multiSelectable)
        st |= STATE_SYSTEM_MULTISELECTABLE;
    if (state.offscreen)
        st |= STATE_SYSTEM_OFFSCREEN;
    if (state.pressed)
        st |= STATE_SYSTEM_PRESSED;
    if (state.passwordEdit)
        st |= STATE_SYSTEM_PROTECTED;
    if (state.readOnly)
        st |= STATE_SYSTEM_READONLY;
    if (state.selectable)
        st |= STATE_SYSTEM_SELECTABLE;
    if (state.selected)
        st |= STATE_SYSTEM_SELECTED;
    if (state.selfVoicing)
        st |= STATE_SYSTEM_SELFVOICING;
    if (state.sizeable)
        st |= STATE_SYSTEM_SIZEABLE;
    if (state.traversed)
        st |= STATE_SYSTEM_TRAVERSED;

    (*pvarState).vt = VT_I4;
    (*pvarState).lVal = st;
    return S_OK;
}
示例#21
0
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::put_accName(VARIANT, BSTR)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    return DISP_E_MEMBERNOTFOUND;
}
示例#22
0
// moz: [important, but no need to implement up/down/left/right]
HRESULT STDMETHODCALLTYPE QWindowsMsaaAccessible::accNavigate(long navDir, VARIANT varStart, VARIANT *pvarEnd)
{
    QAccessibleInterface *accessible = accessibleInterface();
    accessibleDebugClientCalls(accessible);
    if (!accessible)
        return E_FAIL;

    QAccessibleInterface *acc = 0;
    switch (navDir) {
    case NAVDIR_FIRSTCHILD:
        acc = accessible->child(0);
        break;
    case NAVDIR_LASTCHILD:
        acc = accessible->child(accessible->childCount() - 1);
        break;
    case NAVDIR_NEXT:
    case NAVDIR_PREVIOUS:
        if (!varStart.lVal){
            QAccessibleInterface *parent = accessible->parent();
            if (parent && parent->isValid()) {
                int index = parent->indexOfChild(accessible);
                index += (navDir == NAVDIR_NEXT) ? 1 : -1;
                if (index >= 0 && index < parent->childCount())
                    acc = parent->child(index);
            }
        } else {
            int index = varStart.lVal;
            index += (navDir == NAVDIR_NEXT) ? 1 : -1;
            if (index > 0 && index <= accessible->childCount())
                acc = accessible->child(index - 1);
        }
        break;

    // Geometrical
    case NAVDIR_UP:
    case NAVDIR_DOWN:
    case NAVDIR_LEFT:
    case NAVDIR_RIGHT: {
        QAccessibleInterface *pIface = accessible->parent();
        if (pIface && pIface->isValid()) {
            const int indexOfOurself = pIface->indexOfChild(accessible);
            QRect startg = accessible->rect();
            QPoint startc = startg.center();
            QAccessibleInterface *candidate = 0;
            unsigned mindist = UINT_MAX;    // will work on screen sizes at least up to 46340x46340
            const int sibCount = pIface->childCount();
            for (int i = 0; i < sibCount; ++i) {
                QAccessibleInterface *sibling = 0;
                sibling = pIface->child(i);
                Q_ASSERT(sibling);
                if (i == indexOfOurself || sibling->state().invisible) {
                    //ignore ourself and invisible siblings
                    continue;
                }

                QRect sibg = sibling->rect();
                QPoint sibc = sibg.center();
                QPoint sibp;
                QPoint startp;
                QPoint distp;
                switch (navDir) {
                case NAVDIR_LEFT:
                    startp = QPoint(startg.left(), startg.top() + startg.height() / 2);
                    sibp = QPoint(sibg.right(), sibg.top() + sibg.height() / 2);
                    if (QPoint(sibc - startc).x() >= 0) {
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_RIGHT:
                    startp = QPoint(startg.right(), startg.top() + startg.height() / 2);
                    sibp = QPoint(sibg.left(), sibg.top() + sibg.height() / 2);
                    if (QPoint(sibc - startc).x() <= 0) {
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_UP:
                    startp = QPoint(startg.left() + startg.width() / 2, startg.top());
                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.bottom());
                    if (QPoint(sibc - startc).y() >= 0) {
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                case NAVDIR_DOWN:
                    startp = QPoint(startg.left() + startg.width() / 2, startg.bottom());
                    sibp = QPoint(sibg.left() + sibg.width() / 2, sibg.top());
                    if (QPoint(sibc - startc).y() <= 0) {
                        continue;
                    }
                    distp = sibp - startp;
                    break;
                default:
                    break;
                }

                // Since we're *comparing* (and not measuring) distances, we can compare the
                // squared distance, (thus, no need to take the sqrt()).
                unsigned dist = distp.x() * distp.x() + distp.y() * distp.y();
                if (dist < mindist) {
                    candidate = sibling;
                    mindist = dist;
                }
            }
            acc = candidate;
        }
    }
        break;
    default:
        break;
    }
    if (!acc) {
        (*pvarEnd).vt = VT_EMPTY;
        return S_FALSE;
    }

    if (IAccessible *iface = QWindowsAccessibility::wrap(acc)) {
        (*pvarEnd).vt = VT_DISPATCH;
        (*pvarEnd).pdispVal = iface;
        return S_OK;
    }

    (*pvarEnd).vt = VT_EMPTY;
    return S_FALSE;
}