├── .gitignore
├── Product
└── SandBoxTricker.zip
├── README.md
├── SandBoxTricker
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ └── MainMenu.xib
├── Info.plist
└── SandBoxTricker.entitlements
├── TFS.sketch
├── TFSHelper.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── TFSHelper
├── AppDelegate.swift
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── Contents.json
│ │ ├── TFS.png
│ │ └── tfs1024.png
│ ├── Contents.json
│ └── TFSmenu.imageset
│ │ ├── Contents.json
│ │ └── TFSmenu.png
├── Base.lproj
│ └── Main.storyboard
├── Info.plist
├── TFSHelper.entitlements
├── Utils.swift
├── setsearchdomains.sh
└── simulateKeys.scpt
├── TFSHelperLauncher
├── AppDelegate.swift
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ └── MainMenu.xib
├── Info.plist
└── TFSHelperLauncher.entitlements
├── TFSHelperTests
├── Info.plist
└── TFSHelperTests.swift
└── image
├── TFS.png
├── TFSmenuicon.png
└── screenshot.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | xcuserdata
13 | *.xccheckout
14 | *.moved-aside
15 | DerivedData
16 | *.hmap
17 | *.ipa
18 | *.xcuserstate
19 |
20 | # CocoaPods
21 | #
22 | # We recommend against adding the Pods directory to your .gitignore. However
23 | # you should judge for yourself, the pros and cons are mentioned at:
24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
25 | #
26 | # Pods/
27 |
--------------------------------------------------------------------------------
/Product/SandBoxTricker.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/Product/SandBoxTricker.zip
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # TFSHelper
2 |
3 | 
4 | 
5 | 
6 |
7 | 
8 |
9 | 鹅厂用 Mac 的小伙伴们的福利!噗,其实也不算什么福利。
10 |
11 | ## 什么是TFSHelper
12 |
13 | TFSHelper 是我开发的一个 Mac 上的 tfs 辅助工具。它可以在我们复制 tfs 链接时自动连接 tfs 服务器,并自动识别 windows 下的 tfs 格式,将其转化成 Mac OS X 的格式后连接到服务器。它不占用 Dock 上的宝贵空间,只停留在上方的菜单栏,当你想手动打开剪贴板中的 tfs 链接时,也可以点击菜单栏的  图标来展开菜单列表,点击“打开链接”按钮。同时也可以选择是否开启自动捕获链接功能和登录时是否自动启动。当自动捕获功能开启时,手动打开链接按钮将会隐藏。它还会自动记录最近使用的5个 tfs 链接:
14 |
15 | 
16 |
17 | 如果你经常会用到这款工具,可以将其设为登录时自动启动。
18 |
19 | 可以在 [https://github.com/yulingtianxia/TFSHelper/releases](https://github.com/yulingtianxia/TFSHelper/releases) 下载 TFSHelper 最新的 Release 版本。
20 |
21 | ## 为什么要做这个小工具
22 | 作为一名 iOS 开发,平时使用 Mac 作为开发机。而身边很多人发的 tfs 链接为 windows 格式,需要手动转换或者照着路径手动一层一层点进去,由于 Mac 解析文件 tfs 的路径较慢,所以十分费时。本着 **“所有超过90秒的重复工作都应自动化”** 的原则,我开发了这款小工具。
23 |
24 | ## 实现原理
25 |
26 | 详细的实现原理可以查看[这篇博文](http://yulingtianxia.com/blog/2016/02/27/TFSHelper/)。
27 |
28 | 开发语言主要是如今火爆的 Swift 语言和古老的 AppleScript 脚本语言。有兴趣的同学可以加入进来,或是提 PR。
29 |
30 | 原理是监听 Mac OS X 的 Clipboard,匹配其中的文字,如果是 `\\tencent\` 或 `smb://tencent.com` 开头的字符串,就使用 AppleScript 脚本打开 Finder 来连接 tfs 地址。
31 |
32 | 登录时启动的原理是将其添加为启动项,可以参照[这篇文章](https://theswiftdev.com/2015/09/17/first-os-x-tutorial-how-to-launch-an-os-x-app-at-login/)。
33 |
34 | 常用链接会记录最近打开的 5 个 TFS 链接,因为 `NSCache` 不是很符合我的要求,所以我自己手动写了个 LRU Cache。相比于 Cocoa 提供的 `NSCache`,我写的这个 LRU Cache 支持遍历 key 值,并根据场景需求做了一些定制,比如 get 操作并不会算作使用频次。用法很简单,可以将其当为数组来获取 key,也能当成字典使用,通过 key 获取 value。因为我让它兼容了两套协议,并实现 `SequenceType` 协议能够使用 `for...in` 遍历,这些特性都是 `NSCache` 所没有的。
35 |
36 | ## 版本记录
37 |
38 | ### v1.3.1
39 |
40 | 自动去除链接中的换行
41 |
42 | ### v1.3.0 beta
43 |
44 | 由于 NSCache 不是很符合我的需求,我自己构造了个LRU Cache 来缓存最近使用的5个 tfs 链接
45 |
46 | ### v1.2.2
47 |
48 | 采用检测并连接 tfs 延时0.5秒清除粘贴板的策略
49 |
50 | ### v1.2.1
51 |
52 | - 修复 bug
53 | - 调整粘贴板策略
54 |
55 | ### v1.2
56 |
57 | - 添加登录时自动启动
58 |
59 | ### v1.1
60 |
61 | - 添加自动捕获tfs链接的开关
62 | - 添加退出功能
63 |
64 | ### v1.0
65 |
66 | - 实现自动打开 tfs 链接
67 | - 实现手动打开 tfs 链接
68 | - 绘制图标
69 |
70 | ## License
71 |
72 | The MIT License.
73 |
74 |
--------------------------------------------------------------------------------
/SandBoxTricker/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // SandBoxTricker
4 | //
5 | // Created by 杨萧玉 on 16/6/4.
6 | // Copyright © 2016年 杨萧玉. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | let mainAppIdentifier = "com.yulingtianxia.TFSHelper"
15 |
16 | func applicationDidFinishLaunching(_ aNotification: Notification) {
17 | // Insert code here to initialize your application
18 | DistributedNotificationCenter.default().addObserver(self, selector: #selector(AppDelegate.simulateKeys), name: Notification.Name("simulateKeys"), object: mainAppIdentifier)
19 | DistributedNotificationCenter.default().addObserver(self, selector: #selector(AppDelegate.terminate), name: Notification.Name("killSandBoxTricker"), object: mainAppIdentifier)
20 | setSearchDomains()
21 | }
22 |
23 | func applicationWillTerminate(_ aNotification: Notification) {
24 | // Insert code here to tear down your application
25 | }
26 |
27 | @objc func simulateKeys() {
28 | let task = Process()
29 | task.launchPath = "/usr/bin/osascript"
30 | task.arguments = ["\(Bundle.main.resourcePath!)/simulateKeys.scpt"]
31 | task.launch()
32 | }
33 |
34 | func setSearchDomains() {
35 | let task = Process()
36 | task.launchPath = "/bin/sh"
37 | task.arguments = ["\(Bundle.main.resourcePath!)/setsearchdomains.sh"]
38 | task.launch()
39 | }
40 |
41 | @objc func terminate() {
42 | NSApp.terminate(nil)
43 | }
44 |
45 | deinit {
46 | DistributedNotificationCenter.default().removeObserver(self)
47 | }
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/SandBoxTricker/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/SandBoxTricker/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
665 |
666 |
667 |
--------------------------------------------------------------------------------
/SandBoxTricker/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.4.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 5
25 | LSApplicationCategoryType
26 | public.app-category.utilities
27 | LSBackgroundOnly
28 |
29 | LSMinimumSystemVersion
30 | $(MACOSX_DEPLOYMENT_TARGET)
31 | NSHumanReadableCopyright
32 | Copyright © 2018年 杨萧玉. All rights reserved.
33 | NSMainNibFile
34 | MainMenu
35 | NSPrincipalClass
36 | NSApplication
37 |
38 |
39 |
--------------------------------------------------------------------------------
/SandBoxTricker/SandBoxTricker.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/TFS.sketch:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/TFS.sketch
--------------------------------------------------------------------------------
/TFSHelper.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A42F6B091D02D83F0030FC9F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42F6B081D02D83F0030FC9F /* AppDelegate.swift */; };
11 | A42F6B0B1D02D83F0030FC9F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A42F6B0A1D02D83F0030FC9F /* Assets.xcassets */; };
12 | A42F6B0E1D02D83F0030FC9F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A42F6B0C1D02D83F0030FC9F /* MainMenu.xib */; };
13 | A432581F1C06E9A500E7E8BE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A432581E1C06E9A500E7E8BE /* AppDelegate.swift */; };
14 | A43258231C06E9A500E7E8BE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A43258221C06E9A500E7E8BE /* Assets.xcassets */; };
15 | A43258261C06E9A500E7E8BE /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A43258241C06E9A500E7E8BE /* Main.storyboard */; };
16 | A43258311C06E9A500E7E8BE /* TFSHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A43258301C06E9A500E7E8BE /* TFSHelperTests.swift */; };
17 | A432584A1C06E9D500E7E8BE /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = A43258491C06E9D500E7E8BE /* Utils.swift */; };
18 | A482F80A1D05740500FD8F6E /* simulateKeys.scpt in Resources */ = {isa = PBXBuildFile; fileRef = A432584B1C06EA2800E7E8BE /* simulateKeys.scpt */; };
19 | A486FBA721BA78930066A827 /* setsearchdomains.sh in Resources */ = {isa = PBXBuildFile; fileRef = A486FBA621BA78930066A827 /* setsearchdomains.sh */; };
20 | A4BB13D01C0B349C00466DF5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4BB13CF1C0B349C00466DF5 /* AppDelegate.swift */; };
21 | A4BB13D21C0B349C00466DF5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A4BB13D11C0B349C00466DF5 /* Assets.xcassets */; };
22 | A4BB13D51C0B349C00466DF5 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = A4BB13D31C0B349C00466DF5 /* MainMenu.xib */; };
23 | A4BB13DD1C0B35BA00466DF5 /* TFSHelperLauncher.app in CopyFiles */ = {isa = PBXBuildFile; fileRef = A4BB13CD1C0B349C00466DF5 /* TFSHelperLauncher.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
24 | /* End PBXBuildFile section */
25 |
26 | /* Begin PBXContainerItemProxy section */
27 | A432582D1C06E9A500E7E8BE /* PBXContainerItemProxy */ = {
28 | isa = PBXContainerItemProxy;
29 | containerPortal = A43258131C06E9A500E7E8BE /* Project object */;
30 | proxyType = 1;
31 | remoteGlobalIDString = A432581A1C06E9A500E7E8BE;
32 | remoteInfo = TFSHelper;
33 | };
34 | /* End PBXContainerItemProxy section */
35 |
36 | /* Begin PBXCopyFilesBuildPhase section */
37 | A4BB13DC1C0B35A300466DF5 /* CopyFiles */ = {
38 | isa = PBXCopyFilesBuildPhase;
39 | buildActionMask = 2147483647;
40 | dstPath = Contents/Library/LoginItems;
41 | dstSubfolderSpec = 1;
42 | files = (
43 | A4BB13DD1C0B35BA00466DF5 /* TFSHelperLauncher.app in CopyFiles */,
44 | );
45 | runOnlyForDeploymentPostprocessing = 0;
46 | };
47 | /* End PBXCopyFilesBuildPhase section */
48 |
49 | /* Begin PBXFileReference section */
50 | A42F6B061D02D83F0030FC9F /* SandBoxTricker.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SandBoxTricker.app; sourceTree = BUILT_PRODUCTS_DIR; };
51 | A42F6B081D02D83F0030FC9F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
52 | A42F6B0A1D02D83F0030FC9F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
53 | A42F6B0D1D02D83F0030FC9F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
54 | A42F6B0F1D02D83F0030FC9F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
55 | A432581B1C06E9A500E7E8BE /* TFSHelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TFSHelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
56 | A432581E1C06E9A500E7E8BE /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
57 | A43258221C06E9A500E7E8BE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
58 | A43258251C06E9A500E7E8BE /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
59 | A43258271C06E9A500E7E8BE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
60 | A432582C1C06E9A500E7E8BE /* TFSHelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TFSHelperTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
61 | A43258301C06E9A500E7E8BE /* TFSHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TFSHelperTests.swift; sourceTree = ""; };
62 | A43258321C06E9A500E7E8BE /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
63 | A43258491C06E9D500E7E8BE /* Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; };
64 | A432584B1C06EA2800E7E8BE /* simulateKeys.scpt */ = {isa = PBXFileReference; lastKnownFileType = file; name = simulateKeys.scpt; path = ../TFSHelper/simulateKeys.scpt; sourceTree = ""; };
65 | A486FBA621BA78930066A827 /* setsearchdomains.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = setsearchdomains.sh; path = TFSHelper/setsearchdomains.sh; sourceTree = SOURCE_ROOT; };
66 | A4ADC03F1D058F310048BB7C /* SandBoxTricker.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = SandBoxTricker.entitlements; sourceTree = ""; };
67 | A4BB13CD1C0B349C00466DF5 /* TFSHelperLauncher.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TFSHelperLauncher.app; sourceTree = BUILT_PRODUCTS_DIR; };
68 | A4BB13CF1C0B349C00466DF5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
69 | A4BB13D11C0B349C00466DF5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
70 | A4BB13D41C0B349C00466DF5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; };
71 | A4BB13D61C0B349C00466DF5 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
72 | A4BB13DA1C0B350F00466DF5 /* TFSHelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TFSHelper.entitlements; sourceTree = ""; };
73 | A4BB13DB1C0B352500466DF5 /* TFSHelperLauncher.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = TFSHelperLauncher.entitlements; sourceTree = ""; };
74 | /* End PBXFileReference section */
75 |
76 | /* Begin PBXFrameworksBuildPhase section */
77 | A42F6B031D02D83F0030FC9F /* Frameworks */ = {
78 | isa = PBXFrameworksBuildPhase;
79 | buildActionMask = 2147483647;
80 | files = (
81 | );
82 | runOnlyForDeploymentPostprocessing = 0;
83 | };
84 | A43258181C06E9A500E7E8BE /* Frameworks */ = {
85 | isa = PBXFrameworksBuildPhase;
86 | buildActionMask = 2147483647;
87 | files = (
88 | );
89 | runOnlyForDeploymentPostprocessing = 0;
90 | };
91 | A43258291C06E9A500E7E8BE /* Frameworks */ = {
92 | isa = PBXFrameworksBuildPhase;
93 | buildActionMask = 2147483647;
94 | files = (
95 | );
96 | runOnlyForDeploymentPostprocessing = 0;
97 | };
98 | A4BB13CA1C0B349C00466DF5 /* Frameworks */ = {
99 | isa = PBXFrameworksBuildPhase;
100 | buildActionMask = 2147483647;
101 | files = (
102 | );
103 | runOnlyForDeploymentPostprocessing = 0;
104 | };
105 | /* End PBXFrameworksBuildPhase section */
106 |
107 | /* Begin PBXGroup section */
108 | A42F6B071D02D83F0030FC9F /* SandBoxTricker */ = {
109 | isa = PBXGroup;
110 | children = (
111 | A4ADC03F1D058F310048BB7C /* SandBoxTricker.entitlements */,
112 | A42F6B081D02D83F0030FC9F /* AppDelegate.swift */,
113 | A432584B1C06EA2800E7E8BE /* simulateKeys.scpt */,
114 | A486FBA621BA78930066A827 /* setsearchdomains.sh */,
115 | A42F6B0A1D02D83F0030FC9F /* Assets.xcassets */,
116 | A42F6B0C1D02D83F0030FC9F /* MainMenu.xib */,
117 | A42F6B0F1D02D83F0030FC9F /* Info.plist */,
118 | );
119 | path = SandBoxTricker;
120 | sourceTree = "";
121 | };
122 | A43258121C06E9A500E7E8BE = {
123 | isa = PBXGroup;
124 | children = (
125 | A432581D1C06E9A500E7E8BE /* TFSHelper */,
126 | A432582F1C06E9A500E7E8BE /* TFSHelperTests */,
127 | A4BB13CE1C0B349C00466DF5 /* TFSHelperLauncher */,
128 | A42F6B071D02D83F0030FC9F /* SandBoxTricker */,
129 | A432581C1C06E9A500E7E8BE /* Products */,
130 | );
131 | sourceTree = "";
132 | };
133 | A432581C1C06E9A500E7E8BE /* Products */ = {
134 | isa = PBXGroup;
135 | children = (
136 | A432581B1C06E9A500E7E8BE /* TFSHelper.app */,
137 | A432582C1C06E9A500E7E8BE /* TFSHelperTests.xctest */,
138 | A4BB13CD1C0B349C00466DF5 /* TFSHelperLauncher.app */,
139 | A42F6B061D02D83F0030FC9F /* SandBoxTricker.app */,
140 | );
141 | name = Products;
142 | sourceTree = "";
143 | };
144 | A432581D1C06E9A500E7E8BE /* TFSHelper */ = {
145 | isa = PBXGroup;
146 | children = (
147 | A4BB13DA1C0B350F00466DF5 /* TFSHelper.entitlements */,
148 | A432581E1C06E9A500E7E8BE /* AppDelegate.swift */,
149 | A43258491C06E9D500E7E8BE /* Utils.swift */,
150 | A43258221C06E9A500E7E8BE /* Assets.xcassets */,
151 | A43258241C06E9A500E7E8BE /* Main.storyboard */,
152 | A43258271C06E9A500E7E8BE /* Info.plist */,
153 | );
154 | path = TFSHelper;
155 | sourceTree = "";
156 | };
157 | A432582F1C06E9A500E7E8BE /* TFSHelperTests */ = {
158 | isa = PBXGroup;
159 | children = (
160 | A43258301C06E9A500E7E8BE /* TFSHelperTests.swift */,
161 | A43258321C06E9A500E7E8BE /* Info.plist */,
162 | );
163 | path = TFSHelperTests;
164 | sourceTree = "";
165 | };
166 | A4BB13CE1C0B349C00466DF5 /* TFSHelperLauncher */ = {
167 | isa = PBXGroup;
168 | children = (
169 | A4BB13DB1C0B352500466DF5 /* TFSHelperLauncher.entitlements */,
170 | A4BB13CF1C0B349C00466DF5 /* AppDelegate.swift */,
171 | A4BB13D11C0B349C00466DF5 /* Assets.xcassets */,
172 | A4BB13D31C0B349C00466DF5 /* MainMenu.xib */,
173 | A4BB13D61C0B349C00466DF5 /* Info.plist */,
174 | );
175 | path = TFSHelperLauncher;
176 | sourceTree = "";
177 | };
178 | /* End PBXGroup section */
179 |
180 | /* Begin PBXNativeTarget section */
181 | A42F6B051D02D83F0030FC9F /* SandBoxTricker */ = {
182 | isa = PBXNativeTarget;
183 | buildConfigurationList = A42F6B121D02D83F0030FC9F /* Build configuration list for PBXNativeTarget "SandBoxTricker" */;
184 | buildPhases = (
185 | A42F6B021D02D83F0030FC9F /* Sources */,
186 | A42F6B031D02D83F0030FC9F /* Frameworks */,
187 | A42F6B041D02D83F0030FC9F /* Resources */,
188 | );
189 | buildRules = (
190 | );
191 | dependencies = (
192 | );
193 | name = SandBoxTricker;
194 | productName = SandBoxTricker;
195 | productReference = A42F6B061D02D83F0030FC9F /* SandBoxTricker.app */;
196 | productType = "com.apple.product-type.application";
197 | };
198 | A432581A1C06E9A500E7E8BE /* TFSHelper */ = {
199 | isa = PBXNativeTarget;
200 | buildConfigurationList = A43258401C06E9A500E7E8BE /* Build configuration list for PBXNativeTarget "TFSHelper" */;
201 | buildPhases = (
202 | A43258171C06E9A500E7E8BE /* Sources */,
203 | A43258181C06E9A500E7E8BE /* Frameworks */,
204 | A43258191C06E9A500E7E8BE /* Resources */,
205 | A4BB13DC1C0B35A300466DF5 /* CopyFiles */,
206 | );
207 | buildRules = (
208 | );
209 | dependencies = (
210 | );
211 | name = TFSHelper;
212 | productName = TFSHelper;
213 | productReference = A432581B1C06E9A500E7E8BE /* TFSHelper.app */;
214 | productType = "com.apple.product-type.application";
215 | };
216 | A432582B1C06E9A500E7E8BE /* TFSHelperTests */ = {
217 | isa = PBXNativeTarget;
218 | buildConfigurationList = A43258431C06E9A500E7E8BE /* Build configuration list for PBXNativeTarget "TFSHelperTests" */;
219 | buildPhases = (
220 | A43258281C06E9A500E7E8BE /* Sources */,
221 | A43258291C06E9A500E7E8BE /* Frameworks */,
222 | A432582A1C06E9A500E7E8BE /* Resources */,
223 | );
224 | buildRules = (
225 | );
226 | dependencies = (
227 | A432582E1C06E9A500E7E8BE /* PBXTargetDependency */,
228 | );
229 | name = TFSHelperTests;
230 | productName = TFSHelperTests;
231 | productReference = A432582C1C06E9A500E7E8BE /* TFSHelperTests.xctest */;
232 | productType = "com.apple.product-type.bundle.unit-test";
233 | };
234 | A4BB13CC1C0B349C00466DF5 /* TFSHelperLauncher */ = {
235 | isa = PBXNativeTarget;
236 | buildConfigurationList = A4BB13D91C0B349C00466DF5 /* Build configuration list for PBXNativeTarget "TFSHelperLauncher" */;
237 | buildPhases = (
238 | A4BB13C91C0B349C00466DF5 /* Sources */,
239 | A4BB13CA1C0B349C00466DF5 /* Frameworks */,
240 | A4BB13CB1C0B349C00466DF5 /* Resources */,
241 | );
242 | buildRules = (
243 | );
244 | dependencies = (
245 | );
246 | name = TFSHelperLauncher;
247 | productName = TFSHelperLauncher;
248 | productReference = A4BB13CD1C0B349C00466DF5 /* TFSHelperLauncher.app */;
249 | productType = "com.apple.product-type.application";
250 | };
251 | /* End PBXNativeTarget section */
252 |
253 | /* Begin PBXProject section */
254 | A43258131C06E9A500E7E8BE /* Project object */ = {
255 | isa = PBXProject;
256 | attributes = {
257 | LastSwiftUpdateCheck = 0730;
258 | LastUpgradeCheck = 1010;
259 | ORGANIZATIONNAME = "杨萧玉";
260 | TargetAttributes = {
261 | A42F6B051D02D83F0030FC9F = {
262 | CreatedOnToolsVersion = 7.3.1;
263 | DevelopmentTeam = D3RCVUP6VH;
264 | LastSwiftMigration = 0900;
265 | SystemCapabilities = {
266 | com.apple.Sandbox = {
267 | enabled = 0;
268 | };
269 | };
270 | };
271 | A432581A1C06E9A500E7E8BE = {
272 | CreatedOnToolsVersion = 7.1.1;
273 | DevelopmentTeam = D3RCVUP6VH;
274 | LastSwiftMigration = 0900;
275 | SystemCapabilities = {
276 | com.apple.Sandbox = {
277 | enabled = 1;
278 | };
279 | };
280 | };
281 | A432582B1C06E9A500E7E8BE = {
282 | CreatedOnToolsVersion = 7.1.1;
283 | LastSwiftMigration = 0900;
284 | TestTargetID = A432581A1C06E9A500E7E8BE;
285 | };
286 | A4BB13CC1C0B349C00466DF5 = {
287 | CreatedOnToolsVersion = 7.1.1;
288 | DevelopmentTeam = D3RCVUP6VH;
289 | LastSwiftMigration = 0900;
290 | SystemCapabilities = {
291 | com.apple.Sandbox = {
292 | enabled = 1;
293 | };
294 | };
295 | };
296 | };
297 | };
298 | buildConfigurationList = A43258161C06E9A500E7E8BE /* Build configuration list for PBXProject "TFSHelper" */;
299 | compatibilityVersion = "Xcode 3.2";
300 | developmentRegion = English;
301 | hasScannedForEncodings = 0;
302 | knownRegions = (
303 | en,
304 | Base,
305 | );
306 | mainGroup = A43258121C06E9A500E7E8BE;
307 | productRefGroup = A432581C1C06E9A500E7E8BE /* Products */;
308 | projectDirPath = "";
309 | projectRoot = "";
310 | targets = (
311 | A432581A1C06E9A500E7E8BE /* TFSHelper */,
312 | A432582B1C06E9A500E7E8BE /* TFSHelperTests */,
313 | A4BB13CC1C0B349C00466DF5 /* TFSHelperLauncher */,
314 | A42F6B051D02D83F0030FC9F /* SandBoxTricker */,
315 | );
316 | };
317 | /* End PBXProject section */
318 |
319 | /* Begin PBXResourcesBuildPhase section */
320 | A42F6B041D02D83F0030FC9F /* Resources */ = {
321 | isa = PBXResourcesBuildPhase;
322 | buildActionMask = 2147483647;
323 | files = (
324 | A42F6B0B1D02D83F0030FC9F /* Assets.xcassets in Resources */,
325 | A486FBA721BA78930066A827 /* setsearchdomains.sh in Resources */,
326 | A482F80A1D05740500FD8F6E /* simulateKeys.scpt in Resources */,
327 | A42F6B0E1D02D83F0030FC9F /* MainMenu.xib in Resources */,
328 | );
329 | runOnlyForDeploymentPostprocessing = 0;
330 | };
331 | A43258191C06E9A500E7E8BE /* Resources */ = {
332 | isa = PBXResourcesBuildPhase;
333 | buildActionMask = 2147483647;
334 | files = (
335 | A43258231C06E9A500E7E8BE /* Assets.xcassets in Resources */,
336 | A43258261C06E9A500E7E8BE /* Main.storyboard in Resources */,
337 | );
338 | runOnlyForDeploymentPostprocessing = 0;
339 | };
340 | A432582A1C06E9A500E7E8BE /* Resources */ = {
341 | isa = PBXResourcesBuildPhase;
342 | buildActionMask = 2147483647;
343 | files = (
344 | );
345 | runOnlyForDeploymentPostprocessing = 0;
346 | };
347 | A4BB13CB1C0B349C00466DF5 /* Resources */ = {
348 | isa = PBXResourcesBuildPhase;
349 | buildActionMask = 2147483647;
350 | files = (
351 | A4BB13D21C0B349C00466DF5 /* Assets.xcassets in Resources */,
352 | A4BB13D51C0B349C00466DF5 /* MainMenu.xib in Resources */,
353 | );
354 | runOnlyForDeploymentPostprocessing = 0;
355 | };
356 | /* End PBXResourcesBuildPhase section */
357 |
358 | /* Begin PBXSourcesBuildPhase section */
359 | A42F6B021D02D83F0030FC9F /* Sources */ = {
360 | isa = PBXSourcesBuildPhase;
361 | buildActionMask = 2147483647;
362 | files = (
363 | A42F6B091D02D83F0030FC9F /* AppDelegate.swift in Sources */,
364 | );
365 | runOnlyForDeploymentPostprocessing = 0;
366 | };
367 | A43258171C06E9A500E7E8BE /* Sources */ = {
368 | isa = PBXSourcesBuildPhase;
369 | buildActionMask = 2147483647;
370 | files = (
371 | A432581F1C06E9A500E7E8BE /* AppDelegate.swift in Sources */,
372 | A432584A1C06E9D500E7E8BE /* Utils.swift in Sources */,
373 | );
374 | runOnlyForDeploymentPostprocessing = 0;
375 | };
376 | A43258281C06E9A500E7E8BE /* Sources */ = {
377 | isa = PBXSourcesBuildPhase;
378 | buildActionMask = 2147483647;
379 | files = (
380 | A43258311C06E9A500E7E8BE /* TFSHelperTests.swift in Sources */,
381 | );
382 | runOnlyForDeploymentPostprocessing = 0;
383 | };
384 | A4BB13C91C0B349C00466DF5 /* Sources */ = {
385 | isa = PBXSourcesBuildPhase;
386 | buildActionMask = 2147483647;
387 | files = (
388 | A4BB13D01C0B349C00466DF5 /* AppDelegate.swift in Sources */,
389 | );
390 | runOnlyForDeploymentPostprocessing = 0;
391 | };
392 | /* End PBXSourcesBuildPhase section */
393 |
394 | /* Begin PBXTargetDependency section */
395 | A432582E1C06E9A500E7E8BE /* PBXTargetDependency */ = {
396 | isa = PBXTargetDependency;
397 | target = A432581A1C06E9A500E7E8BE /* TFSHelper */;
398 | targetProxy = A432582D1C06E9A500E7E8BE /* PBXContainerItemProxy */;
399 | };
400 | /* End PBXTargetDependency section */
401 |
402 | /* Begin PBXVariantGroup section */
403 | A42F6B0C1D02D83F0030FC9F /* MainMenu.xib */ = {
404 | isa = PBXVariantGroup;
405 | children = (
406 | A42F6B0D1D02D83F0030FC9F /* Base */,
407 | );
408 | name = MainMenu.xib;
409 | sourceTree = "";
410 | };
411 | A43258241C06E9A500E7E8BE /* Main.storyboard */ = {
412 | isa = PBXVariantGroup;
413 | children = (
414 | A43258251C06E9A500E7E8BE /* Base */,
415 | );
416 | name = Main.storyboard;
417 | sourceTree = "";
418 | };
419 | A4BB13D31C0B349C00466DF5 /* MainMenu.xib */ = {
420 | isa = PBXVariantGroup;
421 | children = (
422 | A4BB13D41C0B349C00466DF5 /* Base */,
423 | );
424 | name = MainMenu.xib;
425 | sourceTree = "";
426 | };
427 | /* End PBXVariantGroup section */
428 |
429 | /* Begin XCBuildConfiguration section */
430 | A42F6B101D02D83F0030FC9F /* Debug */ = {
431 | isa = XCBuildConfiguration;
432 | buildSettings = {
433 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
434 | CLANG_ANALYZER_NONNULL = YES;
435 | CODE_SIGN_IDENTITY = "Mac Developer";
436 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer";
437 | COMBINE_HIDPI_IMAGES = YES;
438 | INFOPLIST_FILE = SandBoxTricker/Info.plist;
439 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
440 | MACOSX_DEPLOYMENT_TARGET = 10.10;
441 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.SandBoxTricker;
442 | PRODUCT_NAME = "$(TARGET_NAME)";
443 | PROVISIONING_PROFILE = "";
444 | SKIP_INSTALL = YES;
445 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
446 | SWIFT_VERSION = 4.0;
447 | };
448 | name = Debug;
449 | };
450 | A42F6B111D02D83F0030FC9F /* Release */ = {
451 | isa = XCBuildConfiguration;
452 | buildSettings = {
453 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
454 | CLANG_ANALYZER_NONNULL = YES;
455 | CODE_SIGN_IDENTITY = "Mac Developer";
456 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Mac Developer";
457 | COMBINE_HIDPI_IMAGES = YES;
458 | INFOPLIST_FILE = SandBoxTricker/Info.plist;
459 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
460 | MACOSX_DEPLOYMENT_TARGET = 10.10;
461 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.SandBoxTricker;
462 | PRODUCT_NAME = "$(TARGET_NAME)";
463 | PROVISIONING_PROFILE = "";
464 | SKIP_INSTALL = YES;
465 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
466 | SWIFT_VERSION = 4.0;
467 | };
468 | name = Release;
469 | };
470 | A432583E1C06E9A500E7E8BE /* Debug */ = {
471 | isa = XCBuildConfiguration;
472 | buildSettings = {
473 | ALWAYS_SEARCH_USER_PATHS = NO;
474 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
475 | CLANG_CXX_LIBRARY = "libc++";
476 | CLANG_ENABLE_MODULES = YES;
477 | CLANG_ENABLE_OBJC_ARC = YES;
478 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
479 | CLANG_WARN_BOOL_CONVERSION = YES;
480 | CLANG_WARN_COMMA = YES;
481 | CLANG_WARN_CONSTANT_CONVERSION = YES;
482 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
483 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
484 | CLANG_WARN_EMPTY_BODY = YES;
485 | CLANG_WARN_ENUM_CONVERSION = YES;
486 | CLANG_WARN_INFINITE_RECURSION = YES;
487 | CLANG_WARN_INT_CONVERSION = YES;
488 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
489 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
490 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
491 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
492 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
493 | CLANG_WARN_STRICT_PROTOTYPES = YES;
494 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
495 | CLANG_WARN_UNREACHABLE_CODE = YES;
496 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
497 | CODE_SIGN_IDENTITY = "-";
498 | COPY_PHASE_STRIP = NO;
499 | DEBUG_INFORMATION_FORMAT = dwarf;
500 | ENABLE_STRICT_OBJC_MSGSEND = YES;
501 | ENABLE_TESTABILITY = YES;
502 | GCC_C_LANGUAGE_STANDARD = gnu99;
503 | GCC_DYNAMIC_NO_PIC = NO;
504 | GCC_NO_COMMON_BLOCKS = YES;
505 | GCC_OPTIMIZATION_LEVEL = 0;
506 | GCC_PREPROCESSOR_DEFINITIONS = (
507 | "DEBUG=1",
508 | "$(inherited)",
509 | );
510 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
511 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
512 | GCC_WARN_UNDECLARED_SELECTOR = YES;
513 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
514 | GCC_WARN_UNUSED_FUNCTION = YES;
515 | GCC_WARN_UNUSED_VARIABLE = YES;
516 | MACOSX_DEPLOYMENT_TARGET = 10.10;
517 | MTL_ENABLE_DEBUG_INFO = YES;
518 | ONLY_ACTIVE_ARCH = YES;
519 | SDKROOT = macosx;
520 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
521 | };
522 | name = Debug;
523 | };
524 | A432583F1C06E9A500E7E8BE /* Release */ = {
525 | isa = XCBuildConfiguration;
526 | buildSettings = {
527 | ALWAYS_SEARCH_USER_PATHS = NO;
528 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
529 | CLANG_CXX_LIBRARY = "libc++";
530 | CLANG_ENABLE_MODULES = YES;
531 | CLANG_ENABLE_OBJC_ARC = YES;
532 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
533 | CLANG_WARN_BOOL_CONVERSION = YES;
534 | CLANG_WARN_COMMA = YES;
535 | CLANG_WARN_CONSTANT_CONVERSION = YES;
536 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
537 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
538 | CLANG_WARN_EMPTY_BODY = YES;
539 | CLANG_WARN_ENUM_CONVERSION = YES;
540 | CLANG_WARN_INFINITE_RECURSION = YES;
541 | CLANG_WARN_INT_CONVERSION = YES;
542 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
543 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
544 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
545 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
546 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
547 | CLANG_WARN_STRICT_PROTOTYPES = YES;
548 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
549 | CLANG_WARN_UNREACHABLE_CODE = YES;
550 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
551 | CODE_SIGN_IDENTITY = "-";
552 | COPY_PHASE_STRIP = NO;
553 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
554 | ENABLE_NS_ASSERTIONS = NO;
555 | ENABLE_STRICT_OBJC_MSGSEND = YES;
556 | GCC_C_LANGUAGE_STANDARD = gnu99;
557 | GCC_NO_COMMON_BLOCKS = YES;
558 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
559 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
560 | GCC_WARN_UNDECLARED_SELECTOR = YES;
561 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
562 | GCC_WARN_UNUSED_FUNCTION = YES;
563 | GCC_WARN_UNUSED_VARIABLE = YES;
564 | MACOSX_DEPLOYMENT_TARGET = 10.10;
565 | MTL_ENABLE_DEBUG_INFO = NO;
566 | SDKROOT = macosx;
567 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
568 | };
569 | name = Release;
570 | };
571 | A43258411C06E9A500E7E8BE /* Debug */ = {
572 | isa = XCBuildConfiguration;
573 | buildSettings = {
574 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
575 | CODE_SIGN_ENTITLEMENTS = TFSHelper/TFSHelper.entitlements;
576 | CODE_SIGN_IDENTITY = "Mac Developer";
577 | COMBINE_HIDPI_IMAGES = YES;
578 | INFOPLIST_FILE = TFSHelper/Info.plist;
579 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
580 | MACOSX_DEPLOYMENT_TARGET = 10.10;
581 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelper;
582 | PRODUCT_NAME = "$(TARGET_NAME)";
583 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
584 | SWIFT_VERSION = 4.0;
585 | };
586 | name = Debug;
587 | };
588 | A43258421C06E9A500E7E8BE /* Release */ = {
589 | isa = XCBuildConfiguration;
590 | buildSettings = {
591 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
592 | CODE_SIGN_ENTITLEMENTS = TFSHelper/TFSHelper.entitlements;
593 | CODE_SIGN_IDENTITY = "Mac Developer";
594 | COMBINE_HIDPI_IMAGES = YES;
595 | INFOPLIST_FILE = TFSHelper/Info.plist;
596 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
597 | MACOSX_DEPLOYMENT_TARGET = 10.10;
598 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelper;
599 | PRODUCT_NAME = "$(TARGET_NAME)";
600 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
601 | SWIFT_VERSION = 4.0;
602 | };
603 | name = Release;
604 | };
605 | A43258441C06E9A500E7E8BE /* Debug */ = {
606 | isa = XCBuildConfiguration;
607 | buildSettings = {
608 | BUNDLE_LOADER = "$(TEST_HOST)";
609 | COMBINE_HIDPI_IMAGES = YES;
610 | INFOPLIST_FILE = TFSHelperTests/Info.plist;
611 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
612 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelperTests;
613 | PRODUCT_NAME = "$(TARGET_NAME)";
614 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
615 | SWIFT_VERSION = 4.0;
616 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TFSHelper.app/Contents/MacOS/TFSHelper";
617 | };
618 | name = Debug;
619 | };
620 | A43258451C06E9A500E7E8BE /* Release */ = {
621 | isa = XCBuildConfiguration;
622 | buildSettings = {
623 | BUNDLE_LOADER = "$(TEST_HOST)";
624 | COMBINE_HIDPI_IMAGES = YES;
625 | INFOPLIST_FILE = TFSHelperTests/Info.plist;
626 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
627 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelperTests;
628 | PRODUCT_NAME = "$(TARGET_NAME)";
629 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
630 | SWIFT_VERSION = 4.0;
631 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/TFSHelper.app/Contents/MacOS/TFSHelper";
632 | };
633 | name = Release;
634 | };
635 | A4BB13D71C0B349C00466DF5 /* Debug */ = {
636 | isa = XCBuildConfiguration;
637 | buildSettings = {
638 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
639 | CODE_SIGN_ENTITLEMENTS = TFSHelperLauncher/TFSHelperLauncher.entitlements;
640 | CODE_SIGN_IDENTITY = "Mac Developer";
641 | COMBINE_HIDPI_IMAGES = YES;
642 | INFOPLIST_FILE = TFSHelperLauncher/Info.plist;
643 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
644 | MACOSX_DEPLOYMENT_TARGET = 10.10;
645 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelperLauncher;
646 | PRODUCT_NAME = "$(TARGET_NAME)";
647 | SKIP_INSTALL = YES;
648 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
649 | SWIFT_VERSION = 4.0;
650 | };
651 | name = Debug;
652 | };
653 | A4BB13D81C0B349C00466DF5 /* Release */ = {
654 | isa = XCBuildConfiguration;
655 | buildSettings = {
656 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
657 | CODE_SIGN_ENTITLEMENTS = TFSHelperLauncher/TFSHelperLauncher.entitlements;
658 | CODE_SIGN_IDENTITY = "Mac Developer";
659 | COMBINE_HIDPI_IMAGES = YES;
660 | INFOPLIST_FILE = TFSHelperLauncher/Info.plist;
661 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
662 | MACOSX_DEPLOYMENT_TARGET = 10.10;
663 | PRODUCT_BUNDLE_IDENTIFIER = com.yulingtianxia.TFSHelperLauncher;
664 | PRODUCT_NAME = "$(TARGET_NAME)";
665 | SKIP_INSTALL = YES;
666 | SWIFT_SWIFT3_OBJC_INFERENCE = Off;
667 | SWIFT_VERSION = 4.0;
668 | };
669 | name = Release;
670 | };
671 | /* End XCBuildConfiguration section */
672 |
673 | /* Begin XCConfigurationList section */
674 | A42F6B121D02D83F0030FC9F /* Build configuration list for PBXNativeTarget "SandBoxTricker" */ = {
675 | isa = XCConfigurationList;
676 | buildConfigurations = (
677 | A42F6B101D02D83F0030FC9F /* Debug */,
678 | A42F6B111D02D83F0030FC9F /* Release */,
679 | );
680 | defaultConfigurationIsVisible = 0;
681 | defaultConfigurationName = Release;
682 | };
683 | A43258161C06E9A500E7E8BE /* Build configuration list for PBXProject "TFSHelper" */ = {
684 | isa = XCConfigurationList;
685 | buildConfigurations = (
686 | A432583E1C06E9A500E7E8BE /* Debug */,
687 | A432583F1C06E9A500E7E8BE /* Release */,
688 | );
689 | defaultConfigurationIsVisible = 0;
690 | defaultConfigurationName = Release;
691 | };
692 | A43258401C06E9A500E7E8BE /* Build configuration list for PBXNativeTarget "TFSHelper" */ = {
693 | isa = XCConfigurationList;
694 | buildConfigurations = (
695 | A43258411C06E9A500E7E8BE /* Debug */,
696 | A43258421C06E9A500E7E8BE /* Release */,
697 | );
698 | defaultConfigurationIsVisible = 0;
699 | defaultConfigurationName = Release;
700 | };
701 | A43258431C06E9A500E7E8BE /* Build configuration list for PBXNativeTarget "TFSHelperTests" */ = {
702 | isa = XCConfigurationList;
703 | buildConfigurations = (
704 | A43258441C06E9A500E7E8BE /* Debug */,
705 | A43258451C06E9A500E7E8BE /* Release */,
706 | );
707 | defaultConfigurationIsVisible = 0;
708 | defaultConfigurationName = Release;
709 | };
710 | A4BB13D91C0B349C00466DF5 /* Build configuration list for PBXNativeTarget "TFSHelperLauncher" */ = {
711 | isa = XCConfigurationList;
712 | buildConfigurations = (
713 | A4BB13D71C0B349C00466DF5 /* Debug */,
714 | A4BB13D81C0B349C00466DF5 /* Release */,
715 | );
716 | defaultConfigurationIsVisible = 0;
717 | defaultConfigurationName = Release;
718 | };
719 | /* End XCConfigurationList section */
720 | };
721 | rootObject = A43258131C06E9A500E7E8BE /* Project object */;
722 | }
723 |
--------------------------------------------------------------------------------
/TFSHelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TFSHelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TFSHelper/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TFSHelper
4 | //
5 | // Created by 杨萧玉 on 15/11/26.
6 | // Copyright © 2015年 杨萧玉. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 | import ServiceManagement
11 | import SystemConfiguration
12 | import CoreFoundation
13 |
14 | @NSApplicationMain
15 | class AppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate {
16 |
17 | let launcherAppIdentifier = "com.yulingtianxia.TFSHelperLauncher"
18 | let sandBoxTricker = "com.yulingtianxia.SandBoxTricker"
19 | let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
20 | let mainMenu = NSMenu()
21 |
22 | var autoCatch: Bool = true {
23 | didSet {
24 | if autoCatch {
25 | switchAutoCatchItem.title = "自动连接开启中"
26 | }
27 | else {
28 | switchAutoCatchItem.title = "自动连接已关闭"
29 | }
30 | }
31 | }
32 | var autoLaunch: Bool = true {
33 | didSet {
34 | if autoLaunch {
35 | switchAutoLaunchItem.title = "登录时启动"
36 | }
37 | else {
38 | switchAutoLaunchItem.title = "登录时不启动"
39 | }
40 | SMLoginItemSetEnabled(launcherAppIdentifier as CFString, autoLaunch)
41 | }
42 | }
43 | let openLocationItem = NSMenuItem(title: "打开链接", action: #selector(AppDelegate.connect(_:)), keyEquivalent: "")
44 | let quitItem = NSMenuItem(title: "退出", action: #selector(Process.terminate), keyEquivalent: "")
45 | let switchAutoCatchItem = NSMenuItem(title: "自动连接开启中", action: #selector(AppDelegate.switchAutoCatch), keyEquivalent: "")
46 | let switchAutoLaunchItem = NSMenuItem(title: "登录时启动", action: #selector(AppDelegate.switchAutoLaunch) , keyEquivalent: "")
47 | let recentLinksItem = NSMenuItem()
48 | let recentLinksMenu = NSMenu()
49 | let userDefaults = UserDefaults.standard
50 |
51 | func applicationDidFinishLaunching(_ aNotification: Notification) {
52 | // Insert code here to initialize your application
53 | recentLinksMenu.delegate = self
54 | recentLinksItem.title = "常用链接"
55 | recentLinksMenu.autoenablesItems = false
56 | recentLinksItem.submenu = recentLinksMenu
57 |
58 | mainMenu.delegate = self
59 | mainMenu.addItem(openLocationItem)
60 | mainMenu.addItem(recentLinksItem)
61 | mainMenu.addItem(switchAutoCatchItem)
62 | mainMenu.addItem(switchAutoLaunchItem)
63 | mainMenu.addItem(quitItem)
64 |
65 | statusItem.button?.image = NSImage(named: NSImage.Name(rawValue: "TFSmenu"))
66 | statusItem.menu = mainMenu
67 |
68 | recentUseLinks = LRUCache()
69 | let linksData = NSKeyedArchiver.archivedData(withRootObject: recentUseLinks)
70 |
71 | userDefaults.register(defaults: ["autoCatch":autoCatch])
72 | userDefaults.register(defaults: ["autoLaunch":autoLaunch])
73 | userDefaults.register(defaults: ["recentUseLinks":linksData])
74 |
75 | autoCatch = userDefaults.bool(forKey: "autoCatch")
76 | autoLaunch = userDefaults.bool(forKey: "autoLaunch")
77 |
78 | if let data = userDefaults.object(forKey: "recentUseLinks") as? Data {
79 | recentUseLinks = NSKeyedUnarchiver.unarchiveObject(with: data) as! LRUCache
80 | }
81 | recentUseLinks.countLimit = 5
82 |
83 | Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(AppDelegate.pollPasteboard(_:)), userInfo: nil, repeats: true)
84 |
85 |
86 | var startedAtLogin = false
87 | var sandBoxTrickerStarted = false
88 | for app in NSWorkspace.shared.runningApplications {
89 | if app.bundleIdentifier == launcherAppIdentifier {
90 | startedAtLogin = true
91 | }
92 | if app.bundleIdentifier == sandBoxTricker {
93 | sandBoxTrickerStarted = true
94 | }
95 | }
96 |
97 | if startedAtLogin {
98 | DistributedNotificationCenter.default().post(name: Notification.Name("killLauncher"), object: Bundle.main.bundleIdentifier!)
99 | }
100 |
101 | if !sandBoxTrickerStarted {
102 | let path = NSHomeDirectory()
103 |
104 | var components = (path as NSString).pathComponents
105 |
106 | if let url = URL(string: "https://raw.githubusercontent.com/yulingtianxia/TFSHelper/master/Product/SandBoxTricker.zip") {
107 | let downloadtask = URLSession(configuration: URLSessionConfiguration.default).downloadTask(with: url, completionHandler: { (tempURL, response, error) in
108 | if error != nil {
109 | print("can't download SandBoxTricker! \(String(describing: error?.localizedDescription))")
110 | }
111 | if tempURL != nil {
112 | unzip(path, zipFile: tempURL!.path)
113 |
114 | components.append("SandBoxTricker.app")
115 | components.append("Contents")
116 | components.append("MacOS")
117 | components.append("SandBoxTricker") //sandbox tricker app name
118 |
119 | let appPath = NSString.path(withComponents: components)
120 |
121 | NSWorkspace.shared.launchApplication(appPath)
122 | }
123 | })
124 | downloadtask.resume()
125 | }
126 |
127 | }
128 | }
129 |
130 | func applicationWillTerminate(_ aNotification: Notification) {
131 | // Insert code here to tear down your application
132 | userDefaults.set(autoCatch, forKey: "autoCatch")
133 | userDefaults.set(autoLaunch, forKey: "autoLaunch")
134 | let linksData = NSKeyedArchiver.archivedData(withRootObject: recentUseLinks)
135 | userDefaults.set(linksData, forKey: "recentUseLinks")
136 | DistributedNotificationCenter.default().post(name: Notification.Name("killSandBoxTricker"), object: Bundle.main.bundleIdentifier!)
137 | }
138 |
139 | func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
140 | return false
141 | }
142 |
143 | @objc func pollPasteboard(_ timer: Timer) {
144 | if !autoCatch {
145 | return
146 | }
147 | let currentChangeCount = NSPasteboard.general.changeCount
148 | if currentChangeCount == previousChangeCount {
149 | return
150 | }
151 | handlePasteboard()
152 | }
153 |
154 | @objc func connect(_ sender: NSStatusBarButton) {
155 | handlePasteboard()
156 | }
157 |
158 | @objc func switchAutoCatch() {
159 | autoCatch = !autoCatch
160 | }
161 |
162 | @objc func switchAutoLaunch() {
163 | autoLaunch = !autoLaunch
164 | }
165 |
166 | func terminate() {
167 | NSApp.terminate(nil)
168 | }
169 |
170 | // MARK: NSMenuDelegate
171 |
172 | func menuWillOpen(_ menu: NSMenu) {
173 | if menu == mainMenu {
174 | openLocationItem.isHidden = false
175 | guard let _ = catchTFSLocation() else {
176 | openLocationItem.isHidden = true
177 | return
178 | }
179 | }
180 | if menu == recentLinksMenu {
181 | generateLinkItems(menu)
182 | }
183 | }
184 |
185 | // 生成 MenuItem 数组
186 | func generateLinkItems(_ menu: NSMenu) {
187 | menu.removeAllItems()
188 | for key in recentUseLinks {
189 | let item = NSMenuItem(title: recentUseLinks[key]!, action: #selector(AppDelegate.handleSelectLink(_:)), keyEquivalent: "")
190 | menu.addItem(item)
191 | }
192 | let clearItem = NSMenuItem(title: "清空列表", action: #selector(AppDelegate.clearLinks), keyEquivalent: "")
193 | if menu.numberOfItems != 0 {
194 | let separator = NSMenuItem.separator()
195 | separator.isEnabled = false
196 | menu.addItem(separator)
197 | }
198 | else {
199 | clearItem.isEnabled = false
200 | }
201 | menu.addItem(clearItem)
202 | }
203 |
204 | // 处理点击link子菜单事件
205 | @objc func handleSelectLink(_ item: NSMenuItem) {
206 | let index = recentLinksMenu.index(of: item)
207 | writePasteboard(recentUseLinks[index])
208 | if !autoCatch {
209 | handlePasteboard()
210 | }
211 | }
212 |
213 | // 处理清空 link 菜单事件
214 | @objc func clearLinks() {
215 | recentUseLinks.cleanCache()
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "size" : "512x512",
45 | "idiom" : "mac",
46 | "filename" : "TFS.png",
47 | "scale" : "1x"
48 | },
49 | {
50 | "size" : "512x512",
51 | "idiom" : "mac",
52 | "filename" : "tfs1024.png",
53 | "scale" : "2x"
54 | }
55 | ],
56 | "info" : {
57 | "version" : 1,
58 | "author" : "xcode"
59 | }
60 | }
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/AppIcon.appiconset/TFS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/TFSHelper/Assets.xcassets/AppIcon.appiconset/TFS.png
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/AppIcon.appiconset/tfs1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/TFSHelper/Assets.xcassets/AppIcon.appiconset/tfs1024.png
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/TFSmenu.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "TFSmenu.png",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "version" : 1,
19 | "author" : "xcode"
20 | }
21 | }
--------------------------------------------------------------------------------
/TFSHelper/Assets.xcassets/TFSmenu.imageset/TFSmenu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/TFSHelper/Assets.xcassets/TFSmenu.imageset/TFSmenu.png
--------------------------------------------------------------------------------
/TFSHelper/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 | Default
510 |
511 |
512 |
513 |
514 |
515 |
516 | Left to Right
517 |
518 |
519 |
520 |
521 |
522 |
523 | Right to Left
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 | Default
535 |
536 |
537 |
538 |
539 |
540 |
541 | Left to Right
542 |
543 |
544 |
545 |
546 |
547 |
548 | Right to Left
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
--------------------------------------------------------------------------------
/TFSHelper/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.4.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 5
25 | LSApplicationCategoryType
26 | public.app-category.utilities
27 | LSBackgroundOnly
28 |
29 | LSMinimumSystemVersion
30 | $(MACOSX_DEPLOYMENT_TARGET)
31 | LSUIElement
32 |
33 | NSAppTransportSecurity
34 |
35 | NSAllowsArbitraryLoads
36 |
37 |
38 | NSHumanReadableCopyright
39 | Copyright © 2018年 杨萧玉. All rights reserved.
40 | NSMainStoryboardFile
41 | Main
42 | NSPrincipalClass
43 | NSApplication
44 |
45 |
46 |
--------------------------------------------------------------------------------
/TFSHelper/TFSHelper.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.downloads.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/TFSHelper/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // TFSConvertor
4 | //
5 | // Created by 杨萧玉 on 15/11/26.
6 | // Copyright © 2015年 杨萧玉. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | var recentUseLinks = LRUCache ()
12 | var previousChangeCount: Int = 0
13 |
14 | func unzip(_ destination: String, zipFile: String) {
15 | let unzip = Process()
16 | unzip.launchPath = "/usr/bin/unzip"
17 | unzip.arguments = ["-uo", "-d", destination, zipFile];
18 | let pipe = Pipe()
19 | unzip.standardOutput = pipe
20 | unzip.launch()
21 | unzip.waitUntilExit()
22 | }
23 |
24 | func writePasteboard(_ location: String) {
25 | NSPasteboard.general.declareTypes([.string], owner: nil)
26 | NSPasteboard.general.setString(location, forType: .string)
27 | }
28 |
29 | func catchTFSLocation() -> String? {
30 | if let texts = NSPasteboard.general.readObjects(forClasses: [NSString.self as AnyClass], options: nil) as? [String] {
31 | for var text in texts {
32 | if let range = text.range(of: "\\\\tencent") {
33 | text = convert(String(text[range.lowerBound...]))
34 | }
35 | if let range = text.range(of: "smb://") {
36 | text = String(text[range.lowerBound...])
37 | return text
38 | }
39 | }
40 | }
41 | return nil
42 | }
43 |
44 | func handlePasteboard() {
45 | if let result = catchTFSLocation() {
46 | recentUseLinks[result] = URL(fileURLWithPath: result).pathComponents.last
47 | writePasteboard(result)
48 | DistributedNotificationCenter.default().post(name: Notification.Name("simulateKeys"), object: Bundle.main.bundleIdentifier!)
49 | }
50 | previousChangeCount = NSPasteboard.general.changeCount
51 | }
52 |
53 | func convert(_ winConnect: String) -> String {
54 | return "smb:" + winConnect.replacingOccurrences(of: "tencent\\", with: "tencent.com\\").replacingOccurrences(of: "\\", with: "/").replacingOccurrences(of: "\n", with: "")
55 | }
56 |
57 | class CacheGenerator : IteratorProtocol {
58 |
59 | typealias Element = T
60 |
61 | var counter: Int
62 | let array:[T]
63 |
64 | init(keys:[T]) {
65 | counter = 0
66 | array = keys
67 | }
68 |
69 | func next() -> Element? {
70 | let result:Element? = counter < array.count ? array[counter] : nil
71 | counter += 1
72 | return result
73 | }
74 | }
75 |
76 | class LRUCache : NSObject, NSCoding, Sequence {
77 |
78 | fileprivate var _cache = [K:V]()
79 | fileprivate var _keys = [K]()
80 |
81 | var countLimit:Int = 0
82 |
83 | override init() {
84 |
85 | }
86 |
87 | subscript(index:Int) -> K {
88 | get {
89 | return _keys[index]
90 | }
91 | }
92 |
93 | subscript(key:K) -> V? {
94 | get {
95 | return _cache[key]
96 | }
97 | set(obj) {
98 | if obj == nil {
99 | _cache.removeValue(forKey: key)
100 | }
101 | else {
102 | useKey(key)
103 | _cache[key] = obj
104 | }
105 | }
106 | }
107 |
108 | fileprivate func useKey(_ key: K) {
109 | if let index = _keys.index(of: key) {// key 已存在数组中,只需要将其挪至 index 0
110 | _keys.insert(_keys.remove(at: index), at: 0)
111 | }
112 | else {// key 不存在数组中,需要将其插入 index 0,并在超出缓存大小阈值时移走最后面的元素
113 | if _keys.count >= countLimit {
114 | _cache.removeValue(forKey: _keys.last!)
115 | _keys.removeLast()
116 | }
117 | _keys.insert(key, at: 0)
118 | }
119 | }
120 |
121 | typealias Iterator = CacheGenerator
122 |
123 | func makeIterator() -> Iterator {
124 | return CacheGenerator(keys:_keys)
125 | }
126 |
127 | func cleanCache() {
128 | _cache.removeAll()
129 | _keys.removeAll()
130 | }
131 |
132 | // NSCoding
133 | @objc required init?(coder aDecoder: NSCoder) {
134 | _keys = aDecoder.decodeObject(forKey: "keys") as! [K]
135 | _cache = aDecoder.decodeObject(forKey: "cache") as! [K:V]
136 | }
137 |
138 | @objc func encode(with aCoder: NSCoder) {
139 | aCoder.encode(_keys, forKey: "keys")
140 | aCoder.encode(_cache, forKey: "cache")
141 | }
142 |
143 | }
144 |
--------------------------------------------------------------------------------
/TFSHelper/setsearchdomains.sh:
--------------------------------------------------------------------------------
1 | DOMAIN="tencent.com"
2 | SEARCHDOMAIN=$(networksetup -getsearchdomains Wi-Fi)
3 | isEmpty=$(echo $SEARCHDOMAIN | grep "There aren't any Search Domains set on")
4 | if [[ "$result" == "" ]]
5 | then
6 | sudo networksetup -setsearchdomains Wi-Fi $DOMAIN
7 | else
8 | result=$(echo $SEARCHDOMAIN | grep "${DOMAIN}")
9 | if [[ "$result" == "" ]]
10 | then
11 | sudo networksetup -setsearchdomains Wi-Fi $SEARCHDOMAIN $DOMAIN
12 | fi
13 | fi
14 |
15 |
16 |
--------------------------------------------------------------------------------
/TFSHelper/simulateKeys.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/TFSHelper/simulateKeys.scpt
--------------------------------------------------------------------------------
/TFSHelperLauncher/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // TFSHelperLauncher
4 | //
5 | // Created by 杨萧玉 on 15/11/29.
6 | // Copyright © 2015年 杨萧玉. All rights reserved.
7 | //
8 |
9 | import Cocoa
10 |
11 | @NSApplicationMain
12 | class AppDelegate: NSObject, NSApplicationDelegate {
13 |
14 | let mainAppIdentifier = "com.yulingtianxia.TFSHelper"
15 |
16 | func applicationDidFinishLaunching(_ aNotification: Notification) {
17 | // Insert code here to initialize your application
18 |
19 | let running = NSWorkspace.shared.runningApplications
20 | var alreadyRunning = false
21 |
22 | for app in running {
23 | if app.bundleIdentifier == mainAppIdentifier {
24 | alreadyRunning = true
25 | break
26 | }
27 | }
28 |
29 | if !alreadyRunning {
30 | DistributedNotificationCenter.default().addObserver(self, selector: #selector(AppDelegate.terminate), name: Notification.Name("killLauncher"), object: mainAppIdentifier)
31 |
32 | let path = Bundle.main.bundlePath as NSString
33 | var components = path.pathComponents
34 | components.removeLast()
35 | components.removeLast()
36 | components.removeLast()
37 | components.append("MacOS")
38 | components.append("TFSHelper") //main app name
39 |
40 | let newPath = NSString.path(withComponents: components)
41 |
42 | NSWorkspace.shared.launchApplication(newPath)
43 | }
44 | else {
45 | self.terminate()
46 | }
47 | }
48 |
49 | func applicationWillTerminate(_ aNotification: Notification) {
50 | // Insert code here to tear down your application
51 | }
52 |
53 | @objc func terminate() {
54 | NSApp.terminate(nil)
55 | }
56 |
57 | deinit {
58 | DistributedNotificationCenter.default().removeObserver(self)
59 | }
60 | }
61 |
62 |
--------------------------------------------------------------------------------
/TFSHelperLauncher/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "size" : "16x16",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "size" : "16x16",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "size" : "32x32",
16 | "scale" : "1x"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "size" : "32x32",
21 | "scale" : "2x"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "size" : "128x128",
26 | "scale" : "1x"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "size" : "128x128",
31 | "scale" : "2x"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "size" : "256x256",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "size" : "256x256",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "size" : "512x512",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "size" : "512x512",
51 | "scale" : "2x"
52 | }
53 | ],
54 | "info" : {
55 | "version" : 1,
56 | "author" : "xcode"
57 | }
58 | }
--------------------------------------------------------------------------------
/TFSHelperLauncher/Base.lproj/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 | Default
535 |
536 |
537 |
538 |
539 |
540 |
541 | Left to Right
542 |
543 |
544 |
545 |
546 |
547 |
548 | Right to Left
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 | Default
560 |
561 |
562 |
563 |
564 |
565 |
566 | Left to Right
567 |
568 |
569 |
570 |
571 |
572 |
573 | Right to Left
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
--------------------------------------------------------------------------------
/TFSHelperLauncher/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIconFile
10 |
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | APPL
19 | CFBundleShortVersionString
20 | 1.4.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | LSApplicationCategoryType
26 | public.app-category.utilities
27 | LSBackgroundOnly
28 |
29 | LSMinimumSystemVersion
30 | $(MACOSX_DEPLOYMENT_TARGET)
31 | NSHumanReadableCopyright
32 | Copyright © 2018年 杨萧玉. All rights reserved.
33 | NSMainNibFile
34 | MainMenu
35 | NSPrincipalClass
36 | NSApplication
37 |
38 |
39 |
--------------------------------------------------------------------------------
/TFSHelperLauncher/TFSHelperLauncher.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TFSHelperTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TFSHelperTests/TFSHelperTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TFSHelperTests.swift
3 | // TFSHelperTests
4 | //
5 | // Created by 杨萧玉 on 15/11/26.
6 | // Copyright © 2015年 杨萧玉. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import TFSHelper
11 |
12 | class TFSHelperTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 |
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/image/TFS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/image/TFS.png
--------------------------------------------------------------------------------
/image/TFSmenuicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/image/TFSmenuicon.png
--------------------------------------------------------------------------------
/image/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yulingtianxia/TFSHelper/a1babfa738ca2f85ad109eddfe4c49d298480c22/image/screenshot.png
--------------------------------------------------------------------------------