From f6dfad00ae5633d47ab66bb81b227b8426127317 Mon Sep 17 00:00:00 2001 From: Beingpax Date: Thu, 20 Mar 2025 17:13:00 +0545 Subject: [PATCH] Update Xcode project build settings --- VoiceInk.xcodeproj/project.pbxproj | 51 ++++---------------- VoiceInk/CursorPaster.swift | 55 +++++++++++++++++----- VoiceInk/Views/Settings/SettingsView.swift | 18 +++++++ 3 files changed, 70 insertions(+), 54 deletions(-) diff --git a/VoiceInk.xcodeproj/project.pbxproj b/VoiceInk.xcodeproj/project.pbxproj index d8b94a3..1c4f2d4 100644 --- a/VoiceInk.xcodeproj/project.pbxproj +++ b/VoiceInk.xcodeproj/project.pbxproj @@ -7,16 +7,11 @@ objects = { /* Begin PBXBuildFile section */ - E19E53B02D36D8120067F3D4 /* libggml.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53A72D36D7EF0067F3D4 /* libggml.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E19E53B12D36D8200067F3D4 /* libggml-base.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53A82D36D7EF0067F3D4 /* libggml-base.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E19E53B22D36D82F0067F3D4 /* libwhisper.1.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53AD2D36D7EF0067F3D4 /* libwhisper.1.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E19E53B32D36D84A0067F3D4 /* libggml-cpu.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53AA2D36D7EF0067F3D4 /* libggml-cpu.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E19E53B42D36D85B0067F3D4 /* libggml-blas.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53A92D36D7EF0067F3D4 /* libggml-blas.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - E19E53B52D36D8660067F3D4 /* libggml-metal.dylib in CopyFiles */ = {isa = PBXBuildFile; fileRef = E19E53AB2D36D7EF0067F3D4 /* libggml-metal.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; E1A261122CC143AC00B233D1 /* KeyboardShortcuts in Frameworks */ = {isa = PBXBuildFile; productRef = E1A261112CC143AC00B233D1 /* KeyboardShortcuts */; }; + E1A4486E2D8C03A2004526F9 /* whisper.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = E1A4486D2D8C03A1004526F9 /* whisper.xcframework */; }; + E1A4486F2D8C03A2004526F9 /* whisper.xcframework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E1A4486D2D8C03A1004526F9 /* whisper.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E1ADD45A2CC5352A00303ECB /* LaunchAtLogin in Frameworks */ = {isa = PBXBuildFile; productRef = E1ADD4592CC5352A00303ECB /* LaunchAtLogin */; }; E1ADD45F2CC544F100303ECB /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = E1ADD45E2CC544F100303ECB /* Sparkle */; }; - E1E0F4262CC7FF300005EE87 /* whisper in Frameworks */ = {isa = PBXBuildFile; productRef = E1E0F4252CC7FF300005EE87 /* whisper */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -43,12 +38,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - E19E53B52D36D8660067F3D4 /* libggml-metal.dylib in CopyFiles */, - E19E53B42D36D85B0067F3D4 /* libggml-blas.dylib in CopyFiles */, - E19E53B32D36D84A0067F3D4 /* libggml-cpu.dylib in CopyFiles */, - E19E53B22D36D82F0067F3D4 /* libwhisper.1.dylib in CopyFiles */, - E19E53B12D36D8200067F3D4 /* libggml-base.dylib in CopyFiles */, - E19E53B02D36D8120067F3D4 /* libggml.dylib in CopyFiles */, + E1A4486F2D8C03A2004526F9 /* whisper.xcframework in CopyFiles */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -58,15 +48,7 @@ E11473B02CBE0F0A00318EE4 /* VoiceInk.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VoiceInk.app; sourceTree = BUILT_PRODUCTS_DIR; }; E11473C32CBE0F0B00318EE4 /* VoiceInkTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoiceInkTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; E11473CD2CBE0F0B00318EE4 /* VoiceInkUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VoiceInkUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - E19E53A72D36D7EF0067F3D4 /* libggml.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libggml.dylib; path = /usr/local/lib/libggml.dylib; sourceTree = ""; }; - E19E53A82D36D7EF0067F3D4 /* libggml-base.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libggml-base.dylib"; path = "/usr/local/lib/libggml-base.dylib"; sourceTree = ""; }; - E19E53A92D36D7EF0067F3D4 /* libggml-blas.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libggml-blas.dylib"; path = "/usr/local/lib/libggml-blas.dylib"; sourceTree = ""; }; - E19E53AA2D36D7EF0067F3D4 /* libggml-cpu.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libggml-cpu.dylib"; path = "/usr/local/lib/libggml-cpu.dylib"; sourceTree = ""; }; - E19E53AB2D36D7EF0067F3D4 /* libggml-metal.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libggml-metal.dylib"; path = "/usr/local/lib/libggml-metal.dylib"; sourceTree = ""; }; - E19E53AC2D36D7EF0067F3D4 /* libwhisper.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libwhisper.dylib; path = /usr/local/lib/libwhisper.dylib; sourceTree = ""; }; - E19E53AD2D36D7EF0067F3D4 /* libwhisper.1.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libwhisper.1.dylib; path = /usr/local/lib/libwhisper.1.dylib; sourceTree = ""; }; - E19E53AE2D36D7EF0067F3D4 /* libwhisper.1.7.4.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libwhisper.1.7.4.dylib; path = /usr/local/lib/libwhisper.1.7.4.dylib; sourceTree = ""; }; - E1E0F4242CC7FF2A0005EE87 /* whisper.cpp */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = whisper.cpp; path = /Users/beingpax/whisper.cpp; sourceTree = ""; }; + E1A4486D2D8C03A1004526F9 /* whisper.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = whisper.xcframework; path = "../whisper.cpp/build-apple/whisper.xcframework"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ @@ -92,8 +74,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + E1A4486E2D8C03A2004526F9 /* whisper.xcframework in Frameworks */, E1ADD45A2CC5352A00303ECB /* LaunchAtLogin in Frameworks */, - E1E0F4262CC7FF300005EE87 /* whisper in Frameworks */, E1ADD45F2CC544F100303ECB /* Sparkle in Frameworks */, E1A261122CC143AC00B233D1 /* KeyboardShortcuts in Frameworks */, ); @@ -124,7 +106,6 @@ E11473D02CBE0F0B00318EE4 /* VoiceInkUITests */, E114741C2CBE1DE200318EE4 /* Frameworks */, E11473B12CBE0F0A00318EE4 /* Products */, - E1E0F4242CC7FF2A0005EE87 /* whisper.cpp */, ); sourceTree = ""; }; @@ -141,14 +122,7 @@ E114741C2CBE1DE200318EE4 /* Frameworks */ = { isa = PBXGroup; children = ( - E19E53A72D36D7EF0067F3D4 /* libggml.dylib */, - E19E53A82D36D7EF0067F3D4 /* libggml-base.dylib */, - E19E53A92D36D7EF0067F3D4 /* libggml-blas.dylib */, - E19E53AA2D36D7EF0067F3D4 /* libggml-cpu.dylib */, - E19E53AB2D36D7EF0067F3D4 /* libggml-metal.dylib */, - E19E53AC2D36D7EF0067F3D4 /* libwhisper.dylib */, - E19E53AD2D36D7EF0067F3D4 /* libwhisper.1.dylib */, - E19E53AE2D36D7EF0067F3D4 /* libwhisper.1.7.4.dylib */, + E1A4486D2D8C03A1004526F9 /* whisper.xcframework */, ); name = Frameworks; sourceTree = ""; @@ -177,7 +151,6 @@ E1A261112CC143AC00B233D1 /* KeyboardShortcuts */, E1ADD4592CC5352A00303ECB /* LaunchAtLogin */, E1ADD45E2CC544F100303ECB /* Sparkle */, - E1E0F4252CC7FF300005EE87 /* whisper */, ); productName = VoiceInk; productReference = E11473B02CBE0F0A00318EE4 /* VoiceInk.app */; @@ -468,7 +441,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_TEAM = V6J6A3VWY2; ENABLE_HARDENED_RUNTIME = YES; @@ -483,7 +456,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.12; + MARKETING_VERSION = 1.14; PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -501,7 +474,7 @@ "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - CURRENT_PROJECT_VERSION = 112; + CURRENT_PROJECT_VERSION = 114; DEVELOPMENT_ASSET_PATHS = "\"VoiceInk/Preview Content\""; DEVELOPMENT_TEAM = V6J6A3VWY2; ENABLE_HARDENED_RUNTIME = YES; @@ -516,7 +489,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.12; + MARKETING_VERSION = 1.14; PRODUCT_BUNDLE_IDENTIFIER = com.prakashjoshipax.VoiceInk; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; @@ -676,10 +649,6 @@ package = E1ADD45D2CC544F100303ECB /* XCRemoteSwiftPackageReference "Sparkle" */; productName = Sparkle; }; - E1E0F4252CC7FF300005EE87 /* whisper */ = { - isa = XCSwiftPackageProductDependency; - productName = whisper; - }; /* End XCSwiftPackageProductDependency section */ }; rootObject = E11473A82CBE0F0A00318EE4 /* Project object */; diff --git a/VoiceInk/CursorPaster.swift b/VoiceInk/CursorPaster.swift index bfa8284..3c70f2d 100644 --- a/VoiceInk/CursorPaster.swift +++ b/VoiceInk/CursorPaster.swift @@ -1,8 +1,10 @@ import Foundation import AppKit +import OSLog class CursorPaster { private static let pasteCompletionDelay: TimeInterval = 0.3 + private static let logger = Logger(subsystem: "com.voiceink", category: "CursorPaster") static func pasteAtCursor(_ text: String) { guard AXIsProcessTrusted() else { @@ -18,7 +20,44 @@ class CursorPaster { pasteboard.clearContents() pasteboard.setString(text, forType: .string) - // Simulate cmd+v key press to paste + // Use the preferred paste method based on user settings + if UserDefaults.standard.bool(forKey: "UseAppleScriptPaste") { + pasteUsingAppleScript() + } else { + pasteUsingCommandV() + } + + // Restore the original pasteboard content + DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + pasteCompletionDelay) { + pasteboard.clearContents() + if let oldContents = oldContents { + pasteboard.setString(oldContents, forType: .string) + } + } + } + + private static func pasteUsingAppleScript() -> Bool { + let script = """ + tell application "System Events" + keystroke "v" using command down + end tell + """ + + var error: NSDictionary? + if let scriptObject = NSAppleScript(source: script) { + let output = scriptObject.executeAndReturnError(&error) + if error != nil { + print("AppleScript paste failed: \(error?.description ?? "Unknown error")") + logger.notice("AppleScript paste failed with error: \(error?.description ?? "Unknown error")") + return false + } + logger.notice("AppleScript paste completed successfully") + return true + } + return false + } + + private static func pasteUsingCommandV() { let source = CGEventSource(stateID: .hidSystemState) let cmdDown = CGEvent(keyboardEventSource: source, virtualKey: 0x37, keyDown: true) @@ -35,17 +74,7 @@ class CursorPaster { vUp?.post(tap: .cghidEventTap) cmdUp?.post(tap: .cghidEventTap) - // First clear the clipboard of our pasted content - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.1) { - pasteboard.clearContents() - - // Then restore the original content after a short delay - DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: .now() + 0.2) { - if let oldContents = oldContents { - pasteboard.clearContents() - pasteboard.setString(oldContents, forType: .string) - } - } - } + logger.notice("Command+V paste completed") } } + diff --git a/VoiceInk/Views/Settings/SettingsView.swift b/VoiceInk/Views/Settings/SettingsView.swift index 6a39416..6dd2eaa 100644 --- a/VoiceInk/Views/Settings/SettingsView.swift +++ b/VoiceInk/Views/Settings/SettingsView.swift @@ -147,6 +147,24 @@ struct SettingsView: View { } } + // Paste Method Section + SettingsSection( + icon: "doc.on.clipboard", + title: "Paste Method", + subtitle: "Choose how text is pasted" + ) { + VStack(alignment: .leading, spacing: 8) { + Text("Select the method used to paste text. Use AppleScript if you have a non-standard keyboard layout.") + .settingsDescription() + + Toggle("Use AppleScript Paste Method", isOn: Binding( + get: { UserDefaults.standard.bool(forKey: "UseAppleScriptPaste") }, + set: { UserDefaults.standard.set($0, forKey: "UseAppleScriptPaste") } + )) + .toggleStyle(.switch) + } + } + // Recorder Preference Section SettingsSection( icon: "rectangle.on.rectangle",