blob: ab04384616c15a2af87fe7a0147c87b15dd9d03f [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtGui/qtguiglobal.h>
#if QT_CONFIG(accessibility)
#include "qwindowsuiautils.h"
#include "qwindowscontext.h"
#include "qwindowswindow.h"
#include <QtGui/qwindow.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <cmath>
QT_BEGIN_NAMESPACE
namespace QWindowsUiAutomation {
// Returns the window containing the element (usually the top window),
QWindow *windowForAccessible(const QAccessibleInterface *accessible)
{
QWindow *window = accessible->window();
if (!window) {
const QAccessibleInterface *acc = accessible;
const QAccessibleInterface *par = accessible->parent();
while (par && par->isValid() && !window) {
window = par->window();
acc = par;
par = par->parent();
}
if (!window) {
// Workaround for WebEngineView not knowing its parent.
const auto appWindows = QGuiApplication::topLevelWindows();
for (QWindow *w : appWindows) {
if (QAccessibleInterface *root = w->accessibleRoot()) {
int count = root->childCount();
for (int i = 0; i < count; ++i) {
if (root->child(i) == acc)
return w;
}
}
}
}
}
return window;
}
// Returns the native window handle associated with the element, if any.
// Usually it will be NULL, as Qt5 by default uses alien widgets with no native windows.
HWND hwndForAccessible(const QAccessibleInterface *accessible)
{
if (QWindow *window = accessible->window()) {
if (!accessible->parent() || (accessible->parent()->window() != window)) {
return QWindowsBaseWindow::handleOf(window);
}
}
return nullptr;
}
void clearVariant(VARIANT *variant)
{
variant->vt = VT_EMPTY;
variant->punkVal = nullptr;
}
void setVariantI4(int value, VARIANT *variant)
{
variant->vt = VT_I4;
variant->lVal = value;
}
void setVariantBool(bool value, VARIANT *variant)
{
variant->vt = VT_BOOL;
variant->boolVal = value ? -1 : 0;
}
void setVariantDouble(double value, VARIANT *variant)
{
variant->vt = VT_R8;
variant->dblVal = value;
}
BSTR bStrFromQString(const QString &value)
{
return SysAllocString(reinterpret_cast<const wchar_t *>(value.utf16()));
}
void setVariantString(const QString &value, VARIANT *variant)
{
variant->vt = VT_BSTR;
variant->bstrVal = bStrFromQString(value);
}
// Scales a rect to native coordinates, according to high dpi settings.
void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect)
{
if (w && uiaRect) {
const qreal factor = QHighDpiScaling::factor(w);
uiaRect->left = qreal(rect.x()) * factor;
uiaRect->top = qreal(rect.y()) * factor;
uiaRect->width = qreal(rect.width()) * factor;
uiaRect->height = qreal(rect.height()) * factor;
}
}
// Scales a point from native coordinates, according to high dpi settings.
void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point)
{
if (w && point) {
const qreal factor = QHighDpiScaling::factor(w);
point->setX(int(std::lround(uiaPoint.x / factor)));
point->setY(int(std::lround(uiaPoint.y / factor)));
}
}
// Maps an accessibility role ID to an UI Automation control type ID.
long roleToControlTypeId(QAccessible::Role role)
{
static const QHash<QAccessible::Role, long> mapping {
{QAccessible::TitleBar, UIA_TitleBarControlTypeId},
{QAccessible::MenuBar, UIA_MenuBarControlTypeId},
{QAccessible::ScrollBar, UIA_ScrollBarControlTypeId},
{QAccessible::Grip, UIA_ThumbControlTypeId},
{QAccessible::Sound, UIA_CustomControlTypeId},
{QAccessible::Cursor, UIA_CustomControlTypeId},
{QAccessible::Caret, UIA_CustomControlTypeId},
{QAccessible::AlertMessage, UIA_CustomControlTypeId},
{QAccessible::Window, UIA_WindowControlTypeId},
{QAccessible::Client, UIA_GroupControlTypeId},
{QAccessible::PopupMenu, UIA_MenuControlTypeId},
{QAccessible::MenuItem, UIA_MenuItemControlTypeId},
{QAccessible::ToolTip, UIA_ToolTipControlTypeId},
{QAccessible::Application, UIA_CustomControlTypeId},
{QAccessible::Document, UIA_DocumentControlTypeId},
{QAccessible::Pane, UIA_PaneControlTypeId},
{QAccessible::Chart, UIA_CustomControlTypeId},
{QAccessible::Dialog, UIA_WindowControlTypeId},
{QAccessible::Border, UIA_CustomControlTypeId},
{QAccessible::Grouping, UIA_GroupControlTypeId},
{QAccessible::Separator, UIA_SeparatorControlTypeId},
{QAccessible::ToolBar, UIA_ToolBarControlTypeId},
{QAccessible::StatusBar, UIA_StatusBarControlTypeId},
{QAccessible::Table, UIA_TableControlTypeId},
{QAccessible::ColumnHeader, UIA_HeaderControlTypeId},
{QAccessible::RowHeader, UIA_HeaderControlTypeId},
{QAccessible::Column, UIA_HeaderItemControlTypeId},
{QAccessible::Row, UIA_HeaderItemControlTypeId},
{QAccessible::Cell, UIA_DataItemControlTypeId},
{QAccessible::Link, UIA_HyperlinkControlTypeId},
{QAccessible::HelpBalloon, UIA_ToolTipControlTypeId},
{QAccessible::Assistant, UIA_CustomControlTypeId},
{QAccessible::List, UIA_ListControlTypeId},
{QAccessible::ListItem, UIA_ListItemControlTypeId},
{QAccessible::Tree, UIA_TreeControlTypeId},
{QAccessible::TreeItem, UIA_TreeItemControlTypeId},
{QAccessible::PageTab, UIA_TabItemControlTypeId},
{QAccessible::PropertyPage, UIA_CustomControlTypeId},
{QAccessible::Indicator, UIA_CustomControlTypeId},
{QAccessible::Graphic, UIA_ImageControlTypeId},
{QAccessible::StaticText, UIA_TextControlTypeId},
{QAccessible::EditableText, UIA_EditControlTypeId},
{QAccessible::Button, UIA_ButtonControlTypeId},
{QAccessible::CheckBox, UIA_CheckBoxControlTypeId},
{QAccessible::RadioButton, UIA_RadioButtonControlTypeId},
{QAccessible::ComboBox, UIA_ComboBoxControlTypeId},
{QAccessible::ProgressBar, UIA_ProgressBarControlTypeId},
{QAccessible::Dial, UIA_CustomControlTypeId},
{QAccessible::HotkeyField, UIA_CustomControlTypeId},
{QAccessible::Slider, UIA_SliderControlTypeId},
{QAccessible::SpinBox, UIA_SpinnerControlTypeId},
{QAccessible::Canvas, UIA_CustomControlTypeId},
{QAccessible::Animation, UIA_CustomControlTypeId},
{QAccessible::Equation, UIA_CustomControlTypeId},
{QAccessible::ButtonDropDown, UIA_ButtonControlTypeId},
{QAccessible::ButtonMenu, UIA_ButtonControlTypeId},
{QAccessible::ButtonDropGrid, UIA_ButtonControlTypeId},
{QAccessible::Whitespace, UIA_CustomControlTypeId},
{QAccessible::PageTabList, UIA_TabControlTypeId},
{QAccessible::Clock, UIA_CustomControlTypeId},
{QAccessible::Splitter, UIA_CustomControlTypeId},
};
return mapping.value(role, UIA_CustomControlTypeId);
}
// True if a character can be a separator for a text unit.
bool isTextUnitSeparator(TextUnit unit, const QChar &ch)
{
return (((unit == TextUnit_Word) || (unit == TextUnit_Format)) && ch.isSpace())
|| ((unit == TextUnit_Line) && (ch.toLatin1() == '\n'));
}
} // namespace QWindowsUiAutomation
QT_END_NAMESPACE
#endif // QT_CONFIG(accessibility)