Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@ follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/); versions
correspond to [GitHub Releases](https://github.com/archdex-art/SuperSearch/releases)
and their published installers.

## [0.1.17] — 2026-07-17

Fixes the actual root cause behind the "hotkey doesn't work" reports: the
capture UI itself could persist a corrupted shortcut.

### Fixed
- **Rebinding the hotkey to an Option/Alt combo could silently corrupt it.**
Live log evidence: `Global shortcut registration failed ... error=Found
empty token while parsing hotkey: Alt+\u{a0}`. The General pane's capture
UI built the accelerator from `KeyboardEvent.key` — the *composed*
character — but macOS recomposes many keys under Option into a different
Unicode character than what's printed on the keycap: Option+Space's `key`
is a non-breaking space (U+00A0), not a plain `" "`, and Option+letters
compose accented characters (Option+C → "ç"). The capture UI showed
"Alt+Space" (the *display* used the physical key label) but silently
persisted `"Alt+<NBSP>"` (built from the composed character) to
`settings.json` — invisible until the next boot's registration attempt
rejected it outright. The 0.1.15/0.1.16 self-heal recovered the hotkey
back to the default afterward, but the underlying capture bug meant
rebinding to *any* Option combo reproduced it every time.
`toAccelerator` now resolves letters/digits/Space from
`KeyboardEvent.code` (the physical key, unaffected by modifier
composition) instead of `key`. Verified live: simulated the exact
Option+Space event macOS actually sends (`code: "Space", key: "\u00A0"`)
and confirmed it now captures as `Alt+Space`; same for Option+C
(`key: "ç"`) capturing as `Alt+C`.

## [0.1.16] — 2026-07-17

Fixes the hotkey going completely silent instead of just "unreliable."
Expand Down Expand Up @@ -431,7 +458,8 @@ First cross-platform release — macOS, Linux, and Windows.

---

[Unreleased]: https://github.com/archdex-art/SuperSearch/compare/v0.1.16...HEAD
[Unreleased]: https://github.com/archdex-art/SuperSearch/compare/v0.1.17...HEAD
[0.1.17]: https://github.com/archdex-art/SuperSearch/releases/tag/v0.1.17
[0.1.16]: https://github.com/archdex-art/SuperSearch/releases/tag/v0.1.16
[0.1.15]: https://github.com/archdex-art/SuperSearch/releases/tag/v0.1.15
[0.1.14]: https://github.com/archdex-art/SuperSearch/releases/tag/v0.1.14
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 28 additions & 4 deletions react-command-palette/settings/panes/General.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,37 @@ function toAccelerator(e: KeyboardEvent): string | null {
if (e.altKey) mods.push("Alt");
if (e.shiftKey) mods.push("Shift");
if (mods.length === 0) return null; // require at least one modifier
let key = e.key;
if (key === " ") key = "Space";
else if (key.length === 1) key = key.toUpperCase();
else if (!/^[A-Za-z0-9]/.test(key)) return null; // Escape, Tab, etc. — not bindable
const key = codeToAcceleratorKey(e.code, e.key);
if (key == null) return null;
return [...mods, key].join("+");
}

/** Resolve the pressed key to Tauri accelerator syntax from `code` (the
* *physical* key) wherever possible, not `key` (the *composed* character).
*
* macOS recomposes many keys under Option/Alt into a different Unicode
* character than what's physically printed on the keycap — Option+Space's
* `key` is a non-breaking space (U+00A0), not `" "`; Option+letters compose
* accented characters ("Option+C" → "ç"). Since Alt is one of the four
* modifiers this exact capture UI expects users to hold, keying off `key`
* silently persisted a corrupted accelerator like `"Alt+\u00A0"` straight
* to `settings.json` — invisible in the UI (looked like a normal capture),
* but rejected outright by the OS accelerator parser at registration time
* ("Found empty token while parsing hotkey"), leaving the hotkey broken
* until the boot-time self-heal fell back to the default. `code` names the
* physical key regardless of what a modifier composes it into. */
function codeToAcceleratorKey(code: string, fallbackKey: string): string | null {
if (code === "Space") return "Space";
if (/^Key[A-Z]$/.test(code)) return code.slice(3);
if (/^Digit[0-9]$/.test(code)) return code.slice(5);
// Unrecognized physical key (arrows, Escape, function keys, punctuation,
// …) — `key` is stable for these regardless of modifiers, since Option
// only recomposes *printable* characters.
if (fallbackKey.length === 1) return fallbackKey.toUpperCase();
if (/^[A-Za-z0-9]/.test(fallbackKey)) return fallbackKey;
return null; // Tab, Escape's siblings that aren't bindable, etc.
}

export function GeneralPane({
settings,
onChange,
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "supersearch-app"
version = "0.1.16"
version = "0.1.17"
edition = "2021"
description = "SuperSearch — AI-Native Productivity Layer Desktop App"

Expand Down
2 changes: 1 addition & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
"productName": "SuperSearch",
"version": "0.1.16",
"version": "0.1.17",
"identifier": "com.supersearch.desktop",
"build": {
"frontendDist": "../react-command-palette/dist",
Expand Down
Loading