├── FarewellOfCapsDelay
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── Icon-128.png
│ │ ├── Icon-16.png
│ │ ├── Icon-256.png
│ │ ├── Icon-32.png
│ │ ├── Icon-512.png
│ │ ├── Icon-16@2x.png
│ │ ├── Icon-32@2x.png
│ │ ├── Icon-128@2x.png
│ │ ├── Icon-256@2x.png
│ │ ├── Icon-512@2x.png
│ │ └── Contents.json
│ └── AccentColor.colorset
│ │ └── Contents.json
├── Info.plist
├── FarewellOfCapsDelay.entitlements
├── main.swift
├── PopupFix
│ ├── Utils.swift
│ ├── PopupFix.swift
│ ├── ApplicationObserver.swift
│ └── UIElement.swift
├── PreferenceDialog.swift
├── PreferenceHelper.swift
├── InputSourceManager.swift
├── InputManager.swift
├── UserDefaultWrapper.swift
├── AppDelegate.swift
└── Base.lproj
│ └── Main.storyboard
├── FarewellOfCapsDelay.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcuserdata
│ └── james.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
├── xcshareddata
│ └── xcschemes
│ │ └── FarewellOfCapsDelay.xcscheme
└── project.pbxproj
├── .gitignore
├── Karabiner.md
└── README.md
/FarewellOfCapsDelay/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-128.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-16.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-256.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-32.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-512.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-16@2x.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-32@2x.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-128@2x.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-256@2x.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GST-Main/FOCD/HEAD/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Icon-512@2x.png
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/FarewellOfCapsDelay.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/main.swift:
--------------------------------------------------------------------------------
1 | import AppKit
2 | import os
3 |
4 | let app = NSApplication.shared
5 | let delegate = AppDelegate()
6 | let logger = Logger(subsystem: "com.GST.focd", category: "FOCD")
7 | app.delegate = delegate
8 | app.setActivationPolicy(.accessory)
9 | _ = NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
10 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay.xcodeproj/xcuserdata/james.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | FarewellOfCapsDelay.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 1A7806BE2C71F88C0080D50A
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### macOS ###
2 | # General
3 | .DS_Store
4 | .AppleDouble
5 | .LSOverride
6 |
7 | # Icon must end with two \r
8 | Icon
9 |
10 |
11 | # Thumbnails
12 | ._*
13 |
14 | # Files that might appear in the root of a volume
15 | .DocumentRevisions-V100
16 | .fseventsd
17 | .Spotlight-V100
18 | .TemporaryItems
19 | .Trashes
20 | .VolumeIcon.icns
21 | .com.apple.timemachine.donotpresent
22 |
23 | # Directories potentially created on remote AFP share
24 | .AppleDB
25 | .AppleDesktop
26 | Network Trash Folder
27 | Temporary Items
28 | .apdisk
29 |
30 | ### macOS Patch ###
31 | # iCloud generated files
32 | *.icloud
33 |
34 | ### Xcode ###
35 | ## User settings
36 | xcuserdata/
37 |
38 | ## Xcode 8 and earlier
39 | *.xcscmblueprint
40 | *.xccheckout
41 |
42 | ### Xcode Patch ###
43 | *.xcodeproj/*
44 | !*.xcodeproj/project.pbxproj
45 | !*.xcodeproj/xcshareddata/
46 | !*.xcodeproj/project.xcworkspace/
47 | !*.xcworkspace/contents.xcworkspacedata
48 | /*.gcno
49 | **/xcshareddata/WorkspaceSettings.xcsettings
50 |
--------------------------------------------------------------------------------
/Karabiner.md:
--------------------------------------------------------------------------------
1 | # Karabiner 사용가이드
2 |
3 | ## 키 매핑
4 |
5 | Caps Lock이 아닌 Right alt나 Right Command로 맵핑 가능.
6 |
7 | - Karabiner 설정 중
8 | - Karabiner에서 Complex Modifications에서 아래의 rule을 새로 추가 후 적용
9 |
10 | 아래는 Caps Lock을 Right Alt로 맵핑 예시:
11 |
12 | ```json
13 | {
14 | "description": "Right Alt를 Caps Lock으로 (반복 없음, 뗄 때는 무시)",
15 | "manipulators": [
16 | {
17 | "from": {
18 | "key_code": "right_alt",
19 | "modifiers": { "optional": ["any"] }
20 | },
21 | "to": [
22 | {
23 | "key_code": "caps_lock",
24 | "repeat": false
25 | }
26 | ],
27 | "to_after_key_up": [
28 | {
29 | "set_variable": {
30 | "name": "vk_none",
31 | "value": 0
32 | }
33 | }
34 | ],
35 | "type": "basic"
36 | }
37 | ]
38 | }
39 | ```
40 |
41 | ## 충돌 해결
42 |
43 | FOCD가 Karabiner같은 프로그램이나 내부 권한, 혹은 FOCD 개발 시, 충돌되었을 때의 해결법
44 |
45 | 1. '설정 > 일반 > 로그인 항목 > 백그라운드에서 허용' 에서 Karabiner와 관련된 사항의 토글 버튼을 오프, FOCD 재부팅 후 다시 토글 온
46 |
47 | 
48 |
49 | 2. 1.이 안될 시, `tccutil`로 FOCD의 권한 초기화 후 다시 FOCD 실행
50 |
51 | ```bash
52 | $ tccutil reset All com.GST.focd
53 | ```
54 |
55 |
56 | ## Copyright
57 |
58 | 이 가이드는 [@hanbat1mj](https://github.com/hanbat1mj) 님의 도움으로 작성되었습니다.
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/PopupFix/Utils.swift:
--------------------------------------------------------------------------------
1 | import ApplicationServices
2 |
3 | extension AXError: @retroactive CustomStringConvertible {
4 | public var description: String {
5 | switch self {
6 | case .success: "success"
7 | case .failure: "failure"
8 | case .illegalArgument: "illegalArgument"
9 | case .invalidUIElement: "invalidUIElement"
10 | case .invalidUIElementObserver: "invalidUIElementObserver"
11 | case .cannotComplete: "cannotComplete"
12 | case .attributeUnsupported: "attributeUnsupported"
13 | case .actionUnsupported: "actionUnsupported"
14 | case .notificationUnsupported: "notificationUnsupported"
15 | case .notImplemented: "notImplemented"
16 | case .notificationAlreadyRegistered: "notificationAlreadyRegistered"
17 | case .notificationNotRegistered: "notificationNotRegistered"
18 | case .apiDisabled: "apiDisabled"
19 | case .noValue: "noValue"
20 | case .parameterizedAttributeUnsupported: "parameterizedAttributeUnsupported"
21 | case .notEnoughPrecision: "notEnoughPrecision"
22 | @unknown default: "fuck"
23 | }
24 | }
25 | }
26 |
27 | extension Date {
28 | private static let timestampFormatter: DateFormatter = {
29 | let formatter = DateFormatter()
30 | formatter.dateFormat = "HH:mm:ss.SSSS"
31 | return formatter
32 | }()
33 |
34 | var timestamp: String {
35 | return Self.timestampFormatter.string(from: self)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Icon-16.png",
5 | "idiom" : "mac",
6 | "scale" : "1x",
7 | "size" : "16x16"
8 | },
9 | {
10 | "filename" : "Icon-16@2x.png",
11 | "idiom" : "mac",
12 | "scale" : "2x",
13 | "size" : "16x16"
14 | },
15 | {
16 | "filename" : "Icon-32.png",
17 | "idiom" : "mac",
18 | "scale" : "1x",
19 | "size" : "32x32"
20 | },
21 | {
22 | "filename" : "Icon-32@2x.png",
23 | "idiom" : "mac",
24 | "scale" : "2x",
25 | "size" : "32x32"
26 | },
27 | {
28 | "filename" : "Icon-128.png",
29 | "idiom" : "mac",
30 | "scale" : "1x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "filename" : "Icon-128@2x.png",
35 | "idiom" : "mac",
36 | "scale" : "2x",
37 | "size" : "128x128"
38 | },
39 | {
40 | "filename" : "Icon-256.png",
41 | "idiom" : "mac",
42 | "scale" : "1x",
43 | "size" : "256x256"
44 | },
45 | {
46 | "filename" : "Icon-256@2x.png",
47 | "idiom" : "mac",
48 | "scale" : "2x",
49 | "size" : "256x256"
50 | },
51 | {
52 | "filename" : "Icon-512.png",
53 | "idiom" : "mac",
54 | "scale" : "1x",
55 | "size" : "512x512"
56 | },
57 | {
58 | "filename" : "Icon-512@2x.png",
59 | "idiom" : "mac",
60 | "scale" : "2x",
61 | "size" : "512x512"
62 | }
63 | ],
64 | "info" : {
65 | "author" : "xcode",
66 | "version" : 1
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Farewell Of Capslock Delay
2 | 맥 운영체제에서 캡스락으로 입력기 전환 시 딜레이가 생기는 불편함을 해결해주는 애플리케이션 입니다.
3 |
4 | ## 설치
5 | macOS 14 Sonoma 기준
6 | 1. 앱 실행
7 | 2. 설정 > 개인정보 보호 및 보안 > 입력 모니터링 > 항목에 앱 추가
8 | 3. 설정 > 키보드 > 입력 소스 우측의 "편집" > Caps Lock 키로 ABC 입력 소스 전환 해제
9 |
10 | #### 추천사항 - 시작 프로그램 설정
11 | 일반 > 로그인 항목 > 로그인 시 열기 > 항목에 앱 추가
12 |
13 | #### 추천사항 - 캡스락 비활성화
14 | 키보드 > 키보드 단축키 > 보조 키 > 캡스락 키를 '동작없음'으로 설정
15 |
16 | > [!TIP]
17 | > '시스템 설정 마법사' 기능으로 한번에 설정할 수 있습니다.
18 |
19 | ## 사용법
20 | 앱을 실행합니다. 이 앱은 별도의 창 없이 상태 바에만 존재하는 앱입니다.
21 |
22 | ### 종료
23 | 상태 바에서 ⇪ 아이콘을 클릭해 종료 버튼 누르기
24 |
25 | ### 단축키
26 | * **CapsLock** - 한/영 전환
27 | * **Shift + CapsLock** - 캡스락 토글
28 | * **Option + CapsLock** - 세번째 입력기(일어/중국어)로 전환
29 |
30 | > [!Note]
31 | > 일어 입력기는 로마지만 지원하며 중국어 입력기는 병음 간체만 지원합니다.
32 |
33 | > [!Note]
34 | > 새로 추가된 입력기는 인식하지 않습니다. 앱을 종료 후 재실행 해주세요.
35 |
36 |
37 | ## 제거
38 | 앱 파일을 삭제
39 |
40 | ## Karabiner 사용시
41 | [가이드](https://github.com/GST-Main/FOCD/blob/master/Karabiner.md) 참고
42 |
43 |
44 | ## 업데이트 로그
45 | ### 1.1.0
46 | * 고부하 상태에서 간헐적인 한영전환 씹힘 문제를 완화하였습니다.
47 | * 캡스락 상태에선 캡스락키가 한영전환 대신 캡스락 해제로 작동합니다.
48 | * 상태 바 아이콘 숨기기 기능을 추가하였습니다. 아이콘이 숨겨져도 그대로 작동하며 앱을 한번 더 실행시 다시 나타납니다.
49 |
50 | ### 1.1.1
51 | * macOS 15.2에서의 비정상 작동 수정
52 |
53 | ### 1.2.0
54 | * 간헐적으로 한영 전환 팝업이 비정상적으로 등장하는 macOS 버그 픽스 기능을 추가했습니다.
55 | * 해당 기능을 사용하기 위해선 접근성 권한을 설정해주어야 합니다.
56 | * 앱 아이콘과 이름을 건전하게 변경하였습니다.
57 |
58 | ### 1.2.1
59 | * 한영전환 씹힘문제 개선
60 | * 팝업픽스 기능 비정상 작동 수정
61 |
62 | ### 1.3.0
63 | * 구름입력기 지원
64 | * 두벌식외 다른 한국어 레이아웃 지원
65 | * 캡스락 수동관리 : 키보드 설정에서 캡스락을 비활성화하면 인디케이터가 깜빡이지 않습니다
66 | * 설정 마법사 추가
67 |
68 | ## 알려진 문제
69 | * 아주 가끔식 입력이 밀리거나 씹히는 문제가 있습니다.
70 | * 간혹 일어•중국어 입력기 전환시 영어 입력모드로 진입합니다. 일어 모드 진입시 히라가나 입력모드로 전환되는 것이 의도된 바입니다.
71 | * 아이패드 유니버설 컨트롤 기능 사용시 아이패드에 포커스가 넘어가 있어도 캡스락이 맥에서 한/영 전환으로 동작합니다.
72 | * 팝업 제거 기능은 편법적인 방법을 사용하므로 순간 나타났다 사라질 수 있습니다.
73 | * 다른 접근성 프로그램과 함께 사용할 시 정상 작동하지 않을 수 있습니다. '설정 > 개인정보 보호 및 보안 > 입력 모니터링'에서 키보드 권한을 사용중인 다른 프로그램을 확인해주세요.
74 |
75 | # Disclaimer
76 | 이 소프트웨어를 사용하면서 발생하는 문제는 개발자가 아닌 사용자의 책임임.
77 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay.xcodeproj/xcshareddata/xcschemes/FarewellOfCapsDelay.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
16 |
22 |
23 |
24 |
25 |
26 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/FarewellOfCapsDelay/PreferenceDialog.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | struct PreferenceDialog: View {
4 | @State private var options: Set