@@ -21,6 +21,7 @@ import androidx.compose.ui.geometry.Rect
2121import androidx.compose.ui.node.Nodes
2222import androidx.compose.ui.node.requireCoordinator
2323import androidx.compose.ui.semantics.AccessibilityAction
24+ import androidx.compose.ui.semantics.DesktopSemanticsProperties
2425import androidx.compose.ui.semantics.ProgressBarRangeInfo
2526import androidx.compose.ui.semantics.Role
2627import androidx.compose.ui.semantics.SemanticsActions
@@ -311,12 +312,11 @@ internal class ComposeAccessible(
311312 }
312313
313314 override fun getAccessibleValue (): AccessibleValue ? {
314- val role = semanticsConfig.getOrNull(SemanticsProperties .Role )
315315 // On macOS/VoiceOver, the a11y system appears to inspect the value we return here for
316316 // checkboxes and radio buttons. On Windows, it looks at getAccessibleStateSet instead.
317317 return when {
318318 toggleableState != null -> ToggleableAccessibleValue (this )
319- role == Role . RadioButton -> RadioButtonAccessibleValue (this )
319+ computeAccessibleRole() == AccessibleRole . RADIO_BUTTON -> RadioButtonAccessibleValue (this )
320320 progressBarRangeInfo != null -> ProgressBarAccessibleValue (this )
321321 else -> null
322322 }
@@ -420,19 +420,26 @@ internal class ComposeAccessible(
420420
421421 // -----------------------------------
422422
423- override fun getAccessibleRole (): AccessibleRole {
424- AccessibilityController .AccessibilityUsage .notifyInUse()
425- val fromSemanticRole = when (semanticsConfig.getOrNull(SemanticsProperties .Role )) {
423+ private fun computeAccessibleRole (): AccessibleRole {
424+ // AWT role takes precedence
425+ semanticsConfig.getOrNull(DesktopSemanticsProperties .AwtRole )?.let {
426+ return it
427+ }
428+
429+ // Check semantics role
430+ val role = semanticsConfig.getOrNull(SemanticsProperties .Role )
431+ val accessibleRole = when (role) {
426432 Role .Button -> AccessibleRole .PUSH_BUTTON
427433 Role .Checkbox , Role .Switch -> AccessibleRole .CHECK_BOX
428434 Role .RadioButton -> AccessibleRole .RADIO_BUTTON
429435 Role .Tab -> AccessibleRole .PAGE_TAB
430436 Role .DropdownList -> AccessibleRole .COMBO_BOX
431437 else -> null
432438 }
439+ if (accessibleRole != null ) return accessibleRole
433440
441+ // Guess role from other semantics properties
434442 return when {
435- fromSemanticRole != null -> fromSemanticRole
436443 isPassword -> AccessibleRole .PASSWORD_TEXT
437444 setText != null -> AccessibleRole .TEXT
438445 scrollBy != null -> AccessibleRole .SCROLL_PANE
@@ -449,6 +456,11 @@ internal class ComposeAccessible(
449456 }
450457 }
451458
459+ override fun getAccessibleRole (): AccessibleRole {
460+ AccessibilityController .AccessibilityUsage .notifyInUse()
461+ return computeAccessibleRole()
462+ }
463+
452464 override fun getAccessibleStateSet (): AccessibleStateSet {
453465 return AccessibleStateSet ().apply {
454466 // can we support these
@@ -480,12 +492,12 @@ internal class ComposeAccessible(
480492 if (canCollapse)
481493 add(AccessibleState .EXPANDED )
482494
483- when (semanticsConfig.getOrNull( SemanticsProperties . Role )) {
495+ when (computeAccessibleRole( )) {
484496 // Note that this is not executed on macOS (for checkboxes or radio buttons),
485497 // where the system inspects the value returned by getAccessibleValue instead.
486- Role . Checkbox , Role . Switch -> addCheckedStateForCheckboxOrSwitch()
487- Role . RadioButton -> addCheckedStateForRadioButton()
488- else -> { // Default case, for other (possibly null) roles
498+ AccessibleRole . CHECK_BOX -> addCheckedStateForCheckboxOrSwitch()
499+ AccessibleRole . RADIO_BUTTON -> addCheckedStateForRadioButton()
500+ else -> { // Default case for other roles
489501 addDefaultStateForToggleableState()
490502
491503 if (selected != null )
0 commit comments