在 GUI 应用程序中使用 runloop 调度 IOHIDManager
Scheduling IOHIDManager with runloop in a GUI App
我正在编写一个应用程序,用于监控 swift 中游戏手柄的输入。
我设法构建了一个具有预期行为的命令行应用程序:
import Foundation
import IOKit.hid
var valueCallback : IOHIDValueCallback = {
(context, result, sender, value) in
let element = IOHIDValueGetElement(value)
print(IOHIDElementGetUsage(element), IOHIDValueGetIntegerValue(value))
}
var attachCallback : IOHIDDeviceCallback = {
(context, result, sender, device) in
IOHIDDeviceOpen(device, IOOptionBits(kIOHIDOptionsTypeSeizeDevice))
IOHIDDeviceRegisterInputValueCallback(device, valueCallback, context)
print("Controller attached")
}
var detachCallback : IOHIDDeviceCallback = {
(context, result, sender, device) in
print("Controller detached")
}
class HID {
let manager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
let devices = [kIOHIDTransportKey: "Bluetooth"] as CFDictionary
init() {
IOHIDManagerSetDeviceMatching(self.manager, self.devices)
IOHIDManagerRegisterDeviceMatchingCallback(self.manager, attachCallback, nil)
IOHIDManagerRegisterDeviceRemovalCallback(self.manager, detachCallback, nil)
IOHIDManagerScheduleWithRunLoop(self.manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)
IOHIDManagerOpen(self.manager, IOOptionBits(kIOHIDOptionsTypeNone))
}
}
var hidTest = HID()
CFRunLoopRun()
然后我想在实际的应用程序中使用它,但它无法按预期工作。我对 class 和回调使用了相同的代码,并在 AppDelegate 中尝试了这个:
import Cocoa
import SwiftUI
import AppKit
import IOKit.hid
import Foundation
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = ContentView()
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.isReleasedWhenClosed = false
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
let hidTest = HID()
CFRunLoopRun()
}
}
编译一切正常,但我无法从游戏手柄获得任何值。我认为问题在于:IOHIDManagerScheduleWithRunLoop(self.manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)
因为管理器可能没有附加到应用程序的 RunLoop。
我需要做些什么才能完成这项工作吗?
提前致谢!
我不是 Swift 专家,但我知道 IOKit 和 运行 循环,所以我会尝试回答。
我认为对 CFRunLoopRun()
的调用可能存在问题。 Cocoa 个应用程序已经 运行 在 运行 循环中,该循环由 NSApplication
隐式创建并 运行。不要显式 运行 运行 循环,只允许 applicationDidFinishLaunching
到 return.
执行此操作时,您可能应该使 HID 对象成为应用程序对象或类似对象的成员,否则它将被销毁。我不确定 IOKit 的 Swift 绑定是否执行任何自动资源销毁;如果是这样,这可能会破坏 HID 管理器对象,您可能希望它在应用程序的生命周期内保持活动状态。
我正在编写一个应用程序,用于监控 swift 中游戏手柄的输入。 我设法构建了一个具有预期行为的命令行应用程序:
import Foundation
import IOKit.hid
var valueCallback : IOHIDValueCallback = {
(context, result, sender, value) in
let element = IOHIDValueGetElement(value)
print(IOHIDElementGetUsage(element), IOHIDValueGetIntegerValue(value))
}
var attachCallback : IOHIDDeviceCallback = {
(context, result, sender, device) in
IOHIDDeviceOpen(device, IOOptionBits(kIOHIDOptionsTypeSeizeDevice))
IOHIDDeviceRegisterInputValueCallback(device, valueCallback, context)
print("Controller attached")
}
var detachCallback : IOHIDDeviceCallback = {
(context, result, sender, device) in
print("Controller detached")
}
class HID {
let manager = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
let devices = [kIOHIDTransportKey: "Bluetooth"] as CFDictionary
init() {
IOHIDManagerSetDeviceMatching(self.manager, self.devices)
IOHIDManagerRegisterDeviceMatchingCallback(self.manager, attachCallback, nil)
IOHIDManagerRegisterDeviceRemovalCallback(self.manager, detachCallback, nil)
IOHIDManagerScheduleWithRunLoop(self.manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)
IOHIDManagerOpen(self.manager, IOOptionBits(kIOHIDOptionsTypeNone))
}
}
var hidTest = HID()
CFRunLoopRun()
然后我想在实际的应用程序中使用它,但它无法按预期工作。我对 class 和回调使用了相同的代码,并在 AppDelegate 中尝试了这个:
import Cocoa
import SwiftUI
import AppKit
import IOKit.hid
import Foundation
@main
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentView = ContentView()
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.isReleasedWhenClosed = false
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
let hidTest = HID()
CFRunLoopRun()
}
}
编译一切正常,但我无法从游戏手柄获得任何值。我认为问题在于:IOHIDManagerScheduleWithRunLoop(self.manager, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue)
因为管理器可能没有附加到应用程序的 RunLoop。
我需要做些什么才能完成这项工作吗? 提前致谢!
我不是 Swift 专家,但我知道 IOKit 和 运行 循环,所以我会尝试回答。
我认为对 CFRunLoopRun()
的调用可能存在问题。 Cocoa 个应用程序已经 运行 在 运行 循环中,该循环由 NSApplication
隐式创建并 运行。不要显式 运行 运行 循环,只允许 applicationDidFinishLaunching
到 return.
执行此操作时,您可能应该使 HID 对象成为应用程序对象或类似对象的成员,否则它将被销毁。我不确定 IOKit 的 Swift 绑定是否执行任何自动资源销毁;如果是这样,这可能会破坏 HID 管理器对象,您可能希望它在应用程序的生命周期内保持活动状态。