【发布时间】:2014-01-03 05:16:28
【问题描述】:
我正在尝试掌握 IOKit,我觉得我已经很接近了,但还没有。所以请原谅我的困惑。
我设法编写了检测我的 USB 设备的代码(USB 电缆末端的一个简单按钮,它有一个 Windows 驱动程序,但没有 Mac 驱动程序)。
我试图在按下按钮时获得某种回调。
当设备连接到 USB 或移除时,我设法得到回调。现在,我试图找出在按下按钮时如何获得通知,但我无法弄清楚。文档让我很困惑,因为 IOKit 似乎可以同时使用 c++ 和 c,这取决于您访问它的方式(内核扩展或用户空间驱动程序或类似的东西。不确定我有正确的术语。
我尝试添加几个方法来在任何中断值发生更改时获取回调,正如您将在代码中看到的那样。但是什么也没发生。
这是我当前的 AppDelegate.m 文件以及设备上的 USB Probe 信息。
Low Speed device @ 5 (0x14100000): ............................................. Composite device: "DL100B Dream Cheeky Generic Controller"
Port Information: 0x101a
Number Of Endpoints (includes EP0):
Device Descriptor
Configuration Descriptor (current config)
Length (and contents): 34
Number of Interfaces: 1
Configuration Value: 1
Attributes: 0x80 (bus-powered)
MaxPower: 500 mA
Interface #0 - HID
Alternate Setting 0
Number of Endpoints 1
Interface Class: 3 (HID)
Interface Subclass; 0
Interface Protocol: 0
HID Descriptor
Endpoint 0x81 - Interrupt Input
Address: 0x81 (IN)
Attributes: 0x03 (Interrupt)
Max Packet Size: 8
Polling Interval: 10 ms
App Delegate.m 文件:
//
// USBHIDAppDelegate.m
// USBHID
//
// Created by Michael Dolinar on 12-05-02.
// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//
#import "USBHIDAppDelegate.h"
#import "IOKit/hid/IOHIDManager.h"
#include <IOKit/IOKitLib.h>
#include <IOKit/IOCFPlugIn.h>
#include <IOKit/usb/IOUSBLib.h>
#include <IOKit/usb/USBSpec.h>
@implementation USBHIDAppDelegate
@synthesize window = _window;
// New USB device specified in the matching dictionary has been added (callback function)
static void Handle_DeviceMatchingCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
// Retrieve the device name & serial number
NSString *devName = [NSString stringWithUTF8String:
CFStringGetCStringPtr(
IOHIDDeviceGetProperty(inIOHIDDeviceRef,
CFSTR("Product")),
kCFStringEncodingMacRoman)];
UInt32 serialString = CFStringGetCStringPtr(
IOHIDDeviceGetProperty(inIOHIDDeviceRef,
CFSTR("SerialNumber")),
kCFStringEncodingMacRoman);
NSString *devSerialNumber;
if (serialString == 0) {
devSerialNumber = @"No Serial Number";
} else {
devSerialNumber = [NSString stringWithUTF8String:serialString];
}
// Log the device reference, Name, Serial Number & device count
NSLog(@"\nDevice added: %p\nModel: %@\nSerial Number:%@\nDevice count: %ld",
inIOHIDDeviceRef,
devName,
devSerialNumber,
USBDeviceCount(inSender));
//Open the device (Was missing)
IOReturn err = IOHIDDeviceOpen(inIOHIDDeviceRef, 0);
//应该在这里检查错误...
IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, Handle_IOHIDDeviceInputValueCallback, NULL);
//这里还必须再次注册RunLoop...也不见了 IOHIDDeviceScheduleWithRunLoop(inIOHIDDeviceRef, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
}
static void Handle_IOHIDDeviceInputValueCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDValueRef inIOHIDValueRef
)
{
NSLog(@"Value changed");
}
// USB device specified in the matching dictionary has been removed (callback function)
static void Handle_DeviceRemovalCallback(void *inContext,
IOReturn inResult,
void *inSender,
IOHIDDeviceRef inIOHIDDeviceRef){
// Log the device ID & device count
NSLog(@"\nDevice removed: %p\nDevice count: %ld",
(void *)inIOHIDDeviceRef,
USBDeviceCount(inSender));
IOHIDDeviceRegisterInputValueCallback(inIOHIDDeviceRef, NULL, NULL); //Remove callback
}
// Counts the number of devices in the device set (incudes all USB devices that match our dictionary)
static long USBDeviceCount(IOHIDManagerRef HIDManager){
// The device set includes all USB devices that match our matching dictionary. Fetch it.
CFSetRef devSet = IOHIDManagerCopyDevices(HIDManager);
// The devSet will be NULL if there are 0 devices, so only try to count the devices if devSet exists
if(devSet) return CFSetGetCount(devSet);
// There were no matching devices (devSet was NULL), so return a count of 0
return 0;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
SInt32 idVendor = 0x1D34;//0x062A;//0x1d34; //0x1AAD; //// set vendor id
SInt32 idProduct = 0x000D;//0x0000;//0x000d; //0x000F; //// set product id
// Create an HID Manager
IOHIDManagerRef HIDManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
// Create a Matching Dictionary
CFMutableDictionaryRef matchDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
// Specify a device manufacturer in the Matching Dictionary
CFDictionarySetValue(matchDict,
CFSTR(kIOHIDVendorIDKey),
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type, &idVendor));
CFDictionarySetValue(matchDict,
CFSTR(kIOHIDProductKey),
CFNumberCreate(kCFAllocatorDefault,
kCFNumberSInt32Type, &idProduct));
// Register the Matching Dictionary to the HID Manager
IOHIDManagerSetDeviceMatching(HIDManager, matchDict);
// Register a callback for USB device detection with the HID Manager
IOHIDManagerRegisterDeviceMatchingCallback(HIDManager, &Handle_DeviceMatchingCallback, NULL);
// Register a callback fro USB device removal with the HID Manager
IOHIDManagerRegisterDeviceRemovalCallback(HIDManager, &Handle_DeviceRemovalCallback, NULL);
// Register the HID Manager on our app’s run loop
IOHIDManagerScheduleWithRunLoop(HIDManager, CFRunLoopGetMain(), kCFRunLoopDefaultMode);
// Open the HID Manager
IOReturn IOReturn = IOHIDManagerOpen(HIDManager, kIOHIDOptionsTypeNone);
if(IOReturn) NSLog(@"IOHIDManagerOpen failed."); // Couldn't open the HID manager! TODO: proper error handling
}
@end
我什至不确定设备是否正在发送任何内容...我尝试在第 7 级使用 USB 记录器进行记录,但仅按下按钮似乎没有显示任何内容...我如何确保它是实际工作?
更新:能够使用 this Ruby Open Source project 检测按钮按下,用于我用来学习这一点的 BigRedButton。所以我知道它确实有效。 我还重新编写了代码以仅在实际检测到设备时注册值更改,并在移除设备时将其移除。此时仍然没有。
更新 2:让它工作!两个问题...我没有打开设备进行阅读,也没有在 Current RunLoop 上注册设备本身,这也是必需的。来自 WWDC 2011 的有关 Userland 设备访问的精彩 WWDC 视频提供了很大帮助。我还不得不说,我使用的 BigRedBUtton 可能不是一个标准设备,并且从未按计划工作,但我想使用的实际设备就像一个魅力,并且正在给我输入!所以现在一切都很好,感谢 WWDC 视频!
【问题讨论】:
-
我实际上使用的代码块与 Michael Dolinars 教程中的代码块相同。您能否发布或发送您打开设备(不仅仅是 HID 管理器)然后将其添加到运行循环中的代码块?这就是我自己目前陷入的困境。
-
实际上,我看到发生了什么,你的代码块被分解了,它的某些部分看起来像文本。