【问题标题】:Scheduling IOHIDManager with runloop in a GUI App在 GUI 应用程序中使用 runloop 调度 IOHIDManager
【发布时间】:2021-03-26 12:29:03
【问题描述】:

我正在编写一个应用程序,它可以快速监控来自游戏手柄的输入。 我设法构建了一个具有预期行为的命令行应用程序:

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()

然后我想在实际应用程序中使用它,但它不能按预期工作。我对类和回调使用了相同的代码,并在 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 macos swiftui hid iokit


    【解决方案1】:

    我不是 Swift 专家,但我知道 IOKit 和 runloops,所以我会尝试回答。

    我认为调用CFRunLoopRun() 可能存在问题。 Cocoa 应用程序已经在由NSApplication 隐式创建和运行的 runloop 中运行。不要显式运行runloop,只允许applicationDidFinishLaunching返回。

    当您这样做时,您可能应该让您的 HID 对象成为您的应用程序对象或类似对象的成员,否则它将被销毁。我不确定 IOKit 的 Swift 绑定是否执行任何自动资源销毁;如果是这样,这可能会破坏 HID 管理器对象,您可能希望在应用程序的生命周期内保持活动状态。

    【讨论】:

    • 该对象必须在 appDidFinishLaunching 之外声明,所以现在它工作正常并且确实不需要CFRunLoopRun()。对于尝试做同样事情的人来说,沙盒化应用程序仍然允许使用 IOKit,但要获得 HID 支持,您奇怪地需要启用 USB(即使您的游戏手柄是无线的)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-09-16
    • 1970-01-01
    • 2014-07-25
    • 1970-01-01
    • 1970-01-01
    • 2021-10-07
    相关资源
    最近更新 更多