Skip to content

Commit 6c0b051

Browse files
committed
물리 키보드 Caps Lock 상태 변경에 HIS_XPC 함수 연속 호출 추가
macOS Sonoma 이후 Caps Lock으로 한/A 전환 시 커서에 ⇪ 아이콘이 나오는 문제 대응
1 parent b9f6545 commit 6c0b051

File tree

3 files changed

+39
-35
lines changed

3 files changed

+39
-35
lines changed

SokIM.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
DF7A3048289F96970003BFA6 /* InputMonitor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputMonitor.swift; sourceTree = "<group>"; };
4444
DF7A949D27F44C05005E3783 /* Controller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = "<group>"; };
4545
DF7A949F27F470E7005E3783 /* Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helpers.swift; sourceTree = "<group>"; };
46+
DF7DA4F12D7BA98C0004E154 /* HIServices.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HIServices.h; sourceTree = "<group>"; };
4647
DF91AB7F281125C50017664C /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/InfoPlist.strings; sourceTree = "<group>"; };
4748
DF9286CA26F5CFAE00002080 /* SokIM.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SokIM.app; sourceTree = BUILT_PRODUCTS_DIR; };
4849
DF9286CD26F5CFAE00002080 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
@@ -107,6 +108,7 @@
107108
DFD8998527F59E3B00C9B8CE /* Engine.swift */,
108109
DFB825D627F6B25700F31B72 /* QwertyEngine.swift */,
109110
DF2B53C12802B61D00A64F95 /* TwoSetEngine.swift */,
111+
DF7DA4F12D7BA98C0004E154 /* HIServices.h */,
110112
DF7A949F27F470E7005E3783 /* Helpers.swift */,
111113
DFC20DAE28CEFD73006A8EC2 /* Preferences.swift */,
112114
DF9286CF26F5CFB000002080 /* Assets.xcassets */,
@@ -402,6 +404,7 @@
402404
PRODUCT_BUNDLE_IDENTIFIER = com.kiding.inputmethod.sok;
403405
PRODUCT_NAME = "$(TARGET_NAME)";
404406
PROVISIONING_PROFILE_SPECIFIER = "";
407+
SWIFT_OBJC_BRIDGING_HEADER = SokIM/HIServices.h;
405408
SWIFT_VERSION = 5.0;
406409
};
407410
name = Debug;
@@ -431,6 +434,7 @@
431434
PRODUCT_BUNDLE_IDENTIFIER = com.kiding.inputmethod.sok;
432435
PRODUCT_NAME = "$(TARGET_NAME)";
433436
PROVISIONING_PROFILE_SPECIFIER = "";
437+
SWIFT_OBJC_BRIDGING_HEADER = SokIM/HIServices.h;
434438
SWIFT_VERSION = 5.0;
435439
};
436440
name = Release;

SokIM/HIServices.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef HIServices_h
2+
#define HIServices_h
3+
4+
#import <Foundation/Foundation.h>
5+
6+
void HIS_XPC_SetCapsLockModifierState(bool enabled);
7+
8+
#endif

SokIM/Helpers.swift

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -143,21 +143,30 @@ func getMappedModifierUsage(_ usage: UInt32, _ device: IOHIDDevice) -> UInt32 {
143143
return usage
144144
}
145145

146-
// MARK: - Etc
146+
// MARK: - 물리 키보드 Caps Lock 상태
147147

148-
/**
149-
연결된 모든 HID 키보드에 대해 Caps Lock 상태와 LED 조정
150-
@see https://github.com/busyloop/maclight
151-
*/
152-
private var block = DispatchWorkItem { }
148+
private var state: Bool = false
149+
private var block1 = DispatchWorkItem { }
150+
private var block2 = DispatchWorkItem { }
153151
func setKeyboardCapsLock(enabled: Bool) {
154-
debug("\(enabled)")
152+
debug("enabled: \(enabled) (state: \(state))")
155153

156-
block.cancel()
157-
block = DispatchWorkItem {
158-
let hid = IOHIDManagerCreate(kCFAllocatorDefault, 0)
154+
/** HIS_XPC: Caps Lock 상태는 늘 false */
155+
block1.cancel()
156+
block1 = DispatchWorkItem {
157+
debug("HIS_XPC_SetCapsLockModifierState")
158+
HIS_XPC_SetCapsLockModifierState(false)
159+
}
159160

160-
/** HID 키보드 찾기 */
161+
/** HIS_XPC: Sonoma 이후 커서 밑에 생기는 "버블"/HUD/Indicator/Accessory 방지 */
162+
for delay in stride(from: 0, to: 200, by: 20) {
163+
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(delay), execute: block1)
164+
}
165+
166+
block2.cancel()
167+
block2 = DispatchWorkItem {
168+
/** HID: 키보드 찾기 */
169+
let hid = IOHIDManagerCreate(kCFAllocatorDefault, 0)
161170
IOHIDManagerSetDeviceMatching(hid, [
162171
kIOHIDDeviceUsagePageKey: kHIDPage_GenericDesktop, // Generic Desktop Page (0x01)
163172
kIOHIDDeviceUsageKey: kHIDUsage_GD_Keyboard // Keyboard (0x06, Collection Application)
@@ -174,7 +183,7 @@ func setKeyboardCapsLock(enabled: Bool) {
174183
}
175184

176185
for dev in devs {
177-
/** Caps Lock 상태 */
186+
/** HID: Caps Lock 상태는 늘 false */
178187
let serv = IOHIDDeviceGetService(dev)
179188
var conn = io_connect_t()
180189

@@ -184,14 +193,14 @@ func setKeyboardCapsLock(enabled: Bool) {
184193
}
185194
defer { IOServiceClose(conn) }
186195

187-
guard IOHIDSetModifierLockState(conn, Int32(kIOHIDCapsLockState), enabled) == KERN_SUCCESS else {
196+
guard IOHIDSetModifierLockState(conn, Int32(kIOHIDCapsLockState), false) == KERN_SUCCESS else {
188197
warning("IOHIDSetModifierLockState 실패: \(conn)")
189198
continue
190199
}
191200

192201
debug("IOHIDSetModifierLockState 성공: \(dev)")
193202

194-
/** Caps Lock LED */
203+
/** HID: Caps Lock LED */
195204
guard let elems = IOHIDDeviceCopyMatchingElements(dev, [
196205
kIOHIDElementUsagePageKey: kHIDPage_LEDs, // LED Page (0x08)
197206
kIOHIDElementUsageKey: kHIDUsage_LED_CapsLock // Caps Lock (0x02)
@@ -212,30 +221,13 @@ func setKeyboardCapsLock(enabled: Bool) {
212221
debug("IOHIDDeviceSetValue 성공: \(dev)")
213222
}
214223
}
224+
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100), execute: block2)
215225

216-
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200), execute: block)
217-
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300), execute: block)
226+
state = enabled
218227
}
219228

220229
func getKeyboardCapsLock() -> Bool {
221-
debug()
222-
223-
var conn = io_connect_t()
224-
let serv = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching(kIOHIDSystemClass))
225-
226-
guard IOServiceOpen(serv, mach_task_self_, UInt32(kIOHIDParamConnectType), &conn) == KERN_SUCCESS else {
227-
warning("IOServiceOpen 실패: \(serv)")
228-
return false
229-
}
230-
defer { IOServiceClose(conn) }
231-
232-
var enabled = false
233-
guard IOHIDGetModifierLockState(conn, Int32(kIOHIDCapsLockState), &enabled) == KERN_SUCCESS else {
234-
warning("IOHIDGetModifierLockState 실패: \(conn)")
235-
return false
236-
}
237-
238-
debug("IOHIDGetModifierLockState 성공: \(conn) \(enabled)")
230+
debug("state: \(state)")
239231

240-
return enabled
232+
return state
241233
}

0 commit comments

Comments
 (0)