From f5f521634923731aafb2ce3b839b411593afe56a Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:02:55 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Add=20tooltips=20?= =?UTF-8?q?and=20accessibility=20labels=20to=20media=20keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Added `.help(label)` and `.accessibilityLabel(label)` to the icon-only media keys in the on-screen keyboard, and passed descriptive labels instead of empty strings. 🎯 Why: Icon-only buttons without labels are inaccessible to screen readers and lack hover context for visual users. ♿ Accessibility: Improved VoiceOver navigation and general usability by explicitly announcing the function of the media buttons. Co-authored-by: NSEvent <44446865+NSEvent@users.noreply.github.com> --- .Jules/palette.md | 3 +++ .../Components/OnScreenKeyboardView.swift | 20 +++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/.Jules/palette.md b/.Jules/palette.md index f61603c8..7fa484d6 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -25,3 +25,6 @@ ## 2026-06-23 - [SwiftUI Button Accessibility] **Learning:** Found a pattern where SwiftUI icon-only buttons or minimal UI elements were given `.help()` modifiers for hover tooltips but lacked `.accessibilityLabel()` modifiers for screen readers. **Action:** When adding `.help()` to buttons, always pair it with a corresponding `.accessibilityLabel()` to ensure full accessibility. +## 2023-10-27 - [Tooltips and Accessibility Labels on Media Keys] +**Learning:** Icon-only media keys in the on-screen keyboard were missing accessibility labels and tooltips, which makes them inaccessible to screen readers and harder to understand for visual users. +**Action:** Add `.help()` and `.accessibilityLabel()` to icon-only buttons like media playback controls, supplying meaningful descriptive text instead of empty strings. diff --git a/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift b/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift index 7e1833b5..660b2278 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift @@ -534,20 +534,20 @@ struct OnScreenKeyboardView: View { private var mediaControlsRow: some View { HStack(spacing: keySpacing * 6) { mediaControlGroup(title: "PLAYBACK", icon: "play.circle.fill") { - mediaKey(KeyCodeMapping.mediaPrevious, label: "", symbol: "backward.end.fill", keyboardRow: mediaRowIndex, column: 0) - mediaKey(KeyCodeMapping.mediaPlayPause, label: "", symbol: "playpause.fill", keyboardRow: mediaRowIndex, column: 1) - mediaKey(KeyCodeMapping.mediaNext, label: "", symbol: "forward.end.fill", keyboardRow: mediaRowIndex, column: 2) + mediaKey(KeyCodeMapping.mediaPrevious, label: "Previous Track", symbol: "backward.end.fill", keyboardRow: mediaRowIndex, column: 0) + mediaKey(KeyCodeMapping.mediaPlayPause, label: "Play/Pause", symbol: "playpause.fill", keyboardRow: mediaRowIndex, column: 1) + mediaKey(KeyCodeMapping.mediaNext, label: "Next Track", symbol: "forward.end.fill", keyboardRow: mediaRowIndex, column: 2) } mediaControlGroup(title: "SOUND", icon: "speaker.wave.2.fill") { - mediaKey(KeyCodeMapping.volumeMute, label: "", symbol: "speaker.slash.fill", keyboardRow: mediaRowIndex, column: 3) - mediaKey(KeyCodeMapping.volumeDown, label: "", symbol: "speaker.wave.1.fill", keyboardRow: mediaRowIndex, column: 4) - mediaKey(KeyCodeMapping.volumeUp, label: "", symbol: "speaker.wave.3.fill", keyboardRow: mediaRowIndex, column: 5) + mediaKey(KeyCodeMapping.volumeMute, label: "Mute", symbol: "speaker.slash.fill", keyboardRow: mediaRowIndex, column: 3) + mediaKey(KeyCodeMapping.volumeDown, label: "Volume Down", symbol: "speaker.wave.1.fill", keyboardRow: mediaRowIndex, column: 4) + mediaKey(KeyCodeMapping.volumeUp, label: "Volume Up", symbol: "speaker.wave.3.fill", keyboardRow: mediaRowIndex, column: 5) } mediaControlGroup(title: "DISPLAY", icon: "sun.max.fill") { - mediaKey(KeyCodeMapping.brightnessDown, label: "", symbol: "sun.min.fill", keyboardRow: mediaRowIndex, column: 6) - mediaKey(KeyCodeMapping.brightnessUp, label: "", symbol: "sun.max.fill", keyboardRow: mediaRowIndex, column: 7) + mediaKey(KeyCodeMapping.brightnessDown, label: "Brightness Down", symbol: "sun.min.fill", keyboardRow: mediaRowIndex, column: 6) + mediaKey(KeyCodeMapping.brightnessUp, label: "Brightness Up", symbol: "sun.max.fill", keyboardRow: mediaRowIndex, column: 7) } } .padding(.vertical, 4) @@ -600,6 +600,8 @@ struct OnScreenKeyboardView: View { .animation(.spring(response: 0.3, dampingFraction: 0.6), value: isHighlighted) } .buttonStyle(.plain) + .help(label) + .accessibilityLabel(label) .navigationItemBounds(.keyPosition(row: keyboardRow, column: column)) .onHover { hovering in hoveredKey = hovering ? keyCode : nil @@ -941,6 +943,8 @@ struct OnScreenKeyboardView: View { .animation(.spring(response: 0.3, dampingFraction: 0.7), value: isHighlighted) } .buttonStyle(.plain) + .help(label) + .accessibilityLabel(label) .navigationItemBounds(.keyPosition(row: keyboardRow, column: column)) .onHover { hovering in hoveredKey = hovering ? keyCode : nil From 579080b4e17d70f1d648b58ed368ce59ce72ab50 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 09:14:52 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20Add=20tooltips=20?= =?UTF-8?q?and=20accessibility=20labels=20to=20media=20keys=20(Fixed=20bui?= =?UTF-8?q?ld=20issue)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 💡 What: Removed erroneously applied `.help(label)` and `.accessibilityLabel(label)` from `capsLockKey` which lacked the `label` parameter in scope, fixing a compilation error. The media keys continue to have the correct labels applied. 🎯 Why: CI failed due to the scoping issue. ♿ Accessibility: Improved VoiceOver navigation and general usability by explicitly announcing the function of the media buttons. Co-authored-by: NSEvent <44446865+NSEvent@users.noreply.github.com> --- .../Views/Components/OnScreenKeyboardView.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift b/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift index 660b2278..1fda76ed 100644 --- a/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift +++ b/XboxControllerMapper/XboxControllerMapper/Views/Components/OnScreenKeyboardView.swift @@ -943,8 +943,6 @@ struct OnScreenKeyboardView: View { .animation(.spring(response: 0.3, dampingFraction: 0.7), value: isHighlighted) } .buttonStyle(.plain) - .help(label) - .accessibilityLabel(label) .navigationItemBounds(.keyPosition(row: keyboardRow, column: column)) .onHover { hovering in hoveredKey = hovering ? keyCode : nil