Base accessibility API.
This commit is contained in:
@@ -209,6 +209,104 @@ void SceneTree::flush_transform_notifications() {
|
||||
}
|
||||
}
|
||||
|
||||
bool SceneTree::is_accessibility_enabled() const {
|
||||
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
|
||||
int screen_reader_acvite = DisplayServer::get_singleton()->accessibility_screen_reader_active();
|
||||
if ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) || ((accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_AUTO) && (screen_reader_acvite == 0))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SceneTree::is_accessibility_supported() const {
|
||||
if (!DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_ACCESSIBILITY_SCREEN_READER)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DisplayServer::AccessibilityMode accessibility_mode = DisplayServer::accessibility_get_mode();
|
||||
if (accessibility_mode == DisplayServer::AccessibilityMode::ACCESSIBILITY_DISABLED) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneTree::_accessibility_force_update() {
|
||||
accessibility_force_update = true;
|
||||
}
|
||||
|
||||
void SceneTree::_accessibility_notify_change(const Node *p_node, bool p_remove) {
|
||||
if (p_node) {
|
||||
if (p_remove) {
|
||||
accessibility_change_queue.erase(p_node->get_instance_id());
|
||||
} else {
|
||||
accessibility_change_queue.insert(p_node->get_instance_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::_process_accessibility_changes(DisplayServer::WindowID p_window_id) {
|
||||
// Process NOTIFICATION_ACCESSIBILITY_UPDATE.
|
||||
Vector<ObjectID> processed;
|
||||
for (const ObjectID &id : accessibility_change_queue) {
|
||||
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(id));
|
||||
if (!node || !node->get_window()) {
|
||||
processed.push_back(id);
|
||||
continue; // Invalid node, remove from list and skip.
|
||||
} else if (node->get_window()->get_window_id() != p_window_id) {
|
||||
continue; // Another window, skip.
|
||||
}
|
||||
node->notification(Node::NOTIFICATION_ACCESSIBILITY_UPDATE);
|
||||
processed.push_back(id);
|
||||
}
|
||||
|
||||
// Track focus change.
|
||||
// Note: Do not use `Window::get_focused_window()`, it returns both native and embedded windows, and we only care about focused element in the currently processed native window.
|
||||
// Native window focus is handled in the DisplayServer, or AccessKit subclassing adapter.
|
||||
ObjectID oid = DisplayServer::get_singleton()->window_get_attached_instance_id(p_window_id);
|
||||
Window *w_this = (Window *)ObjectDB::get_instance(oid);
|
||||
if (w_this) {
|
||||
Window *w_focus = w_this->get_focused_subwindow();
|
||||
if (w_focus && !w_focus->is_part_of_edited_scene()) {
|
||||
w_this = w_focus;
|
||||
}
|
||||
|
||||
RID new_focus_element;
|
||||
Control *n_focus = w_this->gui_get_focus_owner();
|
||||
if (n_focus && !n_focus->is_part_of_edited_scene()) {
|
||||
new_focus_element = n_focus->get_focused_accessibility_element();
|
||||
} else {
|
||||
new_focus_element = w_this->get_focused_accessibility_element();
|
||||
}
|
||||
|
||||
DisplayServer::get_singleton()->accessibility_update_set_focus(new_focus_element);
|
||||
}
|
||||
|
||||
// Cleanup.
|
||||
for (const ObjectID &id : processed) {
|
||||
accessibility_change_queue.erase(id);
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::_flush_accessibility_changes() {
|
||||
if (is_accessibility_enabled()) {
|
||||
uint64_t time = OS::get_singleton()->get_ticks_msec();
|
||||
if (!accessibility_force_update) {
|
||||
if (time - accessibility_last_update < 1000 / accessibility_upd_per_sec) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
accessibility_force_update = false;
|
||||
accessibility_last_update = time;
|
||||
|
||||
// Push update to the accessibility driver.
|
||||
DisplayServer::get_singleton()->accessibility_update_if_active(callable_mp(this, &SceneTree::_process_accessibility_changes));
|
||||
}
|
||||
}
|
||||
|
||||
void SceneTree::_flush_ugc() {
|
||||
ugc_locked = true;
|
||||
|
||||
@@ -549,6 +647,7 @@ bool SceneTree::physics_process(double p_time) {
|
||||
|
||||
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
|
||||
_flush_delete_queue();
|
||||
|
||||
_call_idle_callbacks();
|
||||
|
||||
return _quit;
|
||||
@@ -607,6 +706,8 @@ bool SceneTree::process(double p_time) {
|
||||
// This should happen last because any processing that deletes something beforehand might expect the object to be removed in the same frame.
|
||||
_flush_delete_queue();
|
||||
|
||||
_flush_accessibility_changes();
|
||||
|
||||
_call_idle_callbacks();
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
@@ -1732,6 +1833,9 @@ void SceneTree::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_root"), &SceneTree::get_root);
|
||||
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_accessibility_enabled"), &SceneTree::is_accessibility_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_accessibility_supported"), &SceneTree::is_accessibility_supported);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_auto_accept_quit"), &SceneTree::is_auto_accept_quit);
|
||||
ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit);
|
||||
ClassDB::bind_method(D_METHOD("is_quit_on_go_back"), &SceneTree::is_quit_on_go_back);
|
||||
@@ -1879,6 +1983,7 @@ SceneTree::SceneTree() {
|
||||
debug_paths_color = GLOBAL_DEF("debug/shapes/paths/geometry_color", Color(0.1, 1.0, 0.7, 0.4));
|
||||
debug_paths_width = GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "debug/shapes/paths/geometry_width", PROPERTY_HINT_RANGE, "0.01,10,0.001,or_greater"), 2.0);
|
||||
collision_debug_contacts = GLOBAL_DEF(PropertyInfo(Variant::INT, "debug/shapes/collision/max_contacts_displayed", PROPERTY_HINT_RANGE, "0,20000,1"), 10000);
|
||||
accessibility_upd_per_sec = GLOBAL_GET(SNAME("accessibility/general/updates_per_second"));
|
||||
|
||||
GLOBAL_DEF("debug/shapes/collision/draw_2d_outlines", true);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user