| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "flutter/shell/platform/windows/accessibility_plugin.h" |
| |
| #include <variant> |
| |
| #include "flutter/fml/logging.h" |
| #include "flutter/fml/platform/win/wstring_conversion.h" |
| #include "flutter/shell/platform/common/client_wrapper/include/flutter/standard_message_codec.h" |
| #include "flutter/shell/platform/windows/flutter_windows_engine.h" |
| #include "flutter/shell/platform/windows/flutter_windows_view.h" |
| |
| namespace flutter { |
| |
| namespace { |
| |
| static constexpr char kAccessibilityChannelName[] = "flutter/accessibility"; |
| static constexpr char kTypeKey[] = "type"; |
| static constexpr char kDataKey[] = "data"; |
| static constexpr char kMessageKey[] = "message"; |
| static constexpr char kAnnounceValue[] = "announce"; |
| |
| // Handles messages like: |
| // {"type": "announce", "data": {"message": "Hello"}} |
| void HandleMessage(AccessibilityPlugin* plugin, const EncodableValue& message) { |
| const auto* map = std::get_if<EncodableMap>(&message); |
| if (!map) { |
| FML_LOG(ERROR) << "Accessibility message must be a map."; |
| return; |
| } |
| const auto& type_itr = map->find(EncodableValue{kTypeKey}); |
| const auto& data_itr = map->find(EncodableValue{kDataKey}); |
| if (type_itr == map->end()) { |
| FML_LOG(ERROR) << "Accessibility message must have a 'type' property."; |
| return; |
| } |
| if (data_itr == map->end()) { |
| FML_LOG(ERROR) << "Accessibility message must have a 'data' property."; |
| return; |
| } |
| const auto* type = std::get_if<std::string>(&type_itr->second); |
| const auto* data = std::get_if<EncodableMap>(&data_itr->second); |
| if (!type) { |
| FML_LOG(ERROR) << "Accessibility message 'type' property must be a string."; |
| return; |
| } |
| if (!data) { |
| FML_LOG(ERROR) << "Accessibility message 'data' property must be a map."; |
| return; |
| } |
| |
| if (type->compare(kAnnounceValue) == 0) { |
| const auto& message_itr = data->find(EncodableValue{kMessageKey}); |
| if (message_itr == data->end()) { |
| return; |
| } |
| const auto* message = std::get_if<std::string>(&message_itr->second); |
| if (!message) { |
| return; |
| } |
| |
| plugin->Announce(*message); |
| } else { |
| FML_LOG(WARNING) << "Accessibility message type '" << *type |
| << "' is not supported."; |
| } |
| } |
| |
| } // namespace |
| |
| AccessibilityPlugin::AccessibilityPlugin(FlutterWindowsEngine* engine) |
| : engine_(engine) {} |
| |
| void AccessibilityPlugin::SetUp(BinaryMessenger* binary_messenger, |
| AccessibilityPlugin* plugin) { |
| BasicMessageChannel<> channel{binary_messenger, kAccessibilityChannelName, |
| &StandardMessageCodec::GetInstance()}; |
| |
| channel.SetMessageHandler( |
| [plugin](const EncodableValue& message, |
| const MessageReply<EncodableValue>& reply) { |
| HandleMessage(plugin, message); |
| |
| // The accessibility channel does not support error handling. |
| // Always return an empty response even on failure. |
| reply(EncodableValue{std::monostate{}}); |
| }); |
| } |
| |
| void AccessibilityPlugin::Announce(const std::string_view message) { |
| if (!engine_->semantics_enabled()) { |
| return; |
| } |
| |
| // TODO(loicsharma): Remove implicit view assumption. |
| // https://github.com/flutter/flutter/issues/142845 |
| auto view = engine_->view(kImplicitViewId); |
| if (!view) { |
| return; |
| } |
| |
| std::wstring wide_text = fml::Utf8ToWideString(message); |
| view->AnnounceAlert(wide_text); |
| } |
| |
| } // namespace flutter |