├── App
├── main.tiff
├── appstore.png
├── playstore.png
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ ├── 128.png
│ │ ├── 16.png
│ │ ├── 256.png
│ │ ├── 32.png
│ │ ├── 512.png
│ │ ├── 64.png
│ │ ├── 1024.png
│ │ └── Contents.json
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
├── UI
│ ├── ReadSize.swift
│ ├── Toast.swift
│ └── ContentView.swift
├── main.swift
├── MainMenu.xib
├── DataBaseClient.swift
└── AnInputController.swift
├── README
├── 1.png
├── 2.png
└── 3.png
├── .gitignore
├── Tests
├── Info.plist
└── Tests.swift
├── ihelper.entitlements
├── ihelper.xcodeproj
├── project.xcworkspace
│ ├── xcuserdata
│ │ └── admin.xcuserdatad
│ │ │ ├── UserInterfaceState.xcuserstate
│ │ │ └── WorkspaceSettings.xcsettings
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── admin.xcuserdatad
│ │ ├── xcschemes
│ │ └── xcschememanagement.plist
│ │ └── xcdebugger
│ │ └── Breakpoints_v2.xcbkptlist
└── project.pbxproj
├── makedmg.sh
├── Info.plist
└── README.md
/App/main.tiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/main.tiff
--------------------------------------------------------------------------------
/README/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/README/1.png
--------------------------------------------------------------------------------
/README/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/README/2.png
--------------------------------------------------------------------------------
/README/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/README/3.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .DS_Store?
3 | ./build
4 | ihelper.app
5 | ihelper.dmg
6 |
--------------------------------------------------------------------------------
/App/appstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/appstore.png
--------------------------------------------------------------------------------
/App/playstore.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/playstore.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/128.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/16.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/256.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/32.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/512.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/64.png
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/App/Assets.xcassets/AppIcon.appiconset/1024.png
--------------------------------------------------------------------------------
/App/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ihelper.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/fumeboy/ihelper/HEAD/ihelper.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/makedmg.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # brew install create-dmg
3 | test -f ihelper.dmg && rm ihelper.dmg
4 | create-dmg \
5 | --volname "ihelper" \
6 | --window-pos 200 120 \
7 | --window-size 800 400 \
8 | "ihelper.dmg" \
9 | "./build/"
10 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/project.xcworkspace/xcuserdata/admin.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseTargetSettings
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/xcuserdata/admin.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | aaaa.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 | ihelper.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 0
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/App/UI/ReadSize.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct SizePreferenceKey: PreferenceKey {
4 | static var defaultValue: CGSize = .zero
5 | static func reduce(value: inout CGSize, nextValue: () -> CGSize) {}
6 | }
7 |
8 | extension View {
9 | func readSize(onChange: @escaping (CGSize) -> Void) -> some View {
10 | background(
11 | GeometryReader { geometryProxy in
12 | Color.clear
13 | .preference(key: SizePreferenceKey.self, value: geometryProxy.size)
14 | }
15 | )
16 | .onPreferenceChange(SizePreferenceKey.self, perform: onChange)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/App/main.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Cocoa
3 | import SwiftUI
4 | import InputMethodKit
5 |
6 | class AppDelegate: NSObject, NSApplicationDelegate {
7 | var server: IMKServer!
8 |
9 | func applicationDidFinishLaunching(_ aNotification: Notification) {
10 | server = IMKServer(
11 | name: "iHelper_1_Connection", bundleIdentifier: Bundle.main.bundleIdentifier)
12 | NSLog("start")
13 | }
14 |
15 | func applicationWillTerminate(_ aNotification: Notification) {
16 | }
17 |
18 | }
19 |
20 | let app = NSApplication.shared
21 | let d = AppDelegate()
22 | app.delegate = d
23 | _ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
24 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/xcuserdata/admin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
9 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/App/MainMenu.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Tests/Tests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // aaaaTests.swift
3 | // aaaaTests
4 | //
5 | // Created by admin on 2022/5/31.
6 | //
7 |
8 | import XCTest
9 | @testable import ihelper
10 |
11 | class Tests: XCTestCase {
12 |
13 | func testCSV() throws {
14 | guard let spans = parseCSVline("a,v,c,")else {throw ""}
15 | guard spans.3 else {throw ""}
16 | guard let spans = parseCSVline("a,v,c") else {throw ""}
17 | guard spans.3 else {throw ""}
18 | guard let spans = parseCSVline("a,v,c,d") else {throw ""}
19 | guard spans.3 == false else {throw ""}
20 | guard let spans = parseCSVline(#"a,v,c,",d""#) else {throw ""}
21 | guard spans.2 == ",d" else {throw spans.2}
22 | guard let spans = parseCSVline(#"a,v,c,",""d""#) else {throw ""}
23 | guard spans.2 == #","d"# else {throw spans.2}
24 | guard let spans = parseCSVline(#"a,v,c,",""""""d""#) else {throw ""}
25 | guard spans.2 == #","""d"# else {throw spans.2}
26 | guard let spans = parseCSVline(#"a,v,c,","""""",d""#) else {throw ""}
27 | guard spans.2 == #",""",d"# else {throw spans.2}
28 |
29 | print(parseCSVline(""))
30 |
31 | }
32 |
33 | }
34 |
35 |
--------------------------------------------------------------------------------
/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {"images":[{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]}
--------------------------------------------------------------------------------
/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.0
21 | CFBundleVersion
22 | 1
23 | InputMethodConnectionName
24 | iHelper_1_Connection
25 | InputMethodServerControllerClass
26 | $(PRODUCT_MODULE_NAME).AnInputController
27 | InputMethodServerDelegateClass
28 | $(PRODUCT_MODULE_NAME).AnInputController
29 | LSApplicationCategoryType
30 | public.app-category.utilities
31 | LSBackgroundOnly
32 |
33 | LSMinimumSystemVersion
34 | 10.9
35 | LSUIElement
36 |
37 | NSMainNibFile
38 | MainMenu
39 | NSPrincipalClass
40 | NSApplication
41 | TISInputSourceID
42 | fumeboy.inputmethod.ihelper
43 | TISIntendedLanguage
44 | zh-Hans
45 | tsInputMethodCharacterRepertoireKey
46 |
47 | Hans
48 | Latn
49 |
50 | tsInputMethodIconFileKey
51 | main.tiff
52 |
53 |
54 |
--------------------------------------------------------------------------------
/App/UI/Toast.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import SwiftUI
3 |
4 | class ToastWindow: NSWindow {
5 | struct ToastView: View {
6 | var text: String
7 | var body: some View {
8 | VStack {
9 | Text(text)
10 | .font(.system(size: 50))
11 | .foregroundColor(.white)
12 | }
13 | .fixedSize()
14 | .padding(20)
15 | .background(Color.black.opacity(0.5))
16 | .clipped()
17 | .cornerRadius(20)
18 | }
19 | }
20 |
21 | struct ToastView_Previews: PreviewProvider {
22 | static var previews: some View {
23 | ToastView(text: "banning mode")
24 | }
25 | }
26 |
27 | private var timer: Timer?
28 |
29 | private let hostingView = NSHostingView(rootView: ToastView(text: "normal mode"))
30 | override var acceptsFirstResponder: Bool {
31 | return false
32 | }
33 |
34 | private func initWindow() {
35 | isOpaque = false
36 | backgroundColor = NSColor.clear
37 | styleMask = .init(arrayLiteral: .borderless, .fullSizeContentView)
38 | hasShadow = false
39 | ignoresMouseEvents = true
40 | isReleasedWhenClosed = false
41 | level = NSWindow.Level(rawValue: NSWindow.Level.RawValue(CGShieldingWindowLevel()))
42 | }
43 | override init(
44 | contentRect: NSRect,
45 | styleMask style: NSWindow.StyleMask,
46 | backing backingStoreType: NSWindow.BackingStoreType,
47 | defer flag: Bool
48 | ) {
49 | super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag)
50 | initWindow()
51 | contentView = hostingView
52 | }
53 |
54 | private func positionWindow() {
55 | guard let screen = getScreenFromPoint(NSEvent.mouseLocation) else {
56 | return
57 | }
58 | let cx = (screen.frame.minX + screen.frame.maxX) / 2 - frame.width / 2
59 | let cy = (screen.frame.maxY - screen.frame.minY) / 5 + screen.frame.minY
60 | self.setFrameOrigin(NSPoint(x: cx, y: cy))
61 | }
62 |
63 | func show(_ text: String) {
64 | timer?.invalidate()
65 | hostingView.rootView.text = text
66 | positionWindow()
67 | orderFront(nil)
68 | timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: false, block: { (_) in
69 | self.close()
70 | })
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NOTE: ihelper -> ihelper-raycast
2 |
3 | 我决定给 raycast(一个类似于 Alfred 的软件) 写插件来实现之前开发输入法所实现的功能。这个项目后面可能不再更新。
4 |
5 | 插件已经写好在这里 https://github.com/fumeboy/ihelper-raycast
6 |
7 | (但我又发现 raycast 限制了 UI 的表达,所以这个项目可能还会更新)
8 |
9 | # ihelper
10 |
11 | 效率工具;辅助记忆;快速输入;
12 |
13 | 
14 |
15 | 
16 |
17 | ## 功能简介
18 |
19 | 用户可以自定义字典在 CSV 文件 `~/.ihelper.csv`;字典行记录 .tag、.desc、.output、.output-type 四项
20 |
21 | 启用 ihelper 输入法,输入能匹配 .tag 的文本查找出匹配的字典行;使用方向键选择要输出一项;敲回车键输出 output 文本或执行对应的 hotkey
22 |
23 | ## 场景举例
24 |
25 | 比如因为我不熟悉 vim 的操作,于是配置了 `vim;cursor;,光标移动到非空格符的下一行,+,` 这一行到字典文件
26 |
27 | 使用时,首先启用输入法并输入 `v` 匹配到 .tag `vim`, 然后选择该行并回车,输入法将输出 .output `+`, vim 窗口接收到 `+`, 执行 “光标移动到非空格符的下一行”
28 |
29 | ## 使用细节
30 |
31 | ### 初始化
32 |
33 | 1. 编译得到的 app 文件放置在 `/Library/Input Methods` 目录
34 |
35 | 2. 字典文件放置在 `~/.ihelper.csv` (第一次使用可以复制本仓库的 `.ihelper.csv`)
36 |
37 | 3. 在系统设置中启用输入法;*需要注意,系统需要重启(或注销重新登陆)才会加载新输入法*
38 |
39 | ### 字典格式
40 |
41 | 每一行为一个字典项,按顺序依次是 tag、desc、output、output-type 四列;
42 |
43 | #### tag
44 |
45 | tag 作为索引项使用,允许多值,按照符号 ; 分割
46 |
47 | #### desc
48 |
49 | 描述该字典行的 text 或 hotkey;无格式要求
50 |
51 | #### output
52 |
53 | 当 output-type == 1 时,输出 output 原文本
54 |
55 | 当 output-type == 2 时,`ctrl+C` 这样的 hotkey 会被执行
56 |
57 | hotkey 格式为 `+` 或 ``
58 |
59 | 其中 `` 的内容可以是:`[shift,ctrl,control,command,cmd,option]` 中的一项
60 |
61 | 其中 `key` 的内容格式请见源文件 `AnInputController.swift` 中的 `keycode`
62 |
63 | ### 按键功能
64 |
65 | ascii(32~126) 对应的按键输入字符
66 |
67 | `space`、`tab`、`enter` 确认输入并输出
68 |
69 | `esc` 清空输入、切换输入模式
70 |
71 | `del` 删除末尾字符
72 |
73 | `arrow up`、`arrow down` 选择输出项
74 |
75 | `arrow left`、 `arrow right` 切页
76 |
77 | ### 输入模式
78 |
79 | 输入模式分为 normal mode 和 banning mode
80 |
81 | normal mode 下输入文本索引 origin,会进行字典查询;也可以直接输出 origin
82 |
83 | banning mode 下输入纯文本,输入法不进行响应;目的是省略切换英文输入法
84 |
85 | *需要注意,在 normal node 下直接输出 origin 时,会自动切换到 banning mode*
86 |
87 | ### 控制模式
88 |
89 | 连续按两次 `esc` 进入控制模式。控制模式下:
90 |
91 | 按 `w` 键打开 `~/.ihelper.csv` 编辑窗口
92 |
93 | 按 `s` 键读取 `~/.ihelper.csv`
94 |
95 | ## 常见问题
96 |
97 | 1. 切换到该输入法但是输入无响应 -> 到 Input Methods 文件夹手动启动 app,应该会弹出系统报错信息;一般是系统版本不匹配
98 | 2. 系统设置里找不到或者无法切换到该输入法 -> 可能是没有注销重新登录,系统未加载该输入法
99 | 3. 怎么判断系统有无加载输入法 -> 查看是否有 ihelper 进程,如果有就是已经加载
100 | 4. hotkey 不生效 -> 输出 hotkey 时,系统会告诉你需要在 “安全性与隐私-辅助功能” 里为 ihelper 添加权限;如果重新安装了输入法,需要删除原权限,注销重新登录后再添加权限
101 | 5. 字典行未加载 -> 检查格式是否正确,特殊符号需要满足 csv 转义规则
102 |
103 |
104 |
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/App/DataBaseClient.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | var configCandidateNum: Int = 10;
4 | let dict_filename = ".ihelper.csv"
5 |
6 | struct Candidate: Hashable {
7 | let tag: String
8 | let desc: String
9 | let output: String
10 | let iftext: Bool
11 | let id: Int
12 | }
13 |
14 | class DataBaseClient{
15 | static let shared = DataBaseClient()
16 |
17 | var filecontent: [(String,String,String,Bool)]!
18 |
19 | func getCandidates(origin: String = String()) -> [Candidate] {
20 | let keywords = origin.components(separatedBy: ";")
21 | var reexp = ""
22 | for (i,k) in keywords.enumerated() {
23 | // (?=.*key1).*;(?=.*key2).*;(?=.*key3)
24 | reexp += "(?=.*"+NSRegularExpression.escapedPattern(for: k)+")"
25 | if i != keywords.count-1 {
26 | reexp += ".*;"
27 | }
28 | }
29 | let RE = try! NSRegularExpression(pattern: reexp, options: .caseInsensitive)
30 | var candidates:[Candidate] = []
31 | for (index,item) in filecontent.enumerated() {
32 | if RE.firstMatch(in: item.0, range: NSRange(location:0,length:item.0.count)) != nil {
33 | candidates.append(Candidate(tag: item.0, desc: item.1, output: item.2, iftext: item.3, id:index))
34 | }
35 | }
36 |
37 | return candidates
38 | }
39 |
40 | func loadDict(){ // parse .csv
41 | let path = NSHomeDirectory()+"/" + dict_filename
42 | if !FileManager.default.fileExists(atPath:path) {
43 | FileManager.default.createFile(atPath: path, contents: nil, attributes: nil)
44 | }
45 | let text = try! String(contentsOfFile:path, encoding: String.Encoding.utf8)
46 | let lines = text.split{ [Character("\n"), Character("\r"), Character("\r\n")].contains($0) }
47 | var kvs = [(String,String,String,Bool)]()
48 | for l in lines{
49 | if let s = parseCSVline(String(l)) { kvs.append(s)}
50 | }
51 | filecontent = kvs
52 | }
53 |
54 | init() {
55 | loadDict()
56 | }
57 | }
58 |
59 | func parseCSVline(_ l: String) -> (String,String,String,Bool)?{
60 | var spans = ["","","",""]
61 | var spanIndex = 0
62 | var openclose = false
63 | for char in l.appending(",") {
64 | switch char {
65 | case "\"":
66 | if openclose == false {
67 | openclose = true
68 | }else{
69 | openclose = false
70 | spans[spanIndex] += "\""
71 | }
72 | case ",":
73 | if openclose == false {
74 | if spans[spanIndex].last == "\""{
75 | spans[spanIndex].remove(at: spans[spanIndex].index(before: spans[spanIndex].endIndex))
76 | }
77 | if spanIndex == 3 {
78 | break
79 | }
80 | spanIndex+=1
81 | }else{
82 | spans[spanIndex] += ","
83 | }
84 | default:
85 | spans[spanIndex] += String(char)
86 | }
87 | }
88 |
89 | if spans[1].count == 0 {
90 | return nil
91 | }
92 | if spans[3] == "2" {
93 | return ((spans[0],spans[1],spans[2],false))
94 | } else {
95 | return ((spans[0],spans[1],spans[2],true))
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/App/UI/ContentView.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | let w :CGFloat = 400
4 | let color1 = Color(red:255,green:255,blue:255,opacity:0.9)
5 | let color2 = Color(red:255,green:255,blue:255,opacity:0.7)
6 | let itemselectedbg = Color.purple.opacity(0.3)
7 | let tagtextcolor = Color(red:194/255,green:194/255,blue:240/255)
8 | let itemHeight: CGFloat = 34
9 | let horizontalmargin: CGFloat = 10
10 | let itemIftextIconWidth: CGFloat = 30
11 |
12 | struct TruncableItem: View {
13 | let candidate: Candidate
14 | let ifselected: Bool
15 |
16 | @State private var intrinsicSize: CGSize = .zero
17 | @State private var truncatedSize: CGSize = .zero
18 | @State private var isTruncated: Bool = false
19 | var body: some View {
20 | let bg = ifselected ? itemselectedbg : Color.clear
21 | Group{
22 | if isTruncated && ifselected {
23 | ScrollView{
24 | VStack(alignment: .leading, spacing: 5) {
25 | Text(candidate.desc).foregroundColor(color1).fixedSize(horizontal: false, vertical: true)
26 | Text(candidate.tag).foregroundColor(tagtextcolor)
27 | Text(candidate.output).foregroundColor(color2).font(.system(size: CGFloat(15)))
28 | }.frame(maxWidth:w-horizontalmargin*2, alignment: .leading)
29 | }
30 | .padding(5)
31 | .padding(.leading,5)
32 | .padding(.trailing,5)
33 | .frame(width:w-horizontalmargin*2, alignment: .leading)
34 | .fixedSize()
35 | }else{
36 | HStack(alignment:.center,spacing: 0){
37 | HStack(alignment:.firstTextBaseline){
38 | Text("\(candidate.desc)")
39 | .foregroundColor(color1)
40 | .frame(maxWidth: w - itemIftextIconWidth - horizontalmargin*2 - 1, alignment: .leading)
41 | .fixedSize()
42 |
43 | Text(":: "+candidate.tag).foregroundColor(tagtextcolor)
44 | .padding(2).padding(.leading,3).padding(.trailing,3)
45 | .background(Color(red:63/255,green:62/255,blue:61/255,opacity: 0.9))
46 |
47 | Text(candidate.output).foregroundColor(Color.gray)
48 | }
49 | .readSize { size in
50 | isTruncated = (CGFloat(size.width) > w-horizontalmargin*2-itemIftextIconWidth)
51 | }
52 | .frame(width: w - itemIftextIconWidth - horizontalmargin*2, alignment: .leading)
53 | .clipped()
54 |
55 | Text(candidate.iftext ? "↩︎" : "⌘").foregroundColor(Color.white.opacity(0.5)).frame(width:itemIftextIconWidth)
56 | }
57 | .padding(5)
58 | .padding(.leading,5)
59 | .padding(.trailing,5)
60 | .fixedSize(horizontal: true, vertical: false)
61 | .frame(width:w, height:itemHeight, alignment: .leading)
62 | }
63 | }
64 | .frame(width: w, alignment: .leading)
65 | .background(bg)
66 | .font(.system(size: CGFloat(16)))
67 | }
68 | }
69 |
70 | struct ContentView: View {
71 | var candidates: [Candidate]
72 | var origin: String
73 | var curPage: Int = 1
74 | var hasNext: Bool = false
75 | var selectedI: Int = -1
76 | var error = ""
77 |
78 | var body: some View {
79 | let headerbg = -1 == selectedI
80 | ? itemselectedbg
81 | : Color(red:55/255,green: 53/255,blue: 54/255)
82 |
83 | return HStack(alignment:.top, spacing:20){
84 | VStack(alignment: .leading, spacing: 20) {
85 | if error.count > 0 {
86 | Text("error :: " + error).foregroundColor(Color.white).font(.system(size: CGFloat(20)))
87 | .padding(.top, 3)
88 | .padding(.bottom, 3)
89 | .padding(.leading, 10)
90 | .frame(width:w, alignment: .leading)
91 | }else{
92 | // header
93 | HStack(alignment:.center){
94 | Text("> " + (selectedI > -1 ? candidates[selectedI].output : origin)).foregroundColor(color1).frame(maxWidth:w-24-20, alignment: .leading).fixedSize(horizontal: true, vertical: false)
95 | Spacer()
96 | Text("\(curPage)").foregroundColor(Color.gray)
97 | }.font(.system(size: CGFloat(20)))
98 | .padding(.top, 3)
99 | .padding(.bottom, 5)
100 | .padding(.leading, 12)
101 | .padding(.trailing, 12)
102 | .frame(width:w-20, alignment: .leading)
103 | .fixedSize(horizontal: false, vertical: false)
104 | .background(headerbg)
105 | .cornerRadius(6)
106 | .padding(10)
107 | .padding(.top,3)
108 | .padding(.bottom,-20)
109 |
110 |
111 | // plane
112 | HStack(alignment:.top){
113 | // list
114 | VStack(alignment: .leading, spacing: 0) {
115 | ForEach(Array(candidates.enumerated()), id: \.element.id) { (index, candidate) in
116 |
117 | TruncableItem(candidate: candidate, ifselected: selectedI == index)
118 |
119 | }
120 | }
121 | }
122 | }}
123 | .padding(.bottom,5)
124 | .frame(width:w, alignment: .leading)
125 | .cornerRadius(6)
126 | .background(Color(red:37/255,green:36/255,blue:34/255))
127 | .padding(6)
128 | .cornerRadius(6)
129 | .border(Color.gray.opacity(0.3),width:6)
130 | .cornerRadius(6)
131 | }
132 | }
133 | }
134 |
135 | struct ContentView_Previews: PreviewProvider {
136 | static var previews: some View {
137 | ContentView(candidates: [
138 | Candidate(tag: "vim;", desc: "跳转至最后一行 跳转至最后一跳转至最后一行 跳转至最后一行跳转至最后一行 跳转至最后一跳转至最后一行 跳转至最后一行", output: "G 跳转至最后一至最后一行 跳转至最后一行 跳转至最后一行 跳转至最后一行 ", iftext: true,id:0),
139 | Candidate(tag: "vim;ae;", desc: "跳转至第一行", output: "gg",iftext: false,id:1),
140 | Candidate(tag: "vim;appe;", desc: "跳转至行尾", output: "g$" , iftext: true,id:2),
141 | Candidate(tag: "vim;", desc: "shift+V 进入可视化", output: "" , iftext: false,id:4),
142 | Candidate(tag: "vim;", desc: "shift+V 进入可视化", output: "" , iftext: false,id:3),
143 | Candidate(tag: "vim;", desc: "shift+V 进入可视化", output: "" , iftext: true,id:5),
144 | Candidate(tag: "vim;", desc: "shift+V 进入可视化", output: "" , iftext: true,id:6),
145 | Candidate(tag: "vim;vim;vim;vim;vim;vim;vivim;vim;vim;vim;vim;vim;vim;vim;vim;", desc: "shift+V 进入可视化", output: "" , iftext: true,id:7),
146 | Candidate(tag: "vim;", desc: "shift+V 进入可视化", output: "12345678912345678911111" , iftext: true,id:8),
147 | Candidate(tag: "vim;", desc: "shift+V 进入可视化可视化可视化可", output: "12345678" , iftext: true,id:9),
148 | ], origin:"vim1234567891234567891111112345678912345678911111", selectedI:7,error: "")
149 | }
150 | }
151 |
152 | class CandidatesWindow: NSWindow, NSWindowDelegate {
153 | let hostingView = NSHostingView(rootView: ContentView(candidates: [], origin: ""))
154 |
155 | func setCandidates(
156 | _ candidatesData: [Candidate],
157 | curPage: Int,
158 | hasNext: Bool,
159 | originalString: String,
160 | topLeft_: NSPoint
161 | ) {
162 | self.hostingView.rootView.error = ""
163 | self.hostingView.rootView.selectedI = -1
164 | self.hostingView.rootView.candidates = candidatesData
165 | self.hostingView.rootView.origin = originalString
166 | self.hostingView.rootView.hasNext = hasNext
167 | self.hostingView.rootView.curPage = curPage
168 |
169 | let origin = transformTopLeft(originalTopLeft:topLeft_)
170 | self.setFrameTopLeftPoint(origin)
171 |
172 | self.orderFront(nil)
173 | NSApp.setActivationPolicy(.prohibited)
174 | }
175 |
176 | func setSelector(i: Int){
177 | hostingView.rootView.selectedI = i
178 | }
179 |
180 | func setError(err: String){
181 | hostingView.rootView.error = err
182 | }
183 |
184 | override init(
185 | contentRect: NSRect,
186 | styleMask style: NSWindow.StyleMask,
187 | backing backingStoreType: NSWindow.BackingStoreType,
188 | defer flag: Bool
189 | ) {
190 | super.init(contentRect: contentRect, styleMask: style, backing: backingStoreType, defer: flag)
191 |
192 | level = NSWindow.Level(rawValue: NSWindow.Level.RawValue(CGShieldingWindowLevel()))
193 | styleMask = .init(arrayLiteral: .fullSizeContentView, .borderless)
194 | isReleasedWhenClosed = false
195 | backgroundColor = .clear
196 | delegate = self
197 |
198 | // 窗口大小可根据内容变化
199 | hostingView.translatesAutoresizingMaskIntoConstraints = false
200 | guard self.contentView != nil else {
201 | return
202 | }
203 | self.contentView?.addSubview(hostingView)
204 | self.contentView?.leftAnchor.constraint(equalTo: hostingView.leftAnchor).isActive = true
205 | self.contentView?.rightAnchor.constraint(equalTo: hostingView.rightAnchor).isActive = true
206 | self.contentView?.topAnchor.constraint(equalTo: hostingView.topAnchor).isActive = true
207 | self.contentView?.bottomAnchor.constraint(equalTo: hostingView.bottomAnchor).isActive = true
208 | }
209 |
210 | private func transformTopLeft(originalTopLeft: NSPoint) -> NSPoint {
211 | var left = originalTopLeft.x
212 | var top = originalTopLeft.y
213 |
214 | if let curScreen = getScreenFromPoint(originalTopLeft) {
215 | let screen = curScreen.frame
216 | left = (screen.maxX - screen.minX)/2 - (w)/2
217 | top = (screen.maxY - screen.minY)/2 + 300
218 | }
219 | return NSPoint(x: left, y: top)
220 | }
221 |
222 | static let shared = CandidatesWindow()
223 | }
224 |
225 | func getScreenFromPoint(_ point: NSPoint) -> NSScreen? {
226 | // find current screen
227 | for screen in NSScreen.screens {
228 | if screen.frame.contains(point) {
229 | return screen
230 | }
231 | }
232 | return NSScreen.main
233 | }
234 |
--------------------------------------------------------------------------------
/App/AnInputController.swift:
--------------------------------------------------------------------------------
1 | import Cocoa
2 | import InputMethodKit
3 |
4 | extension String: LocalizedError {
5 | public var errorDescription: String? { return self }
6 | }
7 |
8 | class AnInputController: IMKInputController {
9 | private var _candidates: [Candidate] = []
10 | private var _candidatesNow: [Candidate] = []
11 | private var _hasNext: Bool = false
12 | private var _selector: Int = -1
13 | private var ifbanned: Bool = false
14 | private var err: String = "" {
15 | didSet{
16 | if self.err.count == 0 {
17 | CandidatesWindow.shared.close()
18 | }else{
19 | CandidatesWindow.shared.setError(err: err)
20 | }
21 | }
22 | }
23 |
24 | private var _originalString = "" {
25 | didSet(old){
26 | curPage = 1
27 | _selector = -1
28 | client()?.setMarkedText(_originalString, selectionRange:NSMakeRange(_originalString.count, 0), replacementRange: replacementRange())
29 | if self._originalString.count == 0{
30 | CandidatesWindow.shared.close()
31 | return
32 | }
33 | if _candidates.count != 0
34 | || (old.count == 0 && self._originalString.count > 0)
35 | || old.count > self._originalString.count {
36 | _candidates = DataBaseClient.shared.getCandidates(origin: self._originalString)
37 | }
38 | refreshCandidatesWindow()
39 | }
40 | }
41 | private var curPage: Int = 1
42 | private var pageItemNum: Int = 0
43 | func refreshCandidatesWindow() {
44 | let starti = (curPage-1)*configCandidateNum
45 | let endi = curPage*configCandidateNum
46 | _hasNext = _candidates.count > endi
47 |
48 | _candidatesNow = Array(_candidates.count > starti ?
49 | _hasNext ? _candidates[starti.. Bool? {
62 | if _originalString.count > 0{
63 | if event.keyCode == kVK_RightArrow {
64 | if _hasNext {
65 | curPage += 1
66 | _selector = -1
67 | self.refreshCandidatesWindow()
68 | }
69 | return true
70 | }
71 | if event.keyCode == kVK_LeftArrow {
72 | if curPage > 1 {
73 | curPage -= 1
74 | _selector = -1
75 | self.refreshCandidatesWindow()
76 | }
77 | return true
78 | }
79 | if event.keyCode == kVK_UpArrow {
80 | if _selector >= 0 {
81 | _selector -= 1
82 | CandidatesWindow.shared.setSelector(i: _selector)
83 | }
84 | return true
85 | }
86 | if event.keyCode == kVK_DownArrow {
87 | if _selector < _candidatesNow.count-1 {
88 | _selector += 1
89 | CandidatesWindow.shared.setSelector(i: _selector)
90 | }
91 | return true
92 | }
93 | }
94 | return nil
95 | }
96 |
97 | private func deleteHandler(event: NSEvent) -> Bool? {
98 | if event.keyCode == kVK_Delete {
99 | if _originalString.count > 0 {
100 | _originalString = String(_originalString.dropLast())
101 | return true
102 | }
103 | return false
104 | }
105 | return nil
106 | }
107 |
108 | private func escHandler(event: NSEvent) -> Bool? {
109 | if event.keyCode == kVK_Escape {
110 | ctrl_press_times+=1
111 | if _originalString.count > 0 {
112 | clean()
113 | }else{
114 | if ctrl_press_times >= 2 {
115 | ifbanned = false
116 | toast.show("control mode")
117 | }else{
118 | ifbanned = !ifbanned
119 | if ifbanned {
120 | toast.show("banning mode")
121 | }else{
122 | toast.show("normal mode")
123 | }
124 | }
125 | }
126 | return true
127 | }
128 | return nil
129 | }
130 |
131 | static let ascii:String = String(Array(32...126).map { Character(Unicode.Scalar($0)) })
132 | private func inputHandler(event: NSEvent) -> Bool? {
133 | if event.modifierFlags.rawValue != 0 && event.modifierFlags != .shift {
134 | // check if .command .option .control is pressing
135 | return nil
136 | }
137 | if event.characters != nil{
138 | if AnInputController.ascii.contains(event.characters!) {
139 | _originalString += event.characters!
140 | return true
141 | }
142 | }
143 | return nil
144 | }
145 |
146 |
147 | static let keycode: [String: UInt16] = [
148 | // a-z
149 | "a": UInt16(kVK_ANSI_A),
150 | "b": UInt16(kVK_ANSI_B),
151 | "c": UInt16(kVK_ANSI_C),
152 | "d": UInt16(kVK_ANSI_D),
153 | "e": UInt16(kVK_ANSI_E),
154 | "f": UInt16(kVK_ANSI_F),
155 | "g": UInt16(kVK_ANSI_G),
156 | "h": UInt16(kVK_ANSI_H),
157 | "i": UInt16(kVK_ANSI_I),
158 | "j": UInt16(kVK_ANSI_J),
159 | "k": UInt16(kVK_ANSI_K),
160 | "l": UInt16(kVK_ANSI_L),
161 | "m": UInt16(kVK_ANSI_M),
162 | "n": UInt16(kVK_ANSI_N),
163 | "o": UInt16(kVK_ANSI_O),
164 | "p": UInt16(kVK_ANSI_P),
165 | "q": UInt16(kVK_ANSI_Q),
166 | "r": UInt16(kVK_ANSI_R),
167 | "s": UInt16(kVK_ANSI_S),
168 | "t": UInt16(kVK_ANSI_T),
169 | "u": UInt16(kVK_ANSI_U),
170 | "v": UInt16(kVK_ANSI_V),
171 | "w": UInt16(kVK_ANSI_W),
172 | "x": UInt16(kVK_ANSI_X),
173 | "y": UInt16(kVK_ANSI_Y),
174 | "z": UInt16(kVK_ANSI_Z),
175 | // Numbers 0-9
176 | "0": UInt16(kVK_ANSI_0),
177 | "1": UInt16(kVK_ANSI_1),
178 | "2": UInt16(kVK_ANSI_2),
179 | "3": UInt16(kVK_ANSI_3),
180 | "4": UInt16(kVK_ANSI_4),
181 | "5": UInt16(kVK_ANSI_5),
182 | "6": UInt16(kVK_ANSI_6),
183 | "7": UInt16(kVK_ANSI_7),
184 | "8": UInt16(kVK_ANSI_8),
185 | "9": UInt16(kVK_ANSI_9),
186 | // Arithmetic operators
187 | "+": UInt16(kVK_ANSI_KeypadPlus),
188 | "plus": UInt16(kVK_ANSI_KeypadPlus),
189 | "-": UInt16(kVK_ANSI_Minus),
190 | "*": UInt16(kVK_ANSI_KeypadMultiply),
191 | "=": UInt16(kVK_ANSI_Equal),
192 | // F1-F20
193 | "f1": UInt16(kVK_F1),
194 | "f2": UInt16(kVK_F2),
195 | "f3": UInt16(kVK_F3),
196 | "f4": UInt16(kVK_F4),
197 | "f5": UInt16(kVK_F5),
198 | "f6": UInt16(kVK_F6),
199 | "f7": UInt16(kVK_F7),
200 | "f8": UInt16(kVK_F8),
201 | "f9": UInt16(kVK_F9),
202 | "f10": UInt16(kVK_F10),
203 | "f11": UInt16(kVK_F11),
204 | "f12": UInt16(kVK_F12),
205 | "f13": UInt16(kVK_F13),
206 | "f14": UInt16(kVK_F14),
207 | "f15": UInt16(kVK_F15),
208 | "f16": UInt16(kVK_F16),
209 | "f17": UInt16(kVK_F17),
210 | "f18": UInt16(kVK_F18),
211 | "f19": UInt16(kVK_F19),
212 | "f20": UInt16(kVK_F20),
213 | // Other keys
214 | "'": UInt16(kVK_ANSI_Quote),
215 | "`": UInt16(kVK_ANSI_Grave),
216 | "capslock": UInt16(kVK_CapsLock),
217 | "delete": UInt16(kVK_ForwardDelete),
218 | "return": UInt16(kVK_Return),
219 | "tab": UInt16(kVK_Tab),
220 | "esc": UInt16(kVK_Escape),
221 | ",": UInt16(kVK_ANSI_Comma),
222 | ".": UInt16(kVK_ANSI_KeypadDecimal),
223 | "(": UInt16(kVK_ANSI_LeftBracket),
224 | ")": UInt16(kVK_ANSI_RightBracket),
225 | ";": UInt16(kVK_ANSI_Semicolon),
226 | "/": UInt16(kVK_ANSI_Slash),
227 | "space": UInt16(kVK_Space),
228 | "command": UInt16(kVK_Command),
229 | "cmd": UInt16(kVK_Command),
230 | "control": UInt16(kVK_Control),
231 | "ctrl": UInt16(kVK_Control),
232 | "fn": UInt16(kVK_Function),
233 | "option": UInt16(kVK_Option),
234 | "shift": UInt16(kVK_Shift),
235 | "down": UInt16(kVK_DownArrow),
236 | "left": UInt16(kVK_LeftArrow),
237 | "right": UInt16(kVK_RightArrow),
238 | "up": UInt16(kVK_UpArrow),
239 | ]
240 |
241 | private func insertHandler(event: NSEvent) throws -> Bool? {
242 | if (event.keyCode == kVK_Return || event.keyCode == kVK_Tab || event.keyCode == kVK_Space) {
243 | if _originalString.count == 0 {
244 | return false
245 | }
246 | if _selector == -1 {
247 | client()?.insertText(NSAttributedString(string: _originalString), replacementRange: replacementRange())
248 | clean()
249 | ifbanned = true
250 | toast.show("banning mode")
251 |
252 | if event.keyCode == kVK_Tab || event.keyCode == kVK_Space {
253 | return false
254 | }
255 | }else{
256 | if _candidatesNow[_selector].iftext {
257 | client()?.insertText(NSAttributedString(string: _candidatesNow[_selector].output), replacementRange: replacementRange())
258 | clean()
259 | }else{
260 | let keys: [String] = _candidatesNow[_selector].output.components(separatedBy: "+")
261 | let press = keys.last!
262 | var flags: UInt64 = 0
263 | for k in keys.dropLast() {
264 | switch k {
265 | case "shift":
266 | flags = CGEventFlags.maskShift.rawValue | flags
267 | case "ctrl","control":
268 | flags = CGEventFlags.maskControl.rawValue | flags
269 | case "command","cmd":
270 | flags = CGEventFlags.maskCommand.rawValue | flags
271 | case "option":
272 | flags = CGEventFlags.maskAlternate.rawValue | flags
273 | default: throw "bad expression of hotkey: " + "\(keys)"
274 | }
275 | }
276 | if let v = AnInputController.keycode[press] {
277 | clean()
278 | let up = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(v), keyDown: false);
279 | let down = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(v), keyDown: true);
280 | if flags != 0 {
281 | down?.flags = CGEventFlags(rawValue: flags);
282 | up?.flags = CGEventFlags(rawValue: flags);
283 | }
284 | down?.post(tap: CGEventTapLocation.cghidEventTap);
285 | up?.post(tap: CGEventTapLocation.cghidEventTap);
286 | }else{
287 | throw "bad expression of hotkey (at the last key): " + _candidatesNow[_selector].output
288 | }
289 | }
290 | }
291 | return true
292 | }
293 | return nil
294 | }
295 |
296 | private var ctrl_press_times : Int = 0
297 | override func handle(_ event: NSEvent!, client sender: Any!) -> Bool {
298 | if err.count > 0 {
299 | err = ""
300 | return true
301 | }
302 | if let r = escHandler(event: event) {
303 | return r
304 | }
305 | if ctrl_press_times >= 2 { // press ESC twice to open control mode
306 | ctrl_press_times = 0
307 | if event.characters == nil{
308 | return false
309 | }
310 |
311 | func shell(_ command: String) -> String {
312 | let task = Process()
313 | let pipe = Pipe()
314 | task.standardOutput = pipe
315 | task.standardError = pipe
316 | task.arguments = ["-c", command]
317 | task.launchPath = "/bin/bash"
318 | task.standardInput = nil
319 | task.launch()
320 | let data = pipe.fileHandleForReading.readDataToEndOfFile()
321 | let output = String(data: data, encoding: .utf8)!
322 | return output
323 | }
324 |
325 | switch event.characters!{
326 | case "s","S":
327 | DataBaseClient.shared.loadDict()
328 | clean()
329 | return true
330 | case "w", "W":
331 | _ = shell("open -a TextEdit ~/"+dict_filename)
332 | return true
333 | default:
334 | return false
335 | }
336 | }
337 | ctrl_press_times = 0
338 | if !ifbanned {
339 | for handler in [
340 | arrowKeyHandler,
341 | insertHandler,
342 | deleteHandler,
343 | inputHandler,
344 | ] {
345 | do {
346 | let r = try handler(event)
347 | if r != nil{
348 | return r!
349 | }
350 | }catch{
351 | err = error.localizedDescription
352 | return true
353 | }
354 | }
355 | }
356 |
357 | return false
358 | }
359 |
360 | // 获取当前输入的光标位置
361 | private func getOriginPoint() -> NSPoint {
362 | let xd: CGFloat = 12
363 | let yd: CGFloat = 4
364 | var rect = NSRect()
365 | client()?.attributes(forCharacterIndex: 0, lineHeightRectangle: &rect)
366 | return NSPoint(x: rect.minX + xd, y: rect.minY - yd)
367 | }
368 |
369 | func clean() {
370 | _originalString = ""
371 | }
372 |
373 | let toast = ToastWindow()
374 |
375 | override func deactivateServer(_ sender: Any!) {
376 | clean()
377 | }
378 | }
379 |
--------------------------------------------------------------------------------
/ihelper.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 8462AE462845ECF9004D41D7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8462AE452845ECF9004D41D7 /* Assets.xcassets */; };
11 | 8462AE542845ECF9004D41D7 /* Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8462AE532845ECF9004D41D7 /* Tests.swift */; };
12 | 8462AE742845F170004D41D7 /* DataBaseClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8462AE6F2845F170004D41D7 /* DataBaseClient.swift */; };
13 | 8462AE752845F170004D41D7 /* main.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 8462AE702845F170004D41D7 /* main.tiff */; };
14 | 847111FD28468EA100C43026 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847111FC28468EA100C43026 /* Toast.swift */; };
15 | 84E8C4782845F5C500B87E5E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8C4772845F5C500B87E5E /* main.swift */; };
16 | 84E8C47B2845F66C00B87E5E /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84E8C47A2845F66C00B87E5E /* MainMenu.xib */; };
17 | 84E8C47E2845F68300B87E5E /* AnInputController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8C47C2845F68300B87E5E /* AnInputController.swift */; };
18 | 84E8C47F2845F68300B87E5E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E8C47D2845F68300B87E5E /* ContentView.swift */; };
19 | 84F6710B28471E6D008DA61F /* ReadSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84F6710A28471E6D008DA61F /* ReadSize.swift */; };
20 | 84F6710D284739CE008DA61F /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = 84F6710C284739CE008DA61F /* README.md */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXContainerItemProxy section */
24 | 8462AE502845ECF9004D41D7 /* PBXContainerItemProxy */ = {
25 | isa = PBXContainerItemProxy;
26 | containerPortal = 8462AE362845ECF8004D41D7 /* Project object */;
27 | proxyType = 1;
28 | remoteGlobalIDString = 8462AE3D2845ECF8004D41D7;
29 | remoteInfo = aaaa;
30 | };
31 | /* End PBXContainerItemProxy section */
32 |
33 | /* Begin PBXFileReference section */
34 | 8462AE3E2845ECF8004D41D7 /* ihelper.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ihelper.app; sourceTree = BUILT_PRODUCTS_DIR; };
35 | 8462AE452845ECF9004D41D7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
36 | 8462AE482845ECF9004D41D7 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
37 | 8462AE4F2845ECF9004D41D7 /* ihelperTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ihelperTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
38 | 8462AE532845ECF9004D41D7 /* Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tests.swift; sourceTree = ""; };
39 | 8462AE6E2845F0A4004D41D7 /* ihelper.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ihelper.entitlements; sourceTree = ""; };
40 | 8462AE6F2845F170004D41D7 /* DataBaseClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DataBaseClient.swift; sourceTree = ""; };
41 | 8462AE702845F170004D41D7 /* main.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = main.tiff; sourceTree = ""; };
42 | 8462AE722845F170004D41D7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | 847111FC28468EA100C43026 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; };
44 | 84E8C4772845F5C500B87E5E /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
45 | 84E8C4792845F62B00B87E5E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
46 | 84E8C47A2845F66C00B87E5E /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = ""; };
47 | 84E8C47C2845F68300B87E5E /* AnInputController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnInputController.swift; sourceTree = ""; };
48 | 84E8C47D2845F68300B87E5E /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
49 | 84F6710A28471E6D008DA61F /* ReadSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReadSize.swift; sourceTree = ""; };
50 | 84F6710C284739CE008DA61F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; };
51 | /* End PBXFileReference section */
52 |
53 | /* Begin PBXFrameworksBuildPhase section */
54 | 8462AE3B2845ECF8004D41D7 /* Frameworks */ = {
55 | isa = PBXFrameworksBuildPhase;
56 | buildActionMask = 2147483647;
57 | files = (
58 | );
59 | runOnlyForDeploymentPostprocessing = 0;
60 | };
61 | 8462AE4C2845ECF9004D41D7 /* Frameworks */ = {
62 | isa = PBXFrameworksBuildPhase;
63 | buildActionMask = 2147483647;
64 | files = (
65 | );
66 | runOnlyForDeploymentPostprocessing = 0;
67 | };
68 | /* End PBXFrameworksBuildPhase section */
69 |
70 | /* Begin PBXGroup section */
71 | 8462AE352845ECF8004D41D7 = {
72 | isa = PBXGroup;
73 | children = (
74 | 84F6710C284739CE008DA61F /* README.md */,
75 | 8462AE722845F170004D41D7 /* Info.plist */,
76 | 8462AE6E2845F0A4004D41D7 /* ihelper.entitlements */,
77 | 8462AE402845ECF8004D41D7 /* App */,
78 | 8462AE522845ECF9004D41D7 /* Tests */,
79 | 8462AE3F2845ECF8004D41D7 /* Products */,
80 | );
81 | sourceTree = "";
82 | };
83 | 8462AE3F2845ECF8004D41D7 /* Products */ = {
84 | isa = PBXGroup;
85 | children = (
86 | 8462AE3E2845ECF8004D41D7 /* ihelper.app */,
87 | 8462AE4F2845ECF9004D41D7 /* ihelperTests.xctest */,
88 | );
89 | name = Products;
90 | sourceTree = "";
91 | };
92 | 8462AE402845ECF8004D41D7 /* App */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 847111FB28468E7F00C43026 /* UI */,
96 | 84E8C47C2845F68300B87E5E /* AnInputController.swift */,
97 | 84E8C47A2845F66C00B87E5E /* MainMenu.xib */,
98 | 84E8C4772845F5C500B87E5E /* main.swift */,
99 | 8462AE6F2845F170004D41D7 /* DataBaseClient.swift */,
100 | 8462AE702845F170004D41D7 /* main.tiff */,
101 | 8462AE452845ECF9004D41D7 /* Assets.xcassets */,
102 | 8462AE472845ECF9004D41D7 /* Preview Content */,
103 | );
104 | path = App;
105 | sourceTree = "";
106 | };
107 | 8462AE472845ECF9004D41D7 /* Preview Content */ = {
108 | isa = PBXGroup;
109 | children = (
110 | 8462AE482845ECF9004D41D7 /* Preview Assets.xcassets */,
111 | );
112 | path = "Preview Content";
113 | sourceTree = "";
114 | };
115 | 8462AE522845ECF9004D41D7 /* Tests */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 84E8C4792845F62B00B87E5E /* Info.plist */,
119 | 8462AE532845ECF9004D41D7 /* Tests.swift */,
120 | );
121 | path = Tests;
122 | sourceTree = "";
123 | };
124 | 847111FB28468E7F00C43026 /* UI */ = {
125 | isa = PBXGroup;
126 | children = (
127 | 84E8C47D2845F68300B87E5E /* ContentView.swift */,
128 | 847111FC28468EA100C43026 /* Toast.swift */,
129 | 84F6710A28471E6D008DA61F /* ReadSize.swift */,
130 | );
131 | path = UI;
132 | sourceTree = "";
133 | };
134 | /* End PBXGroup section */
135 |
136 | /* Begin PBXNativeTarget section */
137 | 8462AE3D2845ECF8004D41D7 /* ihelper */ = {
138 | isa = PBXNativeTarget;
139 | buildConfigurationList = 8462AE632845ECF9004D41D7 /* Build configuration list for PBXNativeTarget "ihelper" */;
140 | buildPhases = (
141 | 8462AE3A2845ECF8004D41D7 /* Sources */,
142 | 8462AE3B2845ECF8004D41D7 /* Frameworks */,
143 | 8462AE3C2845ECF8004D41D7 /* Resources */,
144 | );
145 | buildRules = (
146 | );
147 | dependencies = (
148 | );
149 | name = ihelper;
150 | productName = aaaa;
151 | productReference = 8462AE3E2845ECF8004D41D7 /* ihelper.app */;
152 | productType = "com.apple.product-type.application";
153 | };
154 | 8462AE4E2845ECF9004D41D7 /* ihelperTests */ = {
155 | isa = PBXNativeTarget;
156 | buildConfigurationList = 8462AE662845ECF9004D41D7 /* Build configuration list for PBXNativeTarget "ihelperTests" */;
157 | buildPhases = (
158 | 8462AE4B2845ECF9004D41D7 /* Sources */,
159 | 8462AE4C2845ECF9004D41D7 /* Frameworks */,
160 | 8462AE4D2845ECF9004D41D7 /* Resources */,
161 | );
162 | buildRules = (
163 | );
164 | dependencies = (
165 | 8462AE512845ECF9004D41D7 /* PBXTargetDependency */,
166 | );
167 | name = ihelperTests;
168 | productName = aaaaTests;
169 | productReference = 8462AE4F2845ECF9004D41D7 /* ihelperTests.xctest */;
170 | productType = "com.apple.product-type.bundle.unit-test";
171 | };
172 | /* End PBXNativeTarget section */
173 |
174 | /* Begin PBXProject section */
175 | 8462AE362845ECF8004D41D7 /* Project object */ = {
176 | isa = PBXProject;
177 | attributes = {
178 | BuildIndependentTargetsInParallel = 1;
179 | LastSwiftUpdateCheck = 1340;
180 | LastUpgradeCheck = 1340;
181 | TargetAttributes = {
182 | 8462AE3D2845ECF8004D41D7 = {
183 | CreatedOnToolsVersion = 13.4;
184 | };
185 | 8462AE4E2845ECF9004D41D7 = {
186 | CreatedOnToolsVersion = 13.4;
187 | TestTargetID = 8462AE3D2845ECF8004D41D7;
188 | };
189 | };
190 | };
191 | buildConfigurationList = 8462AE392845ECF8004D41D7 /* Build configuration list for PBXProject "ihelper" */;
192 | compatibilityVersion = "Xcode 13.0";
193 | developmentRegion = en;
194 | hasScannedForEncodings = 0;
195 | knownRegions = (
196 | en,
197 | Base,
198 | );
199 | mainGroup = 8462AE352845ECF8004D41D7;
200 | productRefGroup = 8462AE3F2845ECF8004D41D7 /* Products */;
201 | projectDirPath = "";
202 | projectRoot = "";
203 | targets = (
204 | 8462AE3D2845ECF8004D41D7 /* ihelper */,
205 | 8462AE4E2845ECF9004D41D7 /* ihelperTests */,
206 | );
207 | };
208 | /* End PBXProject section */
209 |
210 | /* Begin PBXResourcesBuildPhase section */
211 | 8462AE3C2845ECF8004D41D7 /* Resources */ = {
212 | isa = PBXResourcesBuildPhase;
213 | buildActionMask = 2147483647;
214 | files = (
215 | 8462AE752845F170004D41D7 /* main.tiff in Resources */,
216 | 8462AE462845ECF9004D41D7 /* Assets.xcassets in Resources */,
217 | 84F6710D284739CE008DA61F /* README.md in Resources */,
218 | 84E8C47B2845F66C00B87E5E /* MainMenu.xib in Resources */,
219 | );
220 | runOnlyForDeploymentPostprocessing = 0;
221 | };
222 | 8462AE4D2845ECF9004D41D7 /* Resources */ = {
223 | isa = PBXResourcesBuildPhase;
224 | buildActionMask = 2147483647;
225 | files = (
226 | );
227 | runOnlyForDeploymentPostprocessing = 0;
228 | };
229 | /* End PBXResourcesBuildPhase section */
230 |
231 | /* Begin PBXSourcesBuildPhase section */
232 | 8462AE3A2845ECF8004D41D7 /* Sources */ = {
233 | isa = PBXSourcesBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 84E8C4782845F5C500B87E5E /* main.swift in Sources */,
237 | 8462AE742845F170004D41D7 /* DataBaseClient.swift in Sources */,
238 | 847111FD28468EA100C43026 /* Toast.swift in Sources */,
239 | 84F6710B28471E6D008DA61F /* ReadSize.swift in Sources */,
240 | 84E8C47F2845F68300B87E5E /* ContentView.swift in Sources */,
241 | 84E8C47E2845F68300B87E5E /* AnInputController.swift in Sources */,
242 | );
243 | runOnlyForDeploymentPostprocessing = 0;
244 | };
245 | 8462AE4B2845ECF9004D41D7 /* Sources */ = {
246 | isa = PBXSourcesBuildPhase;
247 | buildActionMask = 2147483647;
248 | files = (
249 | 8462AE542845ECF9004D41D7 /* Tests.swift in Sources */,
250 | );
251 | runOnlyForDeploymentPostprocessing = 0;
252 | };
253 | /* End PBXSourcesBuildPhase section */
254 |
255 | /* Begin PBXTargetDependency section */
256 | 8462AE512845ECF9004D41D7 /* PBXTargetDependency */ = {
257 | isa = PBXTargetDependency;
258 | target = 8462AE3D2845ECF8004D41D7 /* ihelper */;
259 | targetProxy = 8462AE502845ECF9004D41D7 /* PBXContainerItemProxy */;
260 | };
261 | /* End PBXTargetDependency section */
262 |
263 | /* Begin XCBuildConfiguration section */
264 | 8462AE612845ECF9004D41D7 /* Debug */ = {
265 | isa = XCBuildConfiguration;
266 | buildSettings = {
267 | ALWAYS_SEARCH_USER_PATHS = NO;
268 | CLANG_ANALYZER_NONNULL = YES;
269 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
270 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
271 | CLANG_ENABLE_MODULES = YES;
272 | CLANG_ENABLE_OBJC_ARC = YES;
273 | CLANG_ENABLE_OBJC_WEAK = YES;
274 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
275 | CLANG_WARN_BOOL_CONVERSION = YES;
276 | CLANG_WARN_COMMA = YES;
277 | CLANG_WARN_CONSTANT_CONVERSION = YES;
278 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
279 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
280 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
281 | CLANG_WARN_EMPTY_BODY = YES;
282 | CLANG_WARN_ENUM_CONVERSION = YES;
283 | CLANG_WARN_INFINITE_RECURSION = YES;
284 | CLANG_WARN_INT_CONVERSION = YES;
285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
286 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
288 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
289 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
290 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
291 | CLANG_WARN_STRICT_PROTOTYPES = YES;
292 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
293 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
294 | CLANG_WARN_UNREACHABLE_CODE = YES;
295 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
296 | CONFIGURATION_BUILD_DIR = "/Library/Input Methods";
297 | COPY_PHASE_STRIP = NO;
298 | DEBUG_INFORMATION_FORMAT = dwarf;
299 | ENABLE_STRICT_OBJC_MSGSEND = YES;
300 | ENABLE_TESTABILITY = YES;
301 | GCC_C_LANGUAGE_STANDARD = gnu11;
302 | GCC_DYNAMIC_NO_PIC = NO;
303 | GCC_NO_COMMON_BLOCKS = YES;
304 | GCC_OPTIMIZATION_LEVEL = 0;
305 | GCC_PREPROCESSOR_DEFINITIONS = (
306 | "DEBUG=1",
307 | "$(inherited)",
308 | );
309 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
310 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
311 | GCC_WARN_UNDECLARED_SELECTOR = YES;
312 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
313 | GCC_WARN_UNUSED_FUNCTION = YES;
314 | GCC_WARN_UNUSED_VARIABLE = YES;
315 | INFOPLIST_FILE = Info.plist;
316 | INFOPLIST_PREPROCESS = NO;
317 | MACOSX_DEPLOYMENT_TARGET = 12.3;
318 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
319 | MTL_FAST_MATH = YES;
320 | ONLY_ACTIVE_ARCH = YES;
321 | SDKROOT = macosx;
322 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
323 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
324 | SYMROOT = "/Library/Input Methods";
325 | };
326 | name = Debug;
327 | };
328 | 8462AE622845ECF9004D41D7 /* Release */ = {
329 | isa = XCBuildConfiguration;
330 | buildSettings = {
331 | ALWAYS_SEARCH_USER_PATHS = NO;
332 | CLANG_ANALYZER_NONNULL = YES;
333 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
334 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
335 | CLANG_ENABLE_MODULES = YES;
336 | CLANG_ENABLE_OBJC_ARC = YES;
337 | CLANG_ENABLE_OBJC_WEAK = YES;
338 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
339 | CLANG_WARN_BOOL_CONVERSION = YES;
340 | CLANG_WARN_COMMA = YES;
341 | CLANG_WARN_CONSTANT_CONVERSION = YES;
342 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
343 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
344 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
345 | CLANG_WARN_EMPTY_BODY = YES;
346 | CLANG_WARN_ENUM_CONVERSION = YES;
347 | CLANG_WARN_INFINITE_RECURSION = YES;
348 | CLANG_WARN_INT_CONVERSION = YES;
349 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
350 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
351 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
352 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
353 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
354 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
355 | CLANG_WARN_STRICT_PROTOTYPES = YES;
356 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
357 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
358 | CLANG_WARN_UNREACHABLE_CODE = YES;
359 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
360 | CONFIGURATION_BUILD_DIR = "/Library/Input Methods";
361 | COPY_PHASE_STRIP = NO;
362 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
363 | ENABLE_NS_ASSERTIONS = NO;
364 | ENABLE_STRICT_OBJC_MSGSEND = YES;
365 | GCC_C_LANGUAGE_STANDARD = gnu11;
366 | GCC_NO_COMMON_BLOCKS = YES;
367 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
368 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
369 | GCC_WARN_UNDECLARED_SELECTOR = YES;
370 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
371 | GCC_WARN_UNUSED_FUNCTION = YES;
372 | GCC_WARN_UNUSED_VARIABLE = YES;
373 | INFOPLIST_FILE = Info.plist;
374 | INFOPLIST_PREPROCESS = NO;
375 | MACOSX_DEPLOYMENT_TARGET = 12.3;
376 | MTL_ENABLE_DEBUG_INFO = NO;
377 | MTL_FAST_MATH = YES;
378 | SDKROOT = macosx;
379 | SWIFT_COMPILATION_MODE = wholemodule;
380 | SWIFT_OPTIMIZATION_LEVEL = "-O";
381 | SYMROOT = "/Library/Input Methods";
382 | };
383 | name = Release;
384 | };
385 | 8462AE642845ECF9004D41D7 /* Debug */ = {
386 | isa = XCBuildConfiguration;
387 | buildSettings = {
388 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
389 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
390 | CODE_SIGN_ENTITLEMENTS = ihelper.entitlements;
391 | CODE_SIGN_IDENTITY = "Apple Development";
392 | CODE_SIGN_STYLE = Automatic;
393 | COMBINE_HIDPI_IMAGES = YES;
394 | CURRENT_PROJECT_VERSION = 1;
395 | DEVELOPMENT_ASSET_PATHS = "\"App/Preview Content\"";
396 | DEVELOPMENT_TEAM = ZTMJD8G3H6;
397 | ENABLE_PREVIEWS = YES;
398 | GENERATE_INFOPLIST_FILE = YES;
399 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
400 | LD_RUNPATH_SEARCH_PATHS = (
401 | "$(inherited)",
402 | "@executable_path/../Frameworks",
403 | );
404 | MACOSX_DEPLOYMENT_TARGET = 10.15;
405 | MARKETING_VERSION = 1.0;
406 | PRODUCT_BUNDLE_IDENTIFIER = fumeboy.inputmethod.ihelper;
407 | PRODUCT_NAME = "$(TARGET_NAME)";
408 | SWIFT_EMIT_LOC_STRINGS = YES;
409 | SWIFT_VERSION = 5.0;
410 | };
411 | name = Debug;
412 | };
413 | 8462AE652845ECF9004D41D7 /* Release */ = {
414 | isa = XCBuildConfiguration;
415 | buildSettings = {
416 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
417 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
418 | CODE_SIGN_ENTITLEMENTS = ihelper.entitlements;
419 | CODE_SIGN_IDENTITY = "Apple Development";
420 | CODE_SIGN_STYLE = Automatic;
421 | COMBINE_HIDPI_IMAGES = YES;
422 | CURRENT_PROJECT_VERSION = 1;
423 | DEVELOPMENT_ASSET_PATHS = "\"App/Preview Content\"";
424 | DEVELOPMENT_TEAM = ZTMJD8G3H6;
425 | ENABLE_PREVIEWS = YES;
426 | GENERATE_INFOPLIST_FILE = YES;
427 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
428 | LD_RUNPATH_SEARCH_PATHS = (
429 | "$(inherited)",
430 | "@executable_path/../Frameworks",
431 | );
432 | MACOSX_DEPLOYMENT_TARGET = 10.15;
433 | MARKETING_VERSION = 1.0;
434 | PRODUCT_BUNDLE_IDENTIFIER = fumeboy.inputmethod.ihelper;
435 | PRODUCT_NAME = "$(TARGET_NAME)";
436 | SWIFT_EMIT_LOC_STRINGS = YES;
437 | SWIFT_VERSION = 5.0;
438 | };
439 | name = Release;
440 | };
441 | 8462AE672845ECF9004D41D7 /* Debug */ = {
442 | isa = XCBuildConfiguration;
443 | buildSettings = {
444 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
445 | BUNDLE_LOADER = "$(TEST_HOST)";
446 | CODE_SIGN_STYLE = Automatic;
447 | CURRENT_PROJECT_VERSION = 1;
448 | GENERATE_INFOPLIST_FILE = YES;
449 | INFOPLIST_FILE = Tests/Info.plist;
450 | MACOSX_DEPLOYMENT_TARGET = 12.3;
451 | MARKETING_VERSION = 1.0;
452 | PRODUCT_BUNDLE_IDENTIFIER = a.aaaaTests;
453 | PRODUCT_NAME = "$(TARGET_NAME)";
454 | SWIFT_EMIT_LOC_STRINGS = NO;
455 | SWIFT_VERSION = 5.0;
456 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ihelper.app/Contents/MacOS/ihelper";
457 | };
458 | name = Debug;
459 | };
460 | 8462AE682845ECF9004D41D7 /* Release */ = {
461 | isa = XCBuildConfiguration;
462 | buildSettings = {
463 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
464 | BUNDLE_LOADER = "$(TEST_HOST)";
465 | CODE_SIGN_STYLE = Automatic;
466 | CURRENT_PROJECT_VERSION = 1;
467 | GENERATE_INFOPLIST_FILE = YES;
468 | INFOPLIST_FILE = Tests/Info.plist;
469 | MACOSX_DEPLOYMENT_TARGET = 12.3;
470 | MARKETING_VERSION = 1.0;
471 | PRODUCT_BUNDLE_IDENTIFIER = a.aaaaTests;
472 | PRODUCT_NAME = "$(TARGET_NAME)";
473 | SWIFT_EMIT_LOC_STRINGS = NO;
474 | SWIFT_VERSION = 5.0;
475 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ihelper.app/Contents/MacOS/ihelper";
476 | };
477 | name = Release;
478 | };
479 | /* End XCBuildConfiguration section */
480 |
481 | /* Begin XCConfigurationList section */
482 | 8462AE392845ECF8004D41D7 /* Build configuration list for PBXProject "ihelper" */ = {
483 | isa = XCConfigurationList;
484 | buildConfigurations = (
485 | 8462AE612845ECF9004D41D7 /* Debug */,
486 | 8462AE622845ECF9004D41D7 /* Release */,
487 | );
488 | defaultConfigurationIsVisible = 0;
489 | defaultConfigurationName = Release;
490 | };
491 | 8462AE632845ECF9004D41D7 /* Build configuration list for PBXNativeTarget "ihelper" */ = {
492 | isa = XCConfigurationList;
493 | buildConfigurations = (
494 | 8462AE642845ECF9004D41D7 /* Debug */,
495 | 8462AE652845ECF9004D41D7 /* Release */,
496 | );
497 | defaultConfigurationIsVisible = 0;
498 | defaultConfigurationName = Release;
499 | };
500 | 8462AE662845ECF9004D41D7 /* Build configuration list for PBXNativeTarget "ihelperTests" */ = {
501 | isa = XCConfigurationList;
502 | buildConfigurations = (
503 | 8462AE672845ECF9004D41D7 /* Debug */,
504 | 8462AE682845ECF9004D41D7 /* Release */,
505 | );
506 | defaultConfigurationIsVisible = 0;
507 | defaultConfigurationName = Release;
508 | };
509 | /* End XCConfigurationList section */
510 | };
511 | rootObject = 8462AE362845ECF8004D41D7 /* Project object */;
512 | }
513 |
--------------------------------------------------------------------------------