StrokeMouse

StrokeMouse

中文 · English

License: AGPL-3.0

Custom mouse gestures for macOS. Hold a **per-gesture trigger** (right button by default; middle or side buttons also work), draw a stroke, and run shortcuts, open apps, window commands, media keys, Shell / AppleScript, and more. Gestures can be **global or app-scoped**, configs are **importable/exportable**, and everything runs locally from the menu bar. ## Screenshots | Gesture list | Gesture test | |:---:|:---:| | Gesture list | Gesture test | | General settings | Permissions | |:---:|:---:| | General settings | Permissions | | Record stroke | App scope | |:---:|:---:| | Record stroke | App scope | ## Features - **Menu bar app**: enable/disable gestures, open settings, quit; icon tints by status (normal / paused / needs permission); optional **hide menu bar icon** (confirm if Dock is also hidden; reopen via Dock or relaunch to open settings) - **Gesture library**: sidebar by **Global / per-app** (new gestures inherit the selected scope); search / filter / sort; multi-select batch enable, disable, delete; **JSON import/export** (skip or force-import duplicates) - **Per-gesture triggers**: right button by default; middle / side buttons optional; only enabled triggers are monitored - **Per-gesture target**: choose the frontmost app or the app under the pointer at trigger-down; when a regular window exists, its exact window is frozen too, and app-scope checks and target-aware actions always reuse that target - **Free-path recognition**: arc-length resampling + 1D/2D normalization + limited rotation; significant-turn structure gates; live stroke HUD while holding the trigger - **App scope**: global, or pick apps by icon from installed applications (search / browse `.app`) - **Actions**: shortcuts, open app (icon picker), URL, media keys, window actions, Shell / AppleScript (syntax-highlighted editor; AppleScript presets such as sleep, lock screen, empty trash, plus custom) - **Polish**: EN / 中文 UI, light/dark appearance (system or forced), launch at login, hide Dock / menu bar icon, Sparkle in-app updates (falls back to GitHub Releases on failure) ## Requirements - macOS 14 Sonoma or later - Xcode 16+ (for development builds) - Any mouse works (default gestures use the right button; change per gesture in the editor) ## Permissions | Permission | Purpose | |------------|---------| | **Accessibility** | Global mouse listening (`CGEventTap`), shortcut injection, window AX actions | | **Automation** | Optional; required when AppleScript controls other apps | On first launch or **Settings → Permissions**, use in-app **Guide Me**: open System Settings and drag StrokeMouse into the list. Without trust the engine will not pretend to listen. ## Build & run ### Dependencies ```bash brew install xcodegen ``` ### Generate the project and open ```bash ./scripts/generate_project.sh open StrokeMouse.xcodeproj ``` Or **Run** directly in Xcode (Scheme: `StrokeMouse`). ### CLI build (recommended) Produces a stable path at `output/StrokeMouse.app`, which reduces repeated Accessibility prompts. Debug shows as **StrokeMouse Dev** (Bundle ID `com.strokemouse.app.dev`) so it can be authorized separately from the release **StrokeMouse** app: ```bash ./scripts/build.sh # Debug → output/StrokeMouse.app (Accessibility: StrokeMouse Dev) ./scripts/build.sh --open # open after build ./scripts/build.sh --release # Release (same display name / Bundle ID as shipping builds) ``` ### Release packaging Build ZIP, TAR.GZ, and DMG per architecture, and verify signature, entitlements, and artifact integrity: ```bash # First time locally: ./scripts/generate-codesign-cert.sh --import SPARKLE_PUBLIC_KEY="..." ARCH=arm64 ./scripts/package-app.sh SPARKLE_PUBLIC_KEY="..." ARCH=x86_64 ./scripts/package-app.sh ``` Release packaging uses the stable self-signed identity **`StrokeMouse Release`** so Accessibility grants survive Sparkle updates. See `RELEASING.md` / `certs/README.md`. Bump versions with `./bump.sh -v x.y.z [-p]`. Re-tag the same version and push with `./bump.sh -v x.y.z --force`. ### Tests ```bash xcodebuild -scheme StrokeMouse -configuration Debug test ``` ## Usage 1. Launch the app; a mouse icon appears in the menu bar 2. Grant **Accessibility**, then enable gestures from the menu bar 3. Open **Settings → Gestures** to review defaults or create new ones 4. Hold the gesture’s **trigger** (right button by default; change in the editor), draw a path, release 5. On a successful match, the bound action runs > **Short click vs gesture**: trigger down/up is temporarily captured by the engine. If you release before the minimum stroke distance, a normal click is replayed so the context menu still works. Once drawing starts, drag still moves the system cursor and stroke HUD, but the frontmost app does not receive a paired down/up—so no context menu appears or is selected. Left click and buttons not configured as triggers are always passed through. > Shortcuts activate the frozen app first and also bring its exact window forward when one was captured, which may switch focus or Spaces. Locations without a regular window, such as the Finder desktop, can still run shortcuts and **Hide App**; Close, Minimize, Zoom, Full Screen, and Center still require an exact window. A short click never activates the target. Default gesture examples (right button by default; each gesture can use a different button): | Gesture | Action | |---------|--------| | ↑ | Mission Control (⌃↑) | | ↓ | Application windows (⌃↓) | | ↓← | Minimize window | | ↓→ | Close window | | ↑→ | Open Safari | | →← | Play / pause | | ↑← | Open GitHub | ## Config file Path: ```text ~/Library/Application Support/StrokeMouse/gestures.json ``` Day to day, multi-select under **Settings → Gestures** to export / import JSON packages. For a full-library backup, copy the file above or edit by hand (keep the structure valid). Settings can **Reveal in Finder**. ## Tech stack - Swift / SwiftUI (macOS 14+) - Lightweight MVVM + Service - `CGEventTap` for global mouse events - JSON config persistence - [LaunchAtLogin-Modern](https://github.com/sindresorhus/LaunchAtLogin-Modern) for login launch - [Sparkle](https://github.com/sparkle-project/Sparkle) for signed in-app updates - XcodeGen for the Xcode project ## License & disclaimer This project is licensed under the [GNU Affero General Public License v3.0 (AGPL-3.0)](./LICENSE). This is a local utility. Global event monitoring and script actions are powerful. Only add Shell / AppleScript you trust. The author is not responsible for misuse or accidental damage.