Add URL scheme support for external trigger integration
Register snippingtool:// URL scheme so external tools (Logitech Options, Shortcuts, Stream Deck) can trigger specific capture modes directly. Adds AppDelegate for reliable URL handling in MenuBarExtra-only apps. Supported URLs: snippingtool://fullscreen snippingtool://window snippingtool://region Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,35 @@ final class AppCoordinator: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - External triggers (URL scheme)
|
||||||
|
|
||||||
|
/// Handles `snippingtool://<mode>` URLs so external tools (Logitech
|
||||||
|
/// Options, Shortcuts, Stream Deck, `open` from the command line, …)
|
||||||
|
/// can trigger a specific capture mode instead of just launching the app.
|
||||||
|
/// Accepts the mode either as the host (`snippingtool://region`) or as
|
||||||
|
/// a query item (`snippingtool://capture?mode=region`).
|
||||||
|
func handle(url: URL) {
|
||||||
|
guard url.scheme?.caseInsensitiveCompare("snippingtool") == .orderedSame else { return }
|
||||||
|
|
||||||
|
let modeString = url.host?.lowercased()
|
||||||
|
?? URLComponents(url: url, resolvingAgainstBaseURL: false)?
|
||||||
|
.queryItems?
|
||||||
|
.first(where: { $0.name.caseInsensitiveCompare("mode") == .orderedSame })?
|
||||||
|
.value?
|
||||||
|
.lowercased()
|
||||||
|
|
||||||
|
switch modeString {
|
||||||
|
case "fullscreen", "full", "full-screen", "screen":
|
||||||
|
capture(mode: .fullScreen)
|
||||||
|
case "window":
|
||||||
|
capture(mode: .window)
|
||||||
|
case "region", "area", "selection":
|
||||||
|
capture(mode: .region)
|
||||||
|
default:
|
||||||
|
NSLog("SnippingTool: unrecognized URL trigger \(url.absoluteString)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - Capture
|
// MARK: - Capture
|
||||||
|
|
||||||
func capture(mode: CaptureMode) {
|
func capture(mode: CaptureMode) {
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import AppKit
|
||||||
|
|
||||||
|
/// MenuBarExtra-only apps (no WindowGroup) don't reliably receive SwiftUI's
|
||||||
|
/// `.onOpenURL` scene events — SwiftUI logs "Cannot use Scene methods for
|
||||||
|
/// URL... without using SwiftUI Lifecycle" and the handler never fires.
|
||||||
|
/// The classic AppKit delegate callback works regardless, so URL scheme
|
||||||
|
/// triggers (from Logitech Options, Shortcuts, Stream Deck, `open`, …) are
|
||||||
|
/// routed through here instead.
|
||||||
|
final class AppDelegate: NSObject, NSApplicationDelegate {
|
||||||
|
let coordinator = AppCoordinator()
|
||||||
|
|
||||||
|
func application(_ application: NSApplication, open urls: [URL]) {
|
||||||
|
urls.forEach { coordinator.handle(url: $0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,12 +2,12 @@ import SwiftUI
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
struct SnippingToolApp: App {
|
struct SnippingToolApp: App {
|
||||||
@StateObject private var coordinator = AppCoordinator()
|
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
MenuBarExtra("Snipping Tool", systemImage: "camera.viewfinder") {
|
MenuBarExtra("Snipping Tool", systemImage: "camera.viewfinder") {
|
||||||
MenuBarContentView()
|
MenuBarContentView()
|
||||||
.environmentObject(coordinator)
|
.environmentObject(appDelegate.coordinator)
|
||||||
}
|
}
|
||||||
.menuBarExtraStyle(.menu)
|
.menuBarExtraStyle(.menu)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ targets:
|
|||||||
CFBundleName: Snipping Tool
|
CFBundleName: Snipping Tool
|
||||||
LSUIElement: true
|
LSUIElement: true
|
||||||
NSHumanReadableCopyright: "Copyright © 2026"
|
NSHumanReadableCopyright: "Copyright © 2026"
|
||||||
|
CFBundleURLTypes:
|
||||||
|
- CFBundleURLName: it.wende.snippingtool
|
||||||
|
CFBundleURLSchemes:
|
||||||
|
- snippingtool
|
||||||
settings:
|
settings:
|
||||||
base:
|
base:
|
||||||
PRODUCT_BUNDLE_IDENTIFIER: it.wende.snippingtool
|
PRODUCT_BUNDLE_IDENTIFIER: it.wende.snippingtool
|
||||||
|
|||||||
Reference in New Issue
Block a user