Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwindowsuiautils.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include <QtGui/qtguiglobal.h>
6#if QT_CONFIG(accessibility)
7
8#include "qwindowsuiautils.h"
9#include "qwindowscontext.h"
10#include "qwindowswindow.h"
11
12#include <QtGui/qwindow.h>
13#include <QtGui/private/qhighdpiscaling_p.h>
14#include <qpa/qplatforminputcontextfactory_p.h>
15
16#include <cmath>
17
18QT_BEGIN_NAMESPACE
19
20namespace QWindowsUiAutomation {
21
22// Returns the window containing the element (usually the top window),
23QWindow *windowForAccessible(const QAccessibleInterface *accessible)
24{
25 QWindow *window = accessible->window();
26 if (!window) {
27 const QAccessibleInterface *acc = accessible;
28 const QAccessibleInterface *par = accessible->parent();
29 while (par && par->isValid() && !window) {
30 window = par->window();
31 acc = par;
32 par = par->parent();
33 }
34 if (!window) {
35 // Workaround for WebEngineView not knowing its parent.
36 const auto appWindows = QGuiApplication::topLevelWindows();
37 for (QWindow *w : appWindows) {
38 if (QAccessibleInterface *root = w->accessibleRoot()) {
39 int count = root->childCount();
40 for (int i = 0; i < count; ++i) {
41 if (root->child(i) == acc)
42 return w;
43 }
44 }
45 }
46 }
47 }
48 return window;
49}
50
51// Returns the native window handle associated with the element, if any.
52// Usually it will be NULL, as Qt5 by default uses alien widgets with no native windows.
53HWND hwndForAccessible(const QAccessibleInterface *accessible)
54{
55 if (QWindow *window = accessible->window()) {
56 if (!accessible->parent() || (accessible->parent()->window() != window)) {
57 return QWindowsBaseWindow::handleOf(window);
58 }
59 }
60 return nullptr;
61}
62
63void clearVariant(VARIANT *variant)
64{
65 variant->vt = VT_EMPTY;
66 variant->punkVal = nullptr;
67}
68
69// Scales a rect to native coordinates, according to high dpi settings.
70void rectToNativeUiaRect(const QRect &rect, const QWindow *w, UiaRect *uiaRect)
71{
72 if (w && uiaRect) {
73 QRectF r = QHighDpi::toNativePixels(QRectF(rect), w);
74 uiaRect->left =r.x();
75 uiaRect->top = r.y();
76 uiaRect->width = r.width();
77 uiaRect->height = r.height();
78 }
79}
80
81// Scales a point from native coordinates, according to high dpi settings.
82void nativeUiaPointToPoint(const UiaPoint &uiaPoint, const QWindow *w, QPoint *point)
83{
84 if (w && point)
85 *point = QHighDpi::fromNativePixels(QPoint(uiaPoint.x, uiaPoint.y), w);
86}
87
88// Maps an accessibility role ID to an UI Automation control type ID.
89long roleToControlTypeId(QAccessible::Role role)
90{
91 static const QHash<QAccessible::Role, long> mapping {
92 {QAccessible::TitleBar, UIA_TitleBarControlTypeId},
93 {QAccessible::MenuBar, UIA_MenuBarControlTypeId},
94 {QAccessible::ScrollBar, UIA_ScrollBarControlTypeId},
95 {QAccessible::Grip, UIA_ThumbControlTypeId},
96 {QAccessible::Sound, UIA_CustomControlTypeId},
97 {QAccessible::Cursor, UIA_CustomControlTypeId},
98 {QAccessible::Caret, UIA_CustomControlTypeId},
99 {QAccessible::AlertMessage, UIA_WindowControlTypeId},
100 {QAccessible::Window, UIA_WindowControlTypeId},
101 {QAccessible::Client, UIA_GroupControlTypeId},
102 {QAccessible::PopupMenu, UIA_MenuControlTypeId},
103 {QAccessible::MenuItem, UIA_MenuItemControlTypeId},
104 {QAccessible::ToolTip, UIA_ToolTipControlTypeId},
105 {QAccessible::Application, UIA_CustomControlTypeId},
106 {QAccessible::Document, UIA_DocumentControlTypeId},
107 {QAccessible::Pane, UIA_PaneControlTypeId},
108 {QAccessible::Chart, UIA_CustomControlTypeId},
109 {QAccessible::Dialog, UIA_WindowControlTypeId},
110 {QAccessible::Border, UIA_CustomControlTypeId},
111 {QAccessible::Grouping, UIA_GroupControlTypeId},
112 {QAccessible::Separator, UIA_SeparatorControlTypeId},
113 {QAccessible::ToolBar, UIA_ToolBarControlTypeId},
114 {QAccessible::StatusBar, UIA_StatusBarControlTypeId},
115 {QAccessible::Table, UIA_TableControlTypeId},
116 {QAccessible::ColumnHeader, UIA_HeaderControlTypeId},
117 {QAccessible::RowHeader, UIA_HeaderControlTypeId},
118 {QAccessible::Column, UIA_HeaderItemControlTypeId},
119 {QAccessible::Row, UIA_HeaderItemControlTypeId},
120 {QAccessible::Cell, UIA_DataItemControlTypeId},
121 {QAccessible::Link, UIA_HyperlinkControlTypeId},
122 {QAccessible::HelpBalloon, UIA_ToolTipControlTypeId},
123 {QAccessible::Assistant, UIA_CustomControlTypeId},
124 {QAccessible::List, UIA_ListControlTypeId},
125 {QAccessible::ListItem, UIA_ListItemControlTypeId},
126 {QAccessible::Tree, UIA_TreeControlTypeId},
127 {QAccessible::TreeItem, UIA_TreeItemControlTypeId},
128 {QAccessible::PageTab, UIA_TabItemControlTypeId},
129 {QAccessible::PropertyPage, UIA_CustomControlTypeId},
130 {QAccessible::Indicator, UIA_CustomControlTypeId},
131 {QAccessible::Graphic, UIA_ImageControlTypeId},
132 {QAccessible::StaticText, UIA_TextControlTypeId},
133 {QAccessible::EditableText, UIA_EditControlTypeId},
134 {QAccessible::Button, UIA_ButtonControlTypeId},
135 {QAccessible::CheckBox, UIA_CheckBoxControlTypeId},
136 {QAccessible::Switch, UIA_ButtonControlTypeId},
137 {QAccessible::RadioButton, UIA_RadioButtonControlTypeId},
138 {QAccessible::ComboBox, UIA_ComboBoxControlTypeId},
139 {QAccessible::ProgressBar, UIA_ProgressBarControlTypeId},
140 {QAccessible::Dial, UIA_CustomControlTypeId},
141 {QAccessible::HotkeyField, UIA_CustomControlTypeId},
142 {QAccessible::Slider, UIA_SliderControlTypeId},
143 {QAccessible::SpinBox, UIA_SpinnerControlTypeId},
144 {QAccessible::Canvas, UIA_CustomControlTypeId},
145 {QAccessible::Animation, UIA_CustomControlTypeId},
146 {QAccessible::Equation, UIA_CustomControlTypeId},
147 {QAccessible::ButtonDropDown, UIA_ButtonControlTypeId},
148 {QAccessible::ButtonMenu, UIA_ButtonControlTypeId},
149 {QAccessible::ButtonDropGrid, UIA_ButtonControlTypeId},
150 {QAccessible::Whitespace, UIA_CustomControlTypeId},
151 {QAccessible::PageTabList, UIA_TabControlTypeId},
152 {QAccessible::Clock, UIA_CustomControlTypeId},
153 {QAccessible::Splitter, UIA_CustomControlTypeId},
154 {QAccessible::Paragraph, UIA_TextControlTypeId},
155 {QAccessible::WebDocument, UIA_DocumentControlTypeId},
156 {QAccessible::Heading, UIA_TextControlTypeId},
157 {QAccessible::BlockQuote, UIA_GroupControlTypeId},
158 {QAccessible::LayeredPane, UIA_PaneControlTypeId},
159 };
160
161 long controlType = mapping.value(role, UIA_CustomControlTypeId);
162
163 // The native OSK should be disabled if the Qt OSK is in use,
164 // or if disabled via application attribute.
165 static bool imModuleEmpty = QPlatformInputContextFactory::requested().isEmpty();
166 bool nativeVKDisabled = QCoreApplication::testAttribute(Qt::AA_DisableNativeVirtualKeyboard);
167
168 // If we want to disable the native OSK auto-showing
169 // we have to report text fields as non-editable.
170 if (controlType == UIA_EditControlTypeId && (!imModuleEmpty || nativeVKDisabled))
171 controlType = UIA_TextControlTypeId;
172
173 return controlType;
174}
175
176// True if a character can be a separator for a text unit.
177bool isTextUnitSeparator(TextUnit unit, const QChar &ch)
178{
179 return (((unit == TextUnit_Word) || (unit == TextUnit_Format)) && ch.isSpace())
180 || ((unit == TextUnit_Line) && (ch.toLatin1() == '\n'));
181}
182
183} // namespace QWindowsUiAutomation
184
185
186QT_END_NAMESPACE
187
188#endif // QT_CONFIG(accessibility)