"""Assistive Technology Integration - TASK_57 Phase 2 Implementation.
Screen reader, voice control, and accessibility tool support for automation workflows.
Provides comprehensive assistive technology integration and compatibility testing.
Architecture: Assistive Tech Integration + Compatibility Testing + Voice Control
+ Screen Reader Support
Performance: <200ms assistive tech operations, efficient integration testing
Security: Safe assistive tech integration, secure voice processing
"""
from __future__ import annotations
import logging
from dataclasses import dataclass, field
from datetime import UTC, datetime
from typing import Any
from src.core.accessibility_architecture import (
AccessibilityIssue,
AccessibilityTestId,
AssistiveTechConfig,
AssistiveTechError,
AssistiveTechId,
AssistiveTechnology,
SeverityLevel,
TestResult,
TestStatus,
create_assistive_tech_id,
create_test_result_id,
)
from src.core.constants import (
ACCESSIBILITY_ACCEPTABLE_SCORE,
ACCESSIBILITY_BATTERY_ALERT,
ACCESSIBILITY_BATTERY_HIGH,
ACCESSIBILITY_BATTERY_LOW,
ACCESSIBILITY_BATTERY_MEDIUM,
ACCESSIBILITY_CONFIDENCE_THRESHOLD,
ACCESSIBILITY_SCAN_SPEED_MAX,
ACCESSIBILITY_SCAN_SPEED_MIN,
SENSITIVITY_MAX,
VOICE_PITCH_MAX,
VOICE_RATE_MAX,
)
from src.core.contracts import require
from src.core.either import Either
logger = logging.getLogger(__name__)
@dataclass(frozen=True)
class AssistiveTechCapability:
"""Capability definition for assistive technology."""
capability_id: str
name: str
description: str
technology: AssistiveTechnology
input_methods: list[str] = field(default_factory=list)
output_methods: list[str] = field(default_factory=list)
supported_platforms: list[str] = field(default_factory=list)
configuration_options: dict[str, Any] = field(default_factory=dict)
@dataclass(frozen=True)
class VoiceCommand:
"""Voice command definition for voice control integration."""
command_id: str
trigger_phrase: str
action: str
parameters: dict[str, Any] = field(default_factory=dict)
confidence_threshold: float = 0.8
enabled: bool = True
def __post_init__(self):
if not (0.0 <= self.confidence_threshold <= 1.0):
raise ValueError("Confidence threshold must be between 0.0 and 1.0")
@dataclass(frozen=True)
class ScreenReaderConfig:
"""Configuration for screen reader integration."""
reader_name: str
version: str
voice_settings: dict[str, Any] = field(default_factory=dict)
navigation_mode: str = "browse"
verbosity_level: str = "normal"
announcement_settings: dict[str, Any] = field(default_factory=dict)
keyboard_shortcuts: dict[str, str] = field(default_factory=dict)
@dataclass(frozen=True)
class AssistiveTechTestScenario:
"""Test scenario for assistive technology compatibility."""
scenario_id: str
name: str
description: str
technology: AssistiveTechnology
test_steps: list[str] = field(default_factory=list)
expected_outcomes: list[str] = field(default_factory=list)
success_criteria: list[str] = field(default_factory=list)
automation_compatible: bool = True
class AssistiveTechIntegrationManager:
"""Comprehensive assistive technology integration manager."""
def __init__(self):
self.registered_technologies: dict[AssistiveTechId, AssistiveTechConfig] = {}
self.voice_commands: dict[str, VoiceCommand] = {}
self.screen_reader_configs: dict[str, ScreenReaderConfig] = {}
self.test_scenarios: dict[str, AssistiveTechTestScenario] = {}
self.capabilities: dict[AssistiveTechnology, list[AssistiveTechCapability]] = {}
self._initialize_default_configurations()
def _initialize_default_configurations(self) -> bool:
"""Initialize default assistive technology configurations."""
# Screen Reader Capabilities
self.capabilities[AssistiveTechnology.SCREEN_READER] = [
AssistiveTechCapability(
capability_id="sr_text_reading",
name="Text Reading",
description="Read text content aloud",
technology=AssistiveTechnology.SCREEN_READER,
input_methods=["keyboard", "mouse"],
output_methods=["speech", "braille"],
supported_platforms=["macos", "windows", "linux"],
configuration_options={
"voice_speed": "adjustable",
"voice_pitch": "adjustable",
},
),
AssistiveTechCapability(
capability_id="sr_navigation",
name="Screen Navigation",
description="Navigate interface elements",
technology=AssistiveTechnology.SCREEN_READER,
input_methods=["keyboard"],
output_methods=["speech"],
supported_platforms=["macos", "windows", "linux"],
configuration_options={"navigation_mode": ["browse", "focus", "forms"]},
),
]
# Voice Control Capabilities
self.capabilities[AssistiveTechnology.VOICE_CONTROL] = [
AssistiveTechCapability(
capability_id="vc_command_recognition",
name="Voice Command Recognition",
description="Recognize and execute voice commands",
technology=AssistiveTechnology.VOICE_CONTROL,
input_methods=["microphone"],
output_methods=["system_actions", "speech_feedback"],
supported_platforms=["macos", "windows"],
configuration_options={
"language": "configurable",
"noise_filtering": "adaptive",
},
),
AssistiveTechCapability(
capability_id="vc_dictation",
name="Voice Dictation",
description="Convert speech to text input",
technology=AssistiveTechnology.VOICE_CONTROL,
input_methods=["microphone"],
output_methods=["text_input"],
supported_platforms=["macos", "windows", "ios", "android"],
configuration_options={
"accuracy_mode": ["fast", "accurate"],
"custom_vocabulary": "supported",
},
),
]
# Default Screen Reader Configurations
self.screen_reader_configs["voiceover"] = ScreenReaderConfig(
reader_name="VoiceOver",
version="macOS",
voice_settings={"voice": "Alex", "rate": 50, "pitch": 50},
navigation_mode="browse",
verbosity_level="normal",
announcement_settings={
"announce_notifications": True,
"announce_typed_characters": True,
},
keyboard_shortcuts={
"read_all": "Control+Option+A",
"next_element": "Control+Option+Right",
},
)
# Default Voice Commands
self._initialize_default_voice_commands()
# Default Test Scenarios
self._initialize_default_test_scenarios()
def _initialize_default_voice_commands(self) -> bool:
"""Initialize default voice commands for automation."""
voice_commands = [
VoiceCommand(
command_id="run_macro",
trigger_phrase="run macro",
action="execute_macro",
parameters={"macro_name": "voice_parameter"},
confidence_threshold=0.85,
),
VoiceCommand(
command_id="stop_automation",
trigger_phrase="stop automation",
action="cancel_execution",
parameters={},
confidence_threshold=0.9,
),
VoiceCommand(
command_id="show_help",
trigger_phrase="accessibility help",
action="show_accessibility_help",
parameters={},
confidence_threshold=0.8,
),
]
for command in voice_commands:
self.voice_commands[command.command_id] = command
def _initialize_default_test_scenarios(self) -> bool:
"""Initialize default assistive technology test scenarios."""
scenarios = [
AssistiveTechTestScenario(
scenario_id="sr_navigation_test",
name="Screen Reader Navigation Test",
description="Test automation workflow navigation with screen reader",
technology=AssistiveTechnology.SCREEN_READER,
test_steps=[
"Start screen reader",
"Navigate to automation interface",
"Execute macro using keyboard shortcuts",
"Verify output is announced",
],
expected_outcomes=[
"All interface elements are properly announced",
"Macro execution feedback is provided",
"Navigation is logical and efficient",
],
success_criteria=[
"100% of interactive elements have accessible names",
"Macro status changes are announced",
"Error messages are clearly communicated",
],
),
AssistiveTechTestScenario(
scenario_id="vc_automation_test",
name="Voice Control Automation Test",
description="Test automation workflow execution using voice commands",
technology=AssistiveTechnology.VOICE_CONTROL,
test_steps=[
"Enable voice control",
"Issue voice command to run automation",
"Monitor execution progress",
"Verify completion notification",
],
expected_outcomes=[
"Voice commands are recognized accurately",
"Automation executes as intended",
"Progress feedback is provided",
],
success_criteria=[
"Voice command recognition >90% accuracy",
"Automation completes successfully",
"Audio feedback confirms completion",
],
),
]
for scenario in scenarios:
self.test_scenarios[scenario.scenario_id] = scenario
@require(lambda __self, config: config.name.strip() != "")
async def register_assistive_technology(
self,
config: AssistiveTechConfig,
) -> Either[AssistiveTechError, AssistiveTechId]:
"""Register assistive technology configuration."""
try:
tech_id = create_assistive_tech_id()
# Validate configuration
validation_result = await self._validate_assistive_tech_config(config)
if validation_result.is_left():
return validation_result
# Register the technology
updated_config = AssistiveTechConfig(
tech_id=tech_id,
technology=config.technology,
name=config.name,
version=config.version,
settings=config.settings,
test_scenarios=config.test_scenarios,
compatibility_requirements=config.compatibility_requirements,
)
self.registered_technologies[tech_id] = updated_config
return Either.right(tech_id)
except Exception as e:
return Either.left(
AssistiveTechError(f"Failed to register assistive technology: {e!s}"),
)
async def _validate_assistive_tech_config(
self,
config: AssistiveTechConfig,
) -> Either[AssistiveTechError, None]:
"""Validate assistive technology configuration."""
try:
# Check required fields
if not config.name.strip():
return Either.left(
AssistiveTechError("Assistive technology name is required"),
)
if not config.version.strip():
return Either.left(
AssistiveTechError("Assistive technology version is required"),
)
# Validate technology type
if config.technology not in AssistiveTechnology:
return Either.left(
AssistiveTechError(
f"Unsupported assistive technology: {config.technology}",
),
)
# Validate settings based on technology type
validation_result = await self._validate_technology_specific_settings(
config,
)
if validation_result.is_left():
return validation_result
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(f"Configuration validation failed: {e!s}"),
)
async def _validate_technology_specific_settings(
self,
config: AssistiveTechConfig,
) -> Either[AssistiveTechError, None]:
"""Validate technology-specific settings."""
try:
if config.technology == AssistiveTechnology.SCREEN_READER:
return await self._validate_screen_reader_settings(config.settings)
if config.technology == AssistiveTechnology.VOICE_CONTROL:
return await self._validate_voice_control_settings(config.settings)
if config.technology == AssistiveTechnology.SWITCH_ACCESS:
return await self._validate_switch_access_settings(config.settings)
# Generic validation for other technologies
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(f"Technology-specific validation failed: {e!s}"),
)
async def _validate_screen_reader_settings(
self,
settings: dict[str, Any],
) -> Either[AssistiveTechError, None]:
"""Validate screen reader specific settings."""
try:
# Validate voice settings
if "voice_settings" in settings:
voice_settings = settings["voice_settings"]
if "rate" in voice_settings:
rate = voice_settings["rate"]
if not isinstance(rate, int | float) or not (
0 <= rate <= VOICE_RATE_MAX
):
return Either.left(
AssistiveTechError("Voice rate must be between 0 and 100"),
)
if "pitch" in voice_settings:
pitch = voice_settings["pitch"]
if not isinstance(pitch, int | float) or not (
0 <= pitch <= VOICE_PITCH_MAX
):
return Either.left(
AssistiveTechError("Voice pitch must be between 0 and 100"),
)
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(
f"Screen reader settings validation failed: {e!s}",
),
)
async def _validate_voice_control_settings(
self,
settings: dict[str, Any],
) -> Either[AssistiveTechError, None]:
"""Validate voice control specific settings."""
try:
# Validate microphone settings
if "microphone_settings" in settings:
mic_settings = settings["microphone_settings"]
if "sensitivity" in mic_settings:
sensitivity = mic_settings["sensitivity"]
if not isinstance(sensitivity, int | float) or not (
0 <= sensitivity <= SENSITIVITY_MAX
):
return Either.left(
AssistiveTechError(
"Microphone sensitivity must be between 0 and 100",
),
)
# Validate language settings
if "language" in settings:
supported_languages = ["en-US", "en-GB", "es-ES", "fr-FR", "de-DE"]
if settings["language"] not in supported_languages:
return Either.left(
AssistiveTechError(
f"Unsupported language: {settings['language']}",
),
)
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(
f"Voice control settings validation failed: {e!s}",
),
)
async def _validate_switch_access_settings(
self,
settings: dict[str, Any],
) -> Either[AssistiveTechError, None]:
"""Validate switch access specific settings."""
try:
# Validate switch configuration
if "switch_configuration" in settings:
switch_config = settings["switch_configuration"]
if "scan_speed" in switch_config:
scan_speed = switch_config["scan_speed"]
if not isinstance(scan_speed, int | float) or not (
ACCESSIBILITY_SCAN_SPEED_MIN
<= scan_speed
<= ACCESSIBILITY_SCAN_SPEED_MAX
):
return Either.left(
AssistiveTechError(
"Scan speed must be between 0.1 and 10.0 seconds",
),
)
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(
f"Switch access settings validation failed: {e!s}",
),
)
@require(lambda self, tech_id: tech_id in self.registered_technologies)
async def test_assistive_tech_compatibility(
self,
tech_id: AssistiveTechId,
automation_target: str,
test_scenarios: list[str] | None = None,
) -> Either[AssistiveTechError, TestResult]:
"""Test assistive technology compatibility with automation workflows."""
try:
config = self.registered_technologies[tech_id]
# Determine test scenarios to run
if test_scenarios is None:
test_scenarios = config.test_scenarios
if not test_scenarios:
# Use default scenarios for the technology type
default_scenarios = [
scenario_id
for scenario_id, scenario in self.test_scenarios.items()
if scenario.technology == config.technology
]
test_scenarios = default_scenarios
# Execute compatibility tests
test_result_id = create_test_result_id()
test_id = AccessibilityTestId(
f"compat_{tech_id}_{datetime.now(UTC).timestamp()}",
)
start_time = datetime.now(UTC)
issues: list[AccessibilityIssue] = []
total_checks = len(test_scenarios)
passed_checks = 0
failed_checks = 0
for scenario_id in test_scenarios:
if scenario_id in self.test_scenarios:
scenario = self.test_scenarios[scenario_id]
scenario_result = await self._execute_test_scenario(
scenario,
automation_target,
config,
)
if scenario_result.is_left():
failed_checks += 1
# Create issue for failed scenario
issue = AccessibilityIssue(
issue_id=f"compat_{scenario_id}_{datetime.now(UTC).timestamp()}",
rule_id=f"at_compat_{scenario.technology.value}",
element_selector=automation_target,
description=(
f"Assistive technology compatibility issue: "
f"{scenario.name}"
),
severity=SeverityLevel.HIGH,
suggested_fix=(
f"Review {scenario.name} compatibility requirements"
),
)
issues.append(issue)
else:
passed_checks += 1
end_time = datetime.now(UTC)
compliance_score = (
(passed_checks / total_checks * 100.0) if total_checks > 0 else 0.0
)
test_result = TestResult(
result_id=test_result_id,
test_id=test_id,
status=TestStatus.COMPLETED,
start_time=start_time,
end_time=end_time,
total_checks=total_checks,
passed_checks=passed_checks,
failed_checks=failed_checks,
issues=issues,
compliance_score=compliance_score,
details={
"assistive_technology": config.technology.value,
"technology_name": config.name,
"scenarios_tested": test_scenarios,
"automation_target": automation_target,
},
)
return Either.right(test_result)
except Exception as e:
return Either.left(
AssistiveTechError(f"Compatibility testing failed: {e!s}"),
)
async def _execute_test_scenario(
self,
scenario: AssistiveTechTestScenario,
automation_target: str,
config: AssistiveTechConfig,
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Execute a specific assistive technology test scenario."""
try:
# Simulate test scenario execution
# In a real implementation, this would actually test the assistive
# technology
if scenario.technology == AssistiveTechnology.SCREEN_READER:
return await self._test_screen_reader_scenario(
scenario,
automation_target,
config,
)
if scenario.technology == AssistiveTechnology.VOICE_CONTROL:
return await self._test_voice_control_scenario(
scenario,
automation_target,
config,
)
if scenario.technology == AssistiveTechnology.SWITCH_ACCESS:
return await self._test_switch_access_scenario(
scenario,
automation_target,
config,
)
return await self._test_generic_scenario(
scenario,
automation_target,
config,
)
except Exception as e:
return Either.left(
AssistiveTechError(f"Test scenario execution failed: {e!s}"),
)
async def _test_screen_reader_scenario(
self,
scenario: AssistiveTechTestScenario,
_automation_target: str, # ARG002 fix: Prefix unused parameter
_config: AssistiveTechConfig, # ARG002 fix: Prefix unused parameter
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Test screen reader compatibility scenario."""
try:
# Simulate screen reader testing
results = {
"scenario_id": scenario.scenario_id,
"accessible_elements": 95, # % elements with proper accessibility
"keyboard_navigation": "functional",
"screen_reader_announcements": "clear",
"focus_management": "proper",
"error_handling": "accessible",
}
# Check if results meet success criteria
success_rate = 0.9 # 90% success rate for this simulation
if (
success_rate >= ACCESSIBILITY_CONFIDENCE_THRESHOLD
): # 80% threshold for passing
return Either.right(results)
return Either.left(
AssistiveTechError(
f"Screen reader scenario failed: {scenario.name}",
),
)
except Exception as e:
return Either.left(
AssistiveTechError(f"Screen reader scenario testing failed: {e!s}"),
)
async def _test_voice_control_scenario(
self,
scenario: AssistiveTechTestScenario,
_automation_target: str, # ARG002 fix: Prefix unused parameter
_config: AssistiveTechConfig, # ARG002 fix: Prefix unused parameter
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Test voice control compatibility scenario."""
try:
# Simulate voice control testing
results = {
"scenario_id": scenario.scenario_id,
"command_recognition_rate": 92, # Percentage
"response_time_ms": 150,
"accuracy_rate": 88, # Percentage
"noise_resilience": "good",
"vocabulary_coverage": "comprehensive",
}
# Check if results meet success criteria
if (
results["command_recognition_rate"] >= ACCESSIBILITY_BATTERY_HIGH
and results["accuracy_rate"] >= ACCESSIBILITY_BATTERY_MEDIUM
):
return Either.right(results)
return Either.left(
AssistiveTechError(
f"Voice control scenario failed: {scenario.name}",
),
)
except Exception as e:
return Either.left(
AssistiveTechError(f"Voice control scenario testing failed: {e!s}"),
)
async def _test_switch_access_scenario(
self,
scenario: AssistiveTechTestScenario,
_automation_target: str, # ARG002 fix: Prefix unused parameter
_config: AssistiveTechConfig, # ARG002 fix: Prefix unused parameter
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Test switch access compatibility scenario."""
try:
# Simulate switch access testing
results = {
"scenario_id": scenario.scenario_id,
"scan_efficiency": 85, # Percentage
"target_acquisition_time": 2.5, # Seconds
"error_rate": 5, # Percentage
"navigation_completeness": "full",
"customization_support": "extensive",
}
# Check if results meet success criteria
if (
results["scan_efficiency"] >= ACCESSIBILITY_BATTERY_LOW
and results["error_rate"] <= ACCESSIBILITY_BATTERY_ALERT
):
return Either.right(results)
return Either.left(
AssistiveTechError(
f"Switch access scenario failed: {scenario.name}",
),
)
except Exception as e:
return Either.left(
AssistiveTechError(f"Switch access scenario testing failed: {e!s}"),
)
async def _test_generic_scenario(
self,
scenario: AssistiveTechTestScenario,
_automation_target: str, # ARG002 fix: Prefix unused parameter
_config: AssistiveTechConfig, # ARG002 fix: Prefix unused parameter
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Test generic assistive technology scenario."""
try:
# Simulate generic assistive technology testing
results = {
"scenario_id": scenario.scenario_id,
"compatibility_score": 82, # Percentage
"usability_rating": "good",
"performance_impact": "minimal",
"integration_quality": "satisfactory",
}
if results["compatibility_score"] >= ACCESSIBILITY_ACCEPTABLE_SCORE:
return Either.right(results)
return Either.left(
AssistiveTechError(f"Generic scenario failed: {scenario.name}"),
)
except Exception as e:
return Either.left(
AssistiveTechError(f"Generic scenario testing failed: {e!s}"),
)
def get_supported_technologies(self) -> list[AssistiveTechnology]:
"""Get list of supported assistive technologies."""
return list(AssistiveTechnology)
def get_technology_capabilities(
self,
technology: AssistiveTechnology,
) -> list[AssistiveTechCapability]:
"""Get capabilities for a specific assistive technology."""
return self.capabilities.get(technology, [])
def get_registered_technologies(self) -> list[AssistiveTechConfig]:
"""Get all registered assistive technology configurations."""
return list(self.registered_technologies.values())
def get_voice_commands(self) -> list[VoiceCommand]:
"""Get all configured voice commands."""
return list(self.voice_commands.values())
def get_test_scenarios(
self,
technology: AssistiveTechnology | None = None,
) -> list[AssistiveTechTestScenario]:
"""Get test scenarios for a specific technology or all scenarios."""
if technology is None:
return list(self.test_scenarios.values())
return [
scenario
for scenario in self.test_scenarios.values()
if scenario.technology == technology
]
# FIXME: Contract disabled - @require(lambda __self, command:
# command.confidence_threshold >= 0.0)
def add_voice_command(
self,
command: VoiceCommand,
) -> Either[AssistiveTechError, None]:
"""Add custom voice command for automation control."""
try:
if command.command_id in self.voice_commands:
return Either.left(
AssistiveTechError(
f"Voice command {command.command_id} already exists",
),
)
self.voice_commands[command.command_id] = command
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(f"Failed to add voice command: {e!s}"),
)
def remove_voice_command(self, command_id: str) -> Either[AssistiveTechError, None]:
"""Remove voice command."""
try:
if command_id not in self.voice_commands:
return Either.left(
AssistiveTechError(f"Voice command {command_id} not found"),
)
del self.voice_commands[command_id]
return Either.right(None)
except Exception as e:
return Either.left(
AssistiveTechError(f"Failed to remove voice command: {e!s}"),
)
class AccessibilityOptimizer:
"""Optimizer for improving assistive technology compatibility."""
def __init__(self, integration_manager: AssistiveTechIntegrationManager):
self.integration_manager = integration_manager
async def optimize_for_assistive_tech(
self,
automation_workflow: str,
target_technologies: list[AssistiveTechnology],
) -> Either[AssistiveTechError, dict[str, Any]]:
"""Optimize automation workflow for assistive technology compatibility."""
try:
optimizations = {}
for technology in target_technologies:
tech_optimizations = await self._generate_technology_optimizations(
automation_workflow,
technology,
)
if tech_optimizations.is_left():
return tech_optimizations
optimizations[technology.value] = tech_optimizations.get_right()
return Either.right(
{
"workflow": automation_workflow,
"optimizations": optimizations,
"optimization_timestamp": datetime.now(UTC).isoformat(),
},
)
except Exception as e:
return Either.left(AssistiveTechError(f"Optimization failed: {e!s}"))
async def _generate_technology_optimizations(
self,
_workflow: str,
technology: AssistiveTechnology, # ARG002 fix: Prefix unused parameter
) -> Either[AssistiveTechError, list[dict[str, Any]]]:
"""Generate optimizations for a specific assistive technology."""
try:
optimizations = []
if technology == AssistiveTechnology.SCREEN_READER:
optimizations.extend(
[
{
"type": "accessibility_labels",
"description": "Add descriptive labels to all interactive elements",
"priority": "high",
"implementation": "Ensure all buttons, inputs, and controls have accessible names",
},
{
"type": "heading_structure",
"description": "Implement proper heading hierarchy",
"priority": "medium",
"implementation": "Use H1-H6 tags in logical order",
},
],
)
elif technology == AssistiveTechnology.VOICE_CONTROL:
optimizations.extend(
[
{
"type": "voice_commands",
"description": "Add voice command shortcuts for common actions",
"priority": "high",
"implementation": "Implement voice command recognition for macro execution",
},
{
"type": "confirmation_feedback",
"description": "Provide audio confirmation for voice-initiated actions",
"priority": "medium",
"implementation": "Add speech synthesis for action confirmations",
},
],
)
elif technology == AssistiveTechnology.KEYBOARD_NAVIGATION:
optimizations.extend(
[
{
"type": "keyboard_shortcuts",
"description": "Implement comprehensive keyboard shortcuts",
"priority": "high",
"implementation": "Ensure all functionality is keyboard accessible",
},
{
"type": "focus_indicators",
"description": "Add visible focus indicators",
"priority": "high",
"implementation": "Enhance focus styling for better visibility",
},
],
)
return Either.right(optimizations)
except Exception as e:
return Either.left(
AssistiveTechError(
f"Technology optimization generation failed: {e!s}",
),
)
def get_optimization_recommendations(
self,
issues: list[AccessibilityIssue],
target_technologies: list[AssistiveTechnology],
) -> list[dict[str, Any]]:
"""Get optimization recommendations based on accessibility issues."""
recommendations = []
for issue in issues:
for technology in target_technologies:
recommendation = self._generate_issue_recommendation(issue, technology)
if recommendation:
recommendations.append(recommendation)
return recommendations
def _generate_issue_recommendation(
self,
issue: AccessibilityIssue,
technology: AssistiveTechnology,
) -> dict[str, Any] | None:
"""Generate recommendation for a specific issue and technology."""
recommendation_mapping = {
(AssistiveTechnology.SCREEN_READER, "alt_text_missing"): {
"recommendation": "Add descriptive alt text for screen reader users",
"implementation": "Provide meaningful descriptions of image content and function",
"priority": "high",
},
(AssistiveTechnology.VOICE_CONTROL, "keyboard_focus"): {
"recommendation": "Ensure voice control can interact with focused elements",
"implementation": "Add voice command support for focus management",
"priority": "medium",
},
(AssistiveTechnology.KEYBOARD_NAVIGATION, "form_labels"): {
"recommendation": "Associate labels with form controls for keyboard users",
"implementation": "Use proper label-input relationships",
"priority": "high",
},
}
key = (technology, issue.rule_id)
if key in recommendation_mapping:
recommendation = recommendation_mapping[key].copy()
recommendation.update(
{
"issue_id": issue.issue_id,
"technology": technology.value,
"severity": issue.severity.value,
},
)
return recommendation
return None