IOHIDDisplaySessionFilterWrapper.m   [plain text]


//
//  IOHIDDisplaySessionFilterWrapper.m
//  IOHIDDisplaySessionFilter
//
//  Created by AB on 1/25/19.
//

#import <Foundation/Foundation.h>
#include <CoreFoundation/CoreFoundation.h>
#if COREFOUNDATION_CFPLUGINCOM_SEPARATE
#include <CoreFoundation/CFPlugInCOM.h>
#endif
#include <IOKit/hid/IOHIDSessionFilterPlugIn.h>
#include <IOKit/hid/IOHIDEventSystemKeys.h>
#include "IOHIDDisplaySessionFilter.h"

//82A14D6D-0138-4DE2-8784-A2DBEEB6A100
#define kIOHIDDisplaySessionFilterFactory CFUUIDGetConstantUUIDWithBytes(kCFAllocatorSystemDefault, 0x82, 0xA1, 0x4D, 0x6D, 0x01, 0x38, 0x4D, 0xE2, 0x87, 0x84, 0xA2, 0xDB, 0xEE, 0xB6, 0xA1, 0x00)

void * IOHIDDisplaySessionFilterFactory (CFAllocatorRef allocator, CFUUIDRef typeUUID);
static HRESULT _QueryInterface (void *self, REFIID iid, LPVOID *ppv);
static ULONG _AddRef (void *self);
static ULONG _Release (void *self);
static boolean_t _open (void * self, IOHIDSessionRef session, IOOptionBits options);
static void _close (void * self, IOHIDSessionRef session, IOOptionBits options);
static CFTypeRef _getPropertyForClient(void * self, CFStringRef key, CFTypeRef client);

IOHIDSessionFilterPlugInInterface sIOHIDDisplaySessionFilterFtbl =
{
    // Required padding for COM
    NULL,
    // These three are the required COM functions
    _QueryInterface,
    _AddRef,
    _Release,
    // IOHIDSimpleSessionFilterPlugInInterface functions
    NULL,
    NULL,
    NULL,
    // IOHIDSessionFilterPlugInInterface functions
    _open,
    _close,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    _getPropertyForClient,
    NULL,
};


@interface HIDDisplaySessionFilterWrapper : HIDDisplaySessionFilter {
    IOHIDSessionFilterPlugInInterface _ftbl;
    CFUUIDRef _factoryID;
    @public
    IOHIDSessionFilterPlugInInterface *_ftblPtr;
}
-(nullable instancetype) initWithFactoryID:(CFUUIDRef) factoryID;
@end

@implementation HIDDisplaySessionFilterWrapper

-(nullable instancetype) initWithFactoryID:(CFUUIDRef __nonnull) factoryID
{
    self = [super init];
    if (!self) {
        return nil;
    }
    _ftbl = sIOHIDDisplaySessionFilterFtbl;
    _ftbl._reserved = self;
    _ftblPtr = &_ftbl;
    _factoryID = factoryID;
    CFPlugInAddInstanceForFactory(_factoryID);
    return self;
}

-(void) dealloc
{
    CFPlugInRemoveInstanceForFactory(_factoryID);
    CFRelease(_factoryID);
    [super dealloc];
}

@end

// Non interface functions
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, kIOHIDSimpleSessionFilterPlugInInterfaceID) || CFEqual(interfaceID, kIOHIDSessionFilterPlugInInterfaceID)) {
        _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 boolean_t _open (void * self, IOHIDSessionRef __unused session, IOOptionBits __unused options)
{
    HIDDisplaySessionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return false;
    }
    
    return [obj open];
    
}

static void _close (void * self, IOHIDSessionRef __unused session, IOOptionBits __unused options)
{
    HIDDisplaySessionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return;
    }
    
    return [obj close];
}

static CFTypeRef _getPropertyForClient(void * self, CFStringRef __unused key, CFTypeRef __unused client)
{
    HIDDisplaySessionFilterWrapper * obj = (*(IUnknownVTbl **) self)->_reserved;
    if (!obj) {
        return NULL;
    }
    if (CFEqual(key, CFSTR(kIOHIDSessionFilterDebugKey))) {
        return CFBridgingRetain([obj getProperty]);
    }
    
    return NULL;
}

void * IOHIDDisplaySessionFilterFactory (CFAllocatorRef __unused allocator, CFUUIDRef typeUUID)
{
    // If correct type is being requested, allocate an
    // instance of TestType and return the IUnknown interface.
    if (CFEqual(typeUUID, kIOHIDSessionFilterPlugInTypeID)) {
        HIDDisplaySessionFilterWrapper * obj = [[HIDDisplaySessionFilterWrapper alloc] initWithFactoryID:kIOHIDDisplaySessionFilterFactory];
        if (obj) {
            return (void *)&obj->_ftblPtr;
        }
        return NULL;
    }
    // If the requested type is incorrect, return NULL.
    return NULL;
}