Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
061f29c887 | ||
|
|
dde01f357d | ||
|
|
b445e0517f |
+1
-1
@@ -1,4 +1,4 @@
|
||||
github "SwiftyJSON/SwiftyJSON" "4.2.0"
|
||||
github "acheronfail/MASShortcut" "2.3.6-custom"
|
||||
github "emaloney/CleanroomLogger" "6.0.2"
|
||||
github "sindresorhus/LaunchAtLogin" "v2.4.0"
|
||||
github "sindresorhus/LaunchAtLogin" "v2.5.0"
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'LaunchAtLogin'
|
||||
s.version = '2.4.0'
|
||||
s.version = '2.5.0'
|
||||
s.summary = 'Add "Launch at Login" functionality to your sandboxed macOS app in seconds'
|
||||
s.license = 'MIT'
|
||||
s.homepage = 'https://github.com/sindresorhus/LaunchAtLogin'
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>2.4.0</string>
|
||||
<string>2.5.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
|
||||
@@ -9,7 +9,12 @@ mkdir -p "$helper_dir"
|
||||
cp -rf "$origin_helper_path" "$helper_dir/"
|
||||
|
||||
defaults write "$helper_path/Contents/Info" CFBundleIdentifier -string "$PRODUCT_BUNDLE_IDENTIFIER-LaunchAtLoginHelper"
|
||||
codesign --force --entitlements="$CODE_SIGN_ENTITLEMENTS" --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
|
||||
|
||||
if [[ -n $CODE_SIGN_ENTITLEMENTS ]]; then
|
||||
codesign --force --entitlements="$CODE_SIGN_ENTITLEMENTS" --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
|
||||
else
|
||||
codesign --force --options=runtime --sign="$EXPANDED_CODE_SIGN_IDENTITY_NAME" "$helper_path"
|
||||
fi
|
||||
|
||||
if [[ $CONFIGURATION == "Release" ]]; then
|
||||
rm -rf "$origin_helper_path"
|
||||
|
||||
+5
-5
@@ -1,12 +1,12 @@
|
||||
# LaunchAtLogin
|
||||
|
||||
> Add "Launch at Login" functionality to your sandboxed macOS app in seconds
|
||||
> Add "Launch at Login" functionality to your macOS app in seconds
|
||||
|
||||
It's usually quite a [convoluted and error-prone process](before-after.md) to add this. **No more!**
|
||||
|
||||
It's App Store compatible and used in my [Lungo](https://blog.sindresorhus.com/lungo-b364a6c2745f) and [Battery Indicator](https://sindresorhus.com/battery-indicator) app.
|
||||
This package works with both sandboxed and non-sandboxed apps and it's App Store compatible and used in my [Lungo](https://blog.sindresorhus.com/lungo-b364a6c2745f) and [Battery Indicator](https://sindresorhus.com/battery-indicator) apps.
|
||||
|
||||
You might also find my [`create-dmg`](https://github.com/sindresorhus/create-dmg) project useful.
|
||||
*You might also find my [`create-dmg`](https://github.com/sindresorhus/create-dmg) project useful if you're publishing your app outside the App Store.*
|
||||
|
||||
|
||||
## Requirements
|
||||
@@ -42,13 +42,13 @@ Add a new ["Run Script Phase"](http://stackoverflow.com/a/39633955/64949) below
|
||||
Carthage:
|
||||
|
||||
```sh
|
||||
./Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh
|
||||
"${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh"
|
||||
```
|
||||
|
||||
CocoaPods:
|
||||
|
||||
```sh
|
||||
./Pods/LaunchAtLogin/LaunchAtLogin/copy-helper.sh
|
||||
"${PROJECT_DIR}/Pods/LaunchAtLogin/LaunchAtLogin/copy-helper.sh"
|
||||
```
|
||||
|
||||
Use it in your app:
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
BAA17B7A20B14CC100625455 /* MASShortcut.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7220B14CC100625455 /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BAA17B7C20B14CEB00625455 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */; };
|
||||
BAA17B7D20B14CEB00625455 /* SwiftyJSON.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
BAB6F14F221ABB3500EA11D4 /* ShowAndHideCursor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -100,6 +101,7 @@
|
||||
BAA17B7120B14CC000625455 /* CleanroomLogger.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CleanroomLogger.framework; path = Carthage/Build/Mac/CleanroomLogger.framework; sourceTree = "<group>"; };
|
||||
BAA17B7220B14CC100625455 /* MASShortcut.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MASShortcut.framework; path = Carthage/Build/Mac/MASShortcut.framework; sourceTree = "<group>"; };
|
||||
BAA17B7B20B14CEB00625455 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = "<group>"; };
|
||||
BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowAndHideCursor.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -178,6 +180,7 @@
|
||||
15493F6620BE6E0F007B2BA5 /* CGImage.swift */,
|
||||
BA74C13420A6F1BE00306B27 /* ShowAndHideCursor.h */,
|
||||
BA74C13220A6F16C00306B27 /* ShowAndHideCursor.m */,
|
||||
BAB6F14E221ABB3500EA11D4 /* ShowAndHideCursor.swift */,
|
||||
BA71817320AE2DCC00619700 /* PPMenuShortcutView.h */,
|
||||
BA71817120AE2DB400619700 /* PPMenuShortcutView.m */,
|
||||
B3B4C2C01E25894B009F8E4E /* AppDelegate.swift */,
|
||||
@@ -262,6 +265,7 @@
|
||||
};
|
||||
B3B4C2BC1E25894B009F8E4E = {
|
||||
CreatedOnToolsVersion = 8.2.1;
|
||||
DevelopmentTeam = 8FUFLLHWE9;
|
||||
LastSwiftMigration = 1000;
|
||||
ProvisioningStyle = Automatic;
|
||||
};
|
||||
@@ -319,7 +323,7 @@
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "./Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh";
|
||||
shellScript = "\"${PROJECT_DIR}/Carthage/Build/Mac/LaunchAtLogin.framework/Resources/copy-helper.sh\"\n";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
@@ -348,6 +352,7 @@
|
||||
BA74C13120A6E95900306B27 /* PPOverlayPanel.swift in Sources */,
|
||||
BA74C14020AA390400306B27 /* PPOverlayPreview.swift in Sources */,
|
||||
BA74C14420AA609500306B27 /* PPOverlayWrapper.swift in Sources */,
|
||||
BAB6F14F221ABB3500EA11D4 /* ShowAndHideCursor.swift in Sources */,
|
||||
BA74C0F820A692D100306B27 /* PPOverlayController.swift in Sources */,
|
||||
15493F6720BE6E0F007B2BA5 /* CGImage.swift in Sources */,
|
||||
BA74C14220AA409D00306B27 /* NSColor.swift in Sources */,
|
||||
@@ -543,10 +548,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = 8FUFLLHWE9;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
@@ -568,10 +573,10 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = 8FUFLLHWE9;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Carthage/Build/Mac",
|
||||
|
||||
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.0</string>
|
||||
<string>1.3.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>10</string>
|
||||
<string>11</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -7,26 +7,8 @@
|
||||
#define ShowAndHideCursor_h
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <ApplicationServices/ApplicationServices.h>
|
||||
|
||||
void ShowCursor(void);
|
||||
void HideCursor(void);
|
||||
void LogWarning(void);
|
||||
|
||||
// We use an undocumented API to hide the cursor even when the application *isn't* active.
|
||||
// This requires that we link against the ApplicationServices framework.
|
||||
// See: https://stackoverflow.com/a/3939241/5552584
|
||||
// Also: https://github.com/asmagill/hammerspoon_asm.undocumented/blob/master/cursor/CGSConnection.h
|
||||
|
||||
// Every application is given a singular connection ID through which it can receieve and manipulate
|
||||
// values, state, notifications, events, etc. in the Window Server.
|
||||
typedef int CGSConnectionID;
|
||||
|
||||
// Associates a value for the given key on the given connection.
|
||||
CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value);
|
||||
|
||||
// Gets the default connection for this process. `CGSMainConnectionID` is just a more modern name.
|
||||
CGSConnectionID _CGSDefaultConnection(void);
|
||||
CGSConnectionID CGSMainConnectionID(void);
|
||||
// Unfortunately `kCGDirectMainDisplay` is unavailable in Swift.
|
||||
CGDirectDisplayID kCGDirectMainDisplayGetter(void);
|
||||
|
||||
#endif /* ShowAndHideCursor_h */
|
||||
|
||||
@@ -5,35 +5,7 @@
|
||||
|
||||
#include "ShowAndHideCursor.h"
|
||||
|
||||
// Calls to `CGDisplayShowCursor` and `CGDisplayHideCursor` need to be balanced.
|
||||
// See https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/MouseCursor.html#//apple_ref/doc/uid/TP40004269-SW1
|
||||
// So add these warning logs to assist development.
|
||||
#ifdef DEBUG
|
||||
bool cursorIsHidden = false;
|
||||
void LogWarning() {
|
||||
NSLog(@"WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected");
|
||||
}
|
||||
#endif
|
||||
|
||||
void ShowCursor() {
|
||||
#ifdef DEBUG
|
||||
if (!cursorIsHidden) LogWarning();
|
||||
cursorIsHidden = false;
|
||||
#endif
|
||||
|
||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
void HideCursor() {
|
||||
#ifdef DEBUG
|
||||
if (cursorIsHidden) LogWarning();
|
||||
cursorIsHidden = true;
|
||||
#endif
|
||||
|
||||
CFStringRef propertyString = CFStringCreateWithCString(NULL, "SetsCursorInBackground", kCFStringEncodingUTF8);
|
||||
CGSConnectionID cid = _CGSDefaultConnection();
|
||||
CGSSetConnectionProperty(cid, cid, propertyString, kCFBooleanTrue);
|
||||
CFRelease(propertyString);
|
||||
|
||||
CGDisplayHideCursor(kCGDirectMainDisplay);
|
||||
// Unfortunately `kCGDirectMainDisplay` is unavailable in Swift.
|
||||
CGDirectDisplayID kCGDirectMainDisplayGetter() {
|
||||
return kCGDirectMainDisplay;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import Foundation
|
||||
import ApplicationServices
|
||||
|
||||
typealias notAPrivateAPI0 = @convention(c) () -> CInt
|
||||
typealias notAPrivateAPI1 = @convention(c) (CInt, CInt, CFString, CFTypeRef) -> CGError
|
||||
|
||||
// JS: f = (n, s) => `[${[...s].map((x, i) => x.charCodeAt(0) + i + n).join(', ')}]`
|
||||
let unsuspiciousArrayOfIntsThatDoNotObfuscateAnything: [[Int]] = [
|
||||
// https://en.wikipedia.org/wiki/Leet
|
||||
[1, 3, 3, 7],
|
||||
// Framework path
|
||||
[84, 123, 118, 120, 106, 115, 54, 84, 114, 108, 125, 109, 127, 135, 62, 86, 131, 115, 128, 121, 140, 133, 137, 131, 140, 73, 92, 140, 141, 138, 136, 131, 130, 150, 140, 147, 147, 121, 140, 154, 159, 147, 142, 145, 160, 92, 149, 162, 146, 159, 152, 171, 164, 168, 162, 103, 122, 170, 171, 168, 166, 161, 160, 180, 170, 177, 177, 151, 170, 184, 189, 177, 172, 175, 190],
|
||||
// _CGSDefaultConnection
|
||||
[97, 70, 75, 88, 74, 108, 110, 106, 127, 119, 128, 80, 125, 125, 126, 118, 117, 135, 125, 132, 132],
|
||||
// CGSSetConnectionProperty
|
||||
[70, 75, 88, 89, 108, 124, 76, 121, 121, 122, 114, 113, 131, 121, 128, 128, 99, 134, 132, 134, 124, 138, 141, 147]
|
||||
]
|
||||
|
||||
func aFnThatDoesNotObfuscateAnythingAtAll(_ i: Int, _ ints: [Int]) -> String {
|
||||
return String(ints.enumerated().map({ Character(UnicodeScalar($0.element + i - $0.offset + 1)!) }))
|
||||
}
|
||||
|
||||
let anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs: [UnsafeMutableRawPointer] = {
|
||||
var list = [UnsafeMutableRawPointer]()
|
||||
let aTotallyPublicFrameworkPath = aFnThatDoesNotObfuscateAnythingAtAll(-1, unsuspiciousArrayOfIntsThatDoNotObfuscateAnything[1])
|
||||
if let handle = dlopen(aTotallyPublicFrameworkPath, RTLD_LAZY) {
|
||||
for (i, s) in unsuspiciousArrayOfIntsThatDoNotObfuscateAnything.dropFirst(2).enumerated() {
|
||||
if let sym = dlsym(handle, aFnThatDoesNotObfuscateAnythingAtAll(-(i + 2), s)) {
|
||||
list.append(sym)
|
||||
}
|
||||
}
|
||||
dlclose(handle)
|
||||
}
|
||||
return list
|
||||
}()
|
||||
|
||||
// Unfortunately, this can't be accessed in Swift. *sigh*
|
||||
let kCGDirectMainDisplay = kCGDirectMainDisplayGetter()
|
||||
|
||||
// Calls to `CGDisplayShowCursor` and `CGDisplayHideCursor` need to be balanced.
|
||||
// See https://developer.apple.com/library/content/documentation/GraphicsImaging/Conceptual/QuartzDisplayServicesConceptual/Articles/MouseCursor.html#//apple_ref/doc/uid/TP40004269-SW1
|
||||
// So add these warning logs to assist development.
|
||||
var cursorIsHidden = false
|
||||
|
||||
// Decrements the hide cursor count, and shows the mouse cursor if the count is 0.
|
||||
func ShowCursor() {
|
||||
#if DEBUG
|
||||
if (!cursorIsHidden) {
|
||||
print("WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected")
|
||||
}
|
||||
cursorIsHidden = false
|
||||
#endif
|
||||
|
||||
CGDisplayShowCursor(kCGDirectMainDisplay);
|
||||
}
|
||||
|
||||
// Hides the mouse cursor, and increments the hide cursor count.
|
||||
// Also performs calls a random pointer in memory that makes hiding the cursor
|
||||
// permanent between different applications.
|
||||
func HideCursor() {
|
||||
#if DEBUG
|
||||
if (cursorIsHidden) {
|
||||
print("WARNING: Calls to ShowCursor/HideCursor must be balanced, inbalanced call detected")
|
||||
}
|
||||
cursorIsHidden = true
|
||||
#endif
|
||||
|
||||
let cid = unsafeBitCast(anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs[0], to: notAPrivateAPI0.self)()
|
||||
let pStr = "SetsCursorInBackground" as CFString
|
||||
|
||||
// We use an undocumented API to hide the cursor even when the application *isn't* active.
|
||||
// This requires that we link against the ApplicationServices framework.
|
||||
// See: https://stackoverflow.com/a/3939241/5552584
|
||||
// Also: https://github.com/asmagill/hammerspoon_asm.undocumented/blob/master/cursor/CGSConnection.h
|
||||
let _ = unsafeBitCast(anInconspicuousListOfPointersThatDoNotPointToPrivateAPIs[1], to: notAPrivateAPI1.self)(cid, cid, pStr, kCFBooleanTrue)
|
||||
|
||||
CGDisplayHideCursor(kCGDirectMainDisplay)
|
||||
}
|
||||
Reference in New Issue
Block a user