Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Cocoa
- import Foundation
- import IOKit.hid
- //Struct to store vendor and product ID of the device to be recognized
- public struct HIDMonitorData {
- public let vendorId:Int
- public let productId:Int
- public init (vendorId:Int, productId:Int) {
- self.vendorId = vendorId
- self.productId = productId
- }
- }
- //Struct to save all data of the HID-Device
- public struct HIDDevice {
- public let id:String
- public let vendorId:Int
- public let productId:Int
- public let reportSize:Int
- public let device:IOHIDDevice
- public let name:String
- public init(device:IOHIDDevice) {
- self.device = device
- //Get all Data from IOKit
- self.id = IOHIDDeviceGetProperty(self.device, kIOHIDLocationIDKey as CFString) as? String ?? ""
- self.name = IOHIDDeviceGetProperty(device, kIOHIDProductKey as CFString) as? String ?? ""
- self.vendorId = IOHIDDeviceGetProperty(self.device, kIOHIDVendorIDKey as CFString) as? Int ?? 0
- self.productId = IOHIDDeviceGetProperty(self.device, kIOHIDProductIDKey as CFString) as? Int ?? 0
- self.reportSize = IOHIDDeviceGetProperty(self.device, kIOHIDMaxInputReportSizeKey as CFString) as? Int ?? 0
- }
- }
- //Class that monitors IOKit Inputs
- open class HIDDeviceMonitor: NSObject {
- public let vp:[HIDMonitorData]
- public let reportSize:Int
- public var senderList: [String]
- //Initialize with Data of desired Device
- public init(_ vp:[HIDMonitorData], reportSize:Int) {
- self.vp = vp
- self.reportSize = reportSize
- self.senderList = []
- }
- open func start() {
- print("ready")
- //Create IOHIDManager Object for managing HID devices
- let managerRef = IOHIDManagerCreate(kCFAllocatorDefault, IOOptionBits(kIOHIDOptionsTypeNone))
- var deviceMatches:[[String:Any]] = []
- for vp in self.vp {
- deviceMatches.append([kIOHIDProductIDKey: vp.productId, kIOHIDVendorIDKey: vp.vendorId])
- }
- //Set matching criteria to only get notified with desired device
- IOHIDManagerSetDeviceMatchingMultiple(managerRef, deviceMatches as CFArray)
- //Schedule HID Manager with current run loop
- IOHIDManagerScheduleWithRunLoop(managerRef, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue);
- //Opens all Current and Future HID Devices
- IOHIDManagerOpen(managerRef, IOOptionBits(kIOHIDOptionsTypeNone));
- //Callback Function for Device Match
- let matchingCallback:IOHIDDeviceCallback = { inContext, inResult, inSender, inIOHIDDeviceRef in
- let this:HIDDeviceMonitor = unsafeBitCast(inContext, to: HIDDeviceMonitor.self)
- this.rawDeviceAdded(inResult, inSender: inSender!, inIOHIDDeviceRef: inIOHIDDeviceRef)
- }
- //Callback Function for Device Removed
- let removalCallback:IOHIDDeviceCallback = { inContext, inResult, inSender, inIOHIDDeviceRef in
- let this:HIDDeviceMonitor = unsafeBitCast(inContext, to: HIDDeviceMonitor.self)
- this.rawDeviceRemoved(inResult, inSender: inSender!, inIOHIDDeviceRef: inIOHIDDeviceRef)
- }
- //Register a Callback when a device is matching the criteria above
- IOHIDManagerRegisterDeviceMatchingCallback(managerRef, matchingCallback, unsafeBitCast(self, to: UnsafeMutableRawPointer.self))
- //Register a Callback when a device that is matching the criteria is removed
- IOHIDManagerRegisterDeviceRemovalCallback(managerRef, removalCallback, unsafeBitCast(self, to: UnsafeMutableRawPointer.self))
- RunLoop.current.run();
- }
- //Is called in input callback function
- open func read(_ inResult: IOReturn, inSender: UnsafeMutableRawPointer, type: IOHIDReportType, reportId: UInt32, report: UnsafeMutablePointer<UInt8>, reportLength: CFIndex) {
- let data = Data(bytes: UnsafePointer<UInt8>(report), count: reportLength)
- var playerIndex = 0
- //Distinguishing between two similar controllers. Bit dirty via Pointer Address
- //First Controller to input data is Player 0, next is player 1, ...
- if (!senderList.contains(inSender.debugDescription)) {
- senderList.append(inSender.debugDescription)
- }
- playerIndex = senderList.index(of: inSender.debugDescription)!
- let count = data.count / MemoryLayout<UInt8>.size
- var array = [UInt8](repeating: 0, count: count)
- data.copyBytes(to: &array, count:count * MemoryLayout<UInt8>.size)
- //print(array)
- if (array == [128,128,0]) {
- print("Player \(playerIndex): No Buttons Pressed")
- return
- }
- //Do Stuff with Device Data. For demo, just print Commands:
- var resultArray: [String] = []
- //Y-Axis
- switch array[0] {
- case 255:
- resultArray.append("Left")
- case 0:
- resultArray.append("Right")
- case 128:
- break
- default:
- print("Unexpected Value")
- }
- //X-Axis
- switch array[1] {
- case 255:
- resultArray.append("Up")
- case 0:
- resultArray.append("Down")
- case 128:
- break
- default:
- print("Unexpected Value")
- }
- //Buttons
- var buttonInt = array[2]
- if (buttonInt >= 8) {
- resultArray.append("Button Small Left")
- buttonInt = buttonInt - 8
- }
- if (buttonInt >= 4) {
- resultArray.append("Button Small Right")
- buttonInt = buttonInt - 4
- }
- if (buttonInt >= 2) {
- resultArray.append("Button Big Left")
- buttonInt = buttonInt - 2
- }
- if (buttonInt >= 1) {
- resultArray.append("Button Big Right")
- buttonInt = buttonInt - 1
- }
- print("Player \(playerIndex): \(resultArray)")
- }
- //Is executed in Device Match Callback
- open func rawDeviceAdded(_ inResult: IOReturn, inSender: UnsafeMutableRawPointer, inIOHIDDeviceRef: IOHIDDevice!) {
- //Get Device Data
- let device = HIDDevice(device:inIOHIDDeviceRef)
- // Create memory chunk with reportSize
- let report = UnsafeMutablePointer<UInt8>.allocate(capacity: reportSize)
- //Callback Function on Input Report
- let inputCallback : IOHIDReportCallback = { inContext, inResult, inSender, type, reportId, report, reportLength in
- let this:HIDDeviceMonitor = unsafeBitCast(inContext, to: HIDDeviceMonitor.self)
- this.read(inResult, inSender: inSender!, type: type, reportId: reportId, report: report, reportLength: reportLength)
- }
- //Hook up inputcallback when device issues a report
- IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef!, report, reportSize, inputCallback, unsafeBitCast(self, to: UnsafeMutableRawPointer.self))
- print("HID Device Recognized: \(device.name)")
- }
- //Callback: Removed Matched Device
- open func rawDeviceRemoved(_ inResult: IOReturn, inSender: UnsafeMutableRawPointer, inIOHIDDeviceRef: IOHIDDevice!) {
- let device = HIDDevice(device:inIOHIDDeviceRef)
- print("HID Device Removed: \(device.name)")
- //Reset Sender List for Player Recognition
- senderList = []
- }
- }
- let rfDeviceMonitor = HIDDeviceMonitor([
- HIDMonitorData(vendorId: 0x040b, productId: 0x6533)
- ], reportSize: 64)
- rfDeviceMonitor.start()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement