IOHIDTestConnectionFilterWrapper.m   [plain text]


//
//  IOHIDTestConnectionFilter.m
//  IOHIDTestConnectionFilter
//
//  Created by Abhishek Nayyar on 3/28/18.
//

#include <CoreFoundation/CoreFoundation.h>
#if COREFOUNDATION_CFPLUGINCOM_SEPARATE
#include <CoreFoundation/CFPlugInCOM.h>
#endif

#include <IOKit/hid/IOHIDEventSystemConnection.h>
#include <IOKit/hid/IOHIDConnectionFilterPlugIn.h>
#include "IOHIDTestConnectionFilter.h"
#include <os/log.h>

void * IOHIDTestConnectionFilterFactory (CFAllocatorRef allocator, CFUUIDRef typeUUID);
static HRESULT _QueryInterface (void *self, REFIID iid, LPVOID *ppv);
static ULONG _AddRef (void *self);
static ULONG _Release (void *self);
static CFTypeRef _copyProperty (void * self, CFStringRef key);
static bool _setProperty (void * self, CFStringRef key, CFTypeRef property);
static IOHIDEventRef _filter(void * self, IOHIDEventRef event);

// The IOHIDNXEventTranslatorServiceFilter function table.
IOHIDConnectionFilterPlugInInterface  __ftbl =
{
    // Required padding for COM
    NULL,
    // These three are the required COM functions
    _QueryInterface,
    _AddRef,
    _Release,
    // IOHIDSimpleConnectionFilterPlugInInterface functions
    _filter,
    // IOHIDConnectionFilterPlugInInterface functions
    NULL,//activate
    NULL,//cancel
    NULL,//setDispatchQueue
    NULL,//setCancelHandler
    _copyProperty,
    _setProperty,
};

@interface HIDTestConnectionFilterWrapper : HIDTestConnectionFilter {

    IOHIDConnectionFilterPlugInInterface  _ftbl;
@public
    IOHIDConnectionFilterPlugInInterface  *_ftblPrt;
}
@end

@implementation HIDTestConnectionFilterWrapper
-(nullable instancetype) init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    
    _ftbl = __ftbl;
    _ftbl._reserved = self;
    _ftblPrt = &_ftbl;
    return self;
}
@end

static HRESULT _QueryInterface (void *self, REFIID iid, LPVOID *ppv)
{
    // Create a CoreFoundation UUIDRef for the requested interface.
    CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes( NULL, iid );
    // Test the requested ID against the valid interfaces.
    if (CFEqual(interfaceID, kIOHIDConnectionFilterPlugInInterfaceID)) {
        _AddRef(self);
        *ppv = self;
        CFRelease(interfaceID);
        return S_OK;
    }
    // Requested interface unknown, bail with error.
    *ppv = NULL;
    CFRelease (interfaceID);
    return E_NOINTERFACE;
}

static ULONG _AddRef (void *self)
{
    NSObject * obj = (*(IUnknownVTbl **) self)->_reserved;
    [obj retain];
    return (ULONG) [obj retainCount];
}
static ULONG _Release (void *self)
{
    NSObject * obj = (*(IUnknownVTbl **) self)->_reserved;
    NSUInteger result = [obj retainCount];
    [obj release];
    return (ULONG)--result;
}
static CFTypeRef _copyProperty (void * self, CFStringRef key)
{
    HIDTestConnectionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return false;
    }
    
    return CFBridgingRetain([obj copyProperty:(__bridge NSString*)key]);
}
static bool _setProperty (void * self, CFStringRef key, CFTypeRef property)
{
    HIDTestConnectionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return false;
    }
    
    return [obj setProperty:(__bridge NSString*)key property:(__bridge id)property];
}
static IOHIDEventRef _filter(void * self, IOHIDEventRef event)
{
    HIDTestConnectionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return NULL;
    }
    
    return [obj filter:event];
}
//------------------------------------------------------------------------------
// IOHIDTestConnectionFilterFactory
//------------------------------------------------------------------------------
// Implementation of the factory function for this type.
void * IOHIDTestConnectionFilterFactory (CFAllocatorRef allocator __unused, CFUUIDRef typeUUID)
{
    // If correct type is being requested, allocate an
    // instance of TestType and return the IUnknown interface.
    if (CFEqual(typeUUID, kIOHIDConnectionFilterPlugInTypeID)) {
        HIDTestConnectionFilterWrapper * obj = [[HIDTestConnectionFilterWrapper alloc] init];
        if (obj) {
            return (void *)&obj->_ftblPrt;
        }
        return NULL;
    }
    // If the requested type is incorrect, return NULL.
    return NULL;
}