mirror of
https://github.com/shadowsocks/ShadowsocksX-NG.git
synced 2026-11-03 01:23:43 +00:00
Merge pull request #1501 from hiddenSharp429/develop
Feat(QRCode): Enhance 'Scan QR Code From Screen' notifications # #1250
This commit is contained in:
@@ -24,6 +24,8 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
brew install automake
|
||||
brew install autoconf
|
||||
brew install libtool
|
||||
make VERSION="${GITHUB_SHA::7}" debug
|
||||
make debug-dmg
|
||||
shasum -a 256 build/Debug/ShadowsocksX-NG.dmg > build/Debug/ShadowsocksX-NG.dmg.checksum
|
||||
|
||||
@@ -21,6 +21,8 @@ jobs:
|
||||
- name: Build
|
||||
run: |
|
||||
brew install automake
|
||||
brew install autoconf
|
||||
brew install libtool
|
||||
make VERSION="${GITHUB_REF_NAME}" release
|
||||
make release-dmg
|
||||
shasum -a 256 build/Release/ShadowsocksX-NG.dmg > build/Release/ShadowsocksX-NG.dmg.checksum
|
||||
|
||||
@@ -627,42 +627,43 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDele
|
||||
}
|
||||
|
||||
func handleFoundSSURL(_ note: Notification) {
|
||||
let sendNotify = {
|
||||
(title: String, subtitle: String, infoText: String) in
|
||||
|
||||
let sendNotify = { (title: String, subtitle: String, infoText: String) in
|
||||
let userNote = NSUserNotification()
|
||||
userNote.title = title
|
||||
userNote.subtitle = subtitle
|
||||
userNote.informativeText = infoText
|
||||
userNote.soundName = NSUserNotificationDefaultSoundName
|
||||
|
||||
NSUserNotificationCenter.default
|
||||
.deliver(userNote);
|
||||
NSUserNotificationCenter.default.deliver(userNote)
|
||||
}
|
||||
|
||||
if let userInfo = (note as NSNotification).userInfo {
|
||||
let urls: [URL] = userInfo["urls"] as! [URL]
|
||||
// 检查错误
|
||||
if let error = userInfo["error"] as? String {
|
||||
sendNotify("Scan Failed", "", error.localized)
|
||||
return
|
||||
}
|
||||
|
||||
let mgr = ServerProfileManager.instance
|
||||
let addCount = mgr.addServerProfileByURL(urls: urls)
|
||||
// 使用新的通知信息
|
||||
let title = (userInfo["title"] as? String) ?? ""
|
||||
let subtitle = (userInfo["subtitle"] as? String) ?? ""
|
||||
let body = (userInfo["body"] as? String) ?? ""
|
||||
|
||||
let urls: [URL] = userInfo["urls"] as! [URL]
|
||||
let addCount = ServerProfileManager.instance.addServerProfileByURL(urls: urls)
|
||||
|
||||
if addCount > 0 {
|
||||
var subtitle: String = ""
|
||||
if userInfo["source"] as! String == "qrcode" {
|
||||
subtitle = "By scan QR Code".localized
|
||||
} else if userInfo["source"] as! String == "url" {
|
||||
subtitle = "By handle SS URL".localized
|
||||
} else if userInfo["source"] as! String == "pasteboard" {
|
||||
subtitle = "By import from pasteboard".localized
|
||||
}
|
||||
|
||||
sendNotify("Add \(addCount) Shadowsocks Server Profile".localized, subtitle, "")
|
||||
sendNotify(
|
||||
title.localized,
|
||||
subtitle.localized,
|
||||
"Successfully added \(addCount) server configuration(s)".localized
|
||||
)
|
||||
} else {
|
||||
if userInfo["source"] as! String == "qrcode" {
|
||||
sendNotify("", "", "Not found valid QRCode of shadowsocks profile".localized)
|
||||
} else if userInfo["source"] as! String == "url" {
|
||||
sendNotify("", "", "Not found valid URL of shadowsocks profile".localized)
|
||||
}
|
||||
sendNotify(
|
||||
title.localized,
|
||||
subtitle.localized,
|
||||
body.localized
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,5 +49,7 @@
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>SWBApplication</string>
|
||||
<key>NSScreenCaptureUsageDescription</key>
|
||||
<string>ShadowsocksX-NG needs Screen Recording permission to scan QR codes on your screen</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
+113
-31
@@ -10,71 +10,153 @@
|
||||
#import <CoreImage/CoreImage.h>
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
void ScanQRCodeOnScreen(void) {
|
||||
void ScanQRCodeOnScreen(void) {
|
||||
/* check system version and permission status */
|
||||
if (@available(macOS 10.12, *)) {
|
||||
BOOL hasPermission = CGPreflightScreenCaptureAccess();
|
||||
NSLog(@"Screen Recording Permission Status: %@", hasPermission ? @"Granted" : @"Not Granted");
|
||||
|
||||
if (!hasPermission) {
|
||||
NSLog(@"Requesting Screen Recording Permission...");
|
||||
CGRequestScreenCaptureAccess();
|
||||
|
||||
/* check permission status after request */
|
||||
hasPermission = CGPreflightScreenCaptureAccess();
|
||||
NSLog(@"Screen Recording Permission Status After Request: %@", hasPermission ? @"Granted" : @"Not Granted");
|
||||
|
||||
if (!hasPermission) {
|
||||
NSLog(@"Screen Recording Permission Denied");
|
||||
|
||||
/* send notification about permission missing */
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"NOTIFY_FOUND_SS_URL"
|
||||
object:nil
|
||||
userInfo:@{
|
||||
@"urls": @[],
|
||||
@"source": @"qrcode",
|
||||
@"error": @"Screen Recording permission required. Please grant permission in System Preferences and restart ShadowsocksX-NG"
|
||||
}];
|
||||
|
||||
/* open system privacy settings */
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"x-apple.systempreferences:com.apple.preference.security?Privacy_ScreenCapture"]];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSLog(@"Proceeding with screen capture...");
|
||||
}
|
||||
|
||||
/* displays[] Quartz display ID's */
|
||||
CGDirectDisplayID *displays = nil;
|
||||
|
||||
CGError err = CGDisplayNoErr;
|
||||
CGDisplayCount dspCount = 0;
|
||||
|
||||
/* How many active displays do we have? */
|
||||
err = CGGetActiveDisplayList(0, NULL, &dspCount);
|
||||
/* variables for collecting scan information */
|
||||
NSMutableDictionary *scanInfo = [NSMutableDictionary dictionary];
|
||||
NSMutableArray *foundSSUrls = [NSMutableArray array];
|
||||
NSMutableArray *foundQRCodes = [NSMutableArray array];
|
||||
|
||||
/* If we are getting an error here then their won't be much to display. */
|
||||
if(err != CGDisplayNoErr)
|
||||
{
|
||||
NSLog(@"Could not get active display count (%d)\n", err);
|
||||
/* How many active displays do we have? */
|
||||
CGError err = CGGetActiveDisplayList(0, NULL, &dspCount);
|
||||
|
||||
if(err != CGDisplayNoErr) {
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"NOTIFY_FOUND_SS_URL"
|
||||
object:nil
|
||||
userInfo:@{
|
||||
@"urls": @[],
|
||||
@"source": @"qrcode",
|
||||
@"error": @"Failed to get display list"
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
scanInfo[@"displayCount"] = @(dspCount);
|
||||
NSLog(@"Found %d displays", dspCount);
|
||||
|
||||
/* Allocate enough memory to hold all the display IDs we have. */
|
||||
displays = calloc((size_t)dspCount, sizeof(CGDirectDisplayID));
|
||||
|
||||
// Get the list of active displays
|
||||
err = CGGetActiveDisplayList(dspCount,
|
||||
displays,
|
||||
&dspCount);
|
||||
err = CGGetActiveDisplayList(dspCount, displays, &dspCount);
|
||||
|
||||
/* More error-checking here. */
|
||||
if(err != CGDisplayNoErr)
|
||||
{
|
||||
NSLog(@"Could not get active display list (%d)\n", err);
|
||||
if(err != CGDisplayNoErr) {
|
||||
free(displays);
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"NOTIFY_FOUND_SS_URL"
|
||||
object:nil
|
||||
userInfo:@{
|
||||
@"urls": @[],
|
||||
@"source": @"qrcode",
|
||||
@"error": @"Failed to get display information"
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
NSMutableArray* foundSSUrls = [NSMutableArray array];
|
||||
|
||||
CIDetector *detector = [CIDetector detectorOfType:@"CIDetectorTypeQRCode"
|
||||
context:nil
|
||||
options:@{ CIDetectorAccuracy:CIDetectorAccuracyHigh }];
|
||||
context:nil
|
||||
options:@{ CIDetectorAccuracy:CIDetectorAccuracyHigh }];
|
||||
|
||||
for (unsigned int displaysIndex = 0; displaysIndex < dspCount; displaysIndex++)
|
||||
{
|
||||
/* Make a snapshot image of the current display. */
|
||||
int totalQRCodesFound = 0;
|
||||
int validSSUrlsFound = 0;
|
||||
|
||||
for (unsigned int displaysIndex = 0; displaysIndex < dspCount; displaysIndex++) {
|
||||
CGImageRef image = CGDisplayCreateImage(displays[displaysIndex]);
|
||||
NSArray *features = [detector featuresInImage:[CIImage imageWithCGImage:image]];
|
||||
|
||||
/* count total QR codes found */
|
||||
totalQRCodesFound += (int)features.count;
|
||||
|
||||
for (CIQRCodeFeature *feature in features) {
|
||||
NSLog(@"%@", feature.messageString);
|
||||
if ( [feature.messageString hasPrefix:@"ss://"] )
|
||||
{
|
||||
NSLog(@"Found QR Code: %@", feature.messageString);
|
||||
[foundQRCodes addObject:feature.messageString];
|
||||
|
||||
if ([feature.messageString hasPrefix:@"ss://"]) {
|
||||
NSURL *url = [NSURL URLWithString:feature.messageString];
|
||||
if (url) {
|
||||
[foundSSUrls addObject:url];
|
||||
validSSUrlsFound++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CGImageRelease(image);
|
||||
CGImageRelease(image);
|
||||
}
|
||||
|
||||
free(displays);
|
||||
|
||||
/* prepare notification information */
|
||||
NSString *notificationTitle;
|
||||
NSString *notificationSubtitle;
|
||||
NSString *notificationBody;
|
||||
|
||||
if (totalQRCodesFound == 0) {
|
||||
notificationTitle = [NSString stringWithFormat:@"Scanned %d displays", dspCount];
|
||||
notificationSubtitle = @"No QR codes found";
|
||||
notificationBody = @"Try adjusting the QR code position on your screen";
|
||||
} else if (validSSUrlsFound == 0) {
|
||||
notificationTitle = [NSString stringWithFormat:@"Found %d QR code(s)", totalQRCodesFound];
|
||||
notificationSubtitle = @"No valid Shadowsocks URLs";
|
||||
notificationBody = @"QR codes found are not Shadowsocks configuration";
|
||||
} else {
|
||||
notificationTitle = [NSString stringWithFormat:@"Found %d Shadowsocks URL(s)", validSSUrlsFound];
|
||||
notificationSubtitle = [NSString stringWithFormat:@"Scanned %d displays, found %d QR codes", dspCount, totalQRCodesFound];
|
||||
notificationBody = @"Processing Shadowsocks configuration...";
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter]
|
||||
postNotificationName:@"NOTIFY_FOUND_SS_URL"
|
||||
object:nil
|
||||
userInfo: @{ @"urls": foundSSUrls,
|
||||
@"source": @"qrcode"
|
||||
}
|
||||
];
|
||||
userInfo:@{
|
||||
@"urls": foundSSUrls,
|
||||
@"source": @"qrcode",
|
||||
@"title": notificationTitle,
|
||||
@"subtitle": notificationSubtitle,
|
||||
@"body": notificationBody,
|
||||
@"scanInfo": @{
|
||||
@"displayCount": @(dspCount),
|
||||
@"totalQRCodes": @(totalQRCodesFound),
|
||||
@"validURLs": @(validSSUrlsFound)
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
NSImage* createQRImage(NSString *string, NSSize size) {
|
||||
|
||||
Reference in New Issue
Block a user