我尝试使用IOKit与游戏控制器进行通信,特别是我希望使用IOHIDDeviceRegisterInputValueCallback
通知值更改。我的代码有效,除非设备已插入,因为Mac已启动且从未拔下插头。在这种情况下,IOHIDDeviceOpen
仍然成功,但永远不会调用值回调。如果我尝试使用IOHIDDeviceGetValue
获取值,它会报告没有错误,但我得到的整数值都是零,这是不正确的。
如果我拔下设备并将其重新插回,程序就会开始获取值回调。
我能做些什么来解决这个问题,还是应该责怪硬件呢?
也许有某种方法可以在软件中拔掉插头。内核框架参考列出了一个函数ReEnumerateDevice
,它听起来像是这样做的,但如果它甚至可能来自非内核代码,我需要很多关于如何使用它的帮助
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
答案 0 :(得分:-1)
在启动过程中看起来操作系统会自动卸载设备(因为未使用)
当您断开连接(并再次插入)设备时,操作系统将加载设备......
从documentation开始,根据驱动程序开发中使用的命令行工具,您可以使用:
kextload
加载内核扩展(例如设备驱动程序)或生成 用于远程调试的静态链接符号文件。
和
kextunload
卸载内核扩展(如果可能)。
可能有助于你的另一件事:
驱动程序加载
在所有驱动程序探测到设备后,将附加具有最高探测分数的驱动程序,并调用其必须由所有驱动程序实现的startfunction。 start函数初始化设备硬件并准备运行。如果驱动程序成功启动,则返回true;丢弃剩余的候选驱动程序实例,并且成功启动的驱动程序继续运行。 如果驱动程序无法初始化硬件,则必须使硬件处于调用start时所处的状态并返回false。然后分离并丢弃失败的驱动程序,并使用下一个最高的候选驱动程序探究得分有机会开始。
发生这种情况后的一段时间,将卸载当前未使用的所有已加载驱动程序。
总结this page也可能对您有所帮助