Skip to content

fix(notch): walk the island's clipboard history with the arrow keys - #1945

Open
ruvelro wants to merge 2 commits into
vorssaint:mainfrom
ruvelro:claude/fix-clipboard-keyboard-navigation
Open

ruvelro wants to merge 2 commits into
vorssaint:mainfrom
ruvelro:claude/fix-clipboard-keyboard-navigation

Conversation

@ruvelro

@ruvelro ruvelro commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Summary

When the Dynamic Island is on, the clipboard history shortcut opens the island's Clipboard page. That page only responded to the mouse, so the arrow keys did nothing and Return could not paste. The floating quick panel already supported both.

  • ↑/↓ move a highlighted selection through the cards and scroll it into view. The first arrow lands on the newest entry, and the selection stops at either end.
  • Return (or keypad Enter) pastes the selected entry, or the newest entry if no arrow was pressed. Without Accessibility it copies, the same as clicking a card.
  • The page observes the island service (@ObservedObject), as the Scratchpad page does for its close serial, so every key press reaches the page when it is published.
  • The search field keeps focus, so typing still filters. A new filter or the pinned toggle starts the selection over. Keys typed while an input method is composing stay with the field.

Verification

  • ./build.sh --test: all suites passed. The new notch checks cover key mapping, first-key selection, stopping at the ends, and a filtered-out selection.
  • ./build.sh: bundle built.
  • Tested by hand in an installed release build: the arrow keys walk the history in the island and Return pastes the chosen entry.

🤖 Generated with Claude Code

The clipboard shortcut opens the history in the Dynamic Island when it is
on, and that page only listened to the mouse. The arrow keys now move a
highlighted selection through the cards, scrolling it into view, and
Return pastes it (or the newest entry before any arrow), as the quick
panel already did. The search field keeps the focus, so typing still
filters and a new filter starts the selection over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.onChange(of: service.clipboardKeyPress) { _, press in

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this view keeps service as a plain let, so this onchange only sees a new clipboardkeypress when the body runs for another reason. today that reason is the @appstorage above, which gives every rebuild of the page a new storage object that swiftui never finds equal to the old one. nothing ties the keys to that, and if enabled ever leaves this view the monitor still swallows the arrows and return with no effect, and a swallowed return then pastes on the next redraw, such as the next typed letter. notchscratchpadview reacts to scratchpadcloseserial the same way and holds @observedobject var service, can this view declare it like that too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in e0167df. The page now holds @ObservedObject var service, like NotchScratchpadView.

@vorssaint vorssaint added the incomplete Not mergeable as it stands. The gap is named in a comment. label Sep 24, 2026
The page held the island service as a plain `let`, so its reaction to a
clipboard key only ran when the body was rebuilt for some other reason.
Without such a rebuild the monitor swallowed the arrows and Return with no
effect, and a swallowed Return then pasted on the next redraw. The page
now observes the service, as the Scratchpad page does for its own
serial.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

incomplete Not mergeable as it stands. The gap is named in a comment.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants