macos - 如果设备自启动后插入,IOHIDDeviceRegisterInputValueCallback 将失败

标签 macos cocoa usb hid iokit

我正在尝试使用 IOKit 与游戏 Controller 进行通信,特别是我希望使用 IOHIDDeviceRegisterInputValueCallback 收到值更改的通知。我的代码可以工作,除非设备自 Mac 启动以来就已插入且从未拔出。在这种情况下,IOHIDDeviceOpen 仍然会成功,但永远不会调用值回调。如果我尝试使用 IOHIDDeviceGetValue 获取值,它不会报告错误,但我获取的整数值全为零,这是不正确的。

如果我拔下设备并重新插回,程序就会开始获取值回调。

我能做些什么来解决这个问题,还是我应该责怪硬件?

也许有某种方法可以在软件中拔出并重新插入。内核框架引用列出了一个函数 ReEnumerateDevice ,听起来它可以做到这一点,但我需要很多关于如何使用它的帮助,如果它甚至可以从非内核代码中实现的话。 p>

static void ValueCallback(
    void *context, 
    IOReturn result, 
    void *sender, 
    IOHIDValueRef value )
{
    IOHIDElementRef theElement = IOHIDValueGetElement( value );
    uint32_t usagePage = IOHIDElementGetUsagePage( theElement );
    uint32_t usage = IOHIDElementGetUsage( theElement );
    IOHIDElementCookie cookie = IOHIDElementGetCookie( theElement );
    IOHIDElementType typeCode = IOHIDElementGetType( theElement );

    CFIndex intValue = IOHIDValueGetIntegerValue( value );
    double physValue = IOHIDValueGetScaledValue( value,
        kIOHIDValueScaleTypePhysical );
    double calibratedValue = IOHIDValueGetScaledValue( value,
        kIOHIDValueScaleTypeCalibrated );

    NSLog(@"Element %@ (0x%X, 0x%X, %p, type %d) changed to %d (%f, %f)",
        theElement, (int)usagePage, (int)usage, cookie, (int) typeCode,
        (int)intValue, physValue, calibratedValue );
}

static void DeviceMatchingCallback(
    void *context,
    IOReturn result, 
    void *sender, 
    IOHIDDeviceRef device )
{
    NSLog( @"Added device %@", device );
    IOHIDDeviceScheduleWithRunLoop( device, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
    IOReturn err = IOHIDDeviceOpen( device, kIOHIDOptionsTypeNone );
    NSLog(@"IOHIDDeviceOpen result 0x%08X", err );
    IOHIDDeviceRegisterInputValueCallback( device, ValueCallback, context );

    // Let's see if I can get elements and values.
    CFArrayRef elementArray = IOHIDDeviceCopyMatchingElements( device,
        NULL, 0 );
    if ( elementArray != NULL )
    {
        NSArray* elArray = (NSArray*)elementArray;
        for (id oneEl in elArray)
        {
            IOHIDElementRef anElement = (IOHIDElementRef) oneEl;
            IOHIDElementType elType = IOHIDElementGetType( anElement );
            NSLog(@"Element type %d", (int)elType);
            if ( (elType == 1) || (elType == 2) || (elType == 3) )
            {
                IOHIDElementCookie theCookie =
                    IOHIDElementGetCookie( anElement );
                CFIndex val = -1;
                IOHIDValueRef valueRef = NULL;
                err = IOHIDDeviceGetValue( device, anElement, &valueRef );
                if (err == kIOReturnSuccess)
                {
                    val = IOHIDValueGetIntegerValue( valueRef );
                    NSLog(@"  cookie %p, value %ld", theCookie, val );
                }
                else
                {
                    NSLog(@"  cookie %p, error getting value 0x%08X",
                        theCookie, err );
                }
            }
        }
    }

}

static void DeviceRemovalCallback(
    void *context, 
    IOReturn result, 
    void *sender, 
    IOHIDDeviceRef device )
{
    NSLog( @"Removed device %@", device );
    IOHIDDeviceUnscheduleFromRunLoop( device, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
}

@implementation AppDelegate

@synthesize window = _window;

- (void)dealloc
{
    if (_hidManager != NULL)
    {
        CFRelease( _hidManager );
    }

    [super dealloc];
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
    _hidManager = IOHIDManagerCreate( NULL, 0 );

    IOHIDManagerSetDeviceMatchingMultiple( _hidManager, (CFArrayRef) @[
        @{ @(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
            @(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_Joystick)
        },
        @{ @(kIOHIDDeviceUsagePageKey): @(kHIDPage_GenericDesktop),
            @(kIOHIDDeviceUsageKey): @(kHIDUsage_GD_GamePad)
        }
        ] );

    IOHIDManagerRegisterDeviceMatchingCallback( _hidManager,
        DeviceMatchingCallback, self );
    IOHIDManagerRegisterDeviceRemovalCallback( _hidManager,
        DeviceRemovalCallback, self );

    IOHIDManagerScheduleWithRunLoop( _hidManager, CFRunLoopGetMain(),
        kCFRunLoopDefaultMode );
}

@end

最佳答案

看起来操作系统在启动期间会自动卸载设备(因为未使用)

<小时/>

当您断开(并再次插入)设备时,操作系统将加载设备...

<小时/>

来自documentation ,根据驱动程序开发中使用的命令行工具,您可以使用:

kextload

Loads a kernel extension (such as device driver) or generates a statically linked symbol file for remote debugging.

kextunload

Unloads a kernel extension (if possible).

<小时/>

另一件事可能对您有帮助:

Driver Loading

After all drivers have probed the device, the one with the highest probe score is attached and its startfunction, which must be implemented by all drivers, is invoked. The start function initializes the device hardware and prepares it for operation. If the driver succeeds in starting, it returns true; the remaining candidate driver instances are discarded and the driver that started successfully continues operating. If the driver cannot initialize the hardware it must leave the hardware in the state it was in when start was invoked and return false. The failing driver is then detached and discarded, and the candidate driver with the next highest probe score is given a chance to start.

Some time after this occurs, all loaded drivers that are not currently in use are unloaded.

总结 this page也可能对你有帮助

关于macos - 如果设备自启动后插入,IOHIDDeviceRegisterInputValueCallback 将失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47599103/

相关文章:

macos - Visual Studio 2015 Mac 代理未连接到 Macbook

macos - 找不到符号 : _OBJC_CLASS_$_NSObject

cocoa - 对 NSOutlineView 中的删除键使用react的适当方法是什么

objective-c - 没有 BWToolkit 的首选项工具栏

c# - 用C#通过串口发送一个64字节的数据包

.net - mac/linux `dotnet build` 找不到框架 ".NETFramework.."的引用程序集

macos - 有关 gdb 内存访问投诉的详细信息

Swift Calendar 类返回错误的工作日日期

linux - 如果设备已经连接,udev ignore_device 将无法工作

javax.usb.UsbException : Properties file javax. 未找到 usb.properties