TestIOHIDConnectionFilterPlugIn.m   [plain text]

//
// TestIOHIDConnectionFilterPlugin.m
// IOHIDFamilyUnitTests
//
// Created by Abhishek Nayyar on 3/29/18.
//

#import <XCTest/XCTest.h>
#include <IOKit/hid/IOHIDEventSystemClientPrivate.h>
#include <IOKit/hid/IOHIDEventSystem.h>
#include <IOKit/hid/IOHIDEventSystemPrivate.h>
#include <os/log.h>
#include "IOHIDUnitTestUtility.h"
#include "AppleHIDUsageTables.h"
#include <IOKit/hid/IOHIDServiceKeys.h>
#include <IOKit/hid/IOHIDEvent.h>
#include <IOKit/hid/IOHIDEventData.h>
#include <IOKit/hid/IOHIDEventSystemKeys.h>

#include <IOKit/IOKitLib.h>
#include <IOKit/hidsystem/IOHIDShared.h>
#import "IOHIDUserDeviceTestController.h"
#import "IOHIDUnitTestDescriptors.h"
#include <TargetConditionals.h>

#define kDefaultRunLoopTime 7
#define kUsages "Usages"
#define kUsagePage "UsagePage"

static uint8_t descriptor[] = {
HIDKeyboardDescriptor
};

@interface TestIOHIDConnectionFilterPlugin : XCTestCase
@property IOHIDEventSystemClientRef eventSystem;
@property IOHIDUserDeviceTestController * sourceController;
-(void) handleEvent:(IOHIDEventRef) event;
@end

@implementation TestIOHIDConnectionFilterPlugin
{
UInt32 _eventCount;
NSDictionary *attributes;
NSArray *usageFilter;
}

- (void)setUp {
[super setUp];

NSData * descriptorData = [[NSData alloc] initWithBytes:descriptor length:sizeof(descriptor)];
NSString * uniqueID = [[[NSUUID alloc] init] UUIDString];

self.sourceController = [[IOHIDUserDeviceTestController alloc] initWithDescriptor:descriptorData DeviceUniqueID:uniqueID andQueue:nil];
HIDXCTAssertAndThrowTrue(self.sourceController != nil);

attributes = @{(__bridge_transfer NSString*)kCFBundleIdentifierKey : @("com.apple.IOHIDTestConnectionFilter")};

_eventSystem = IOHIDEventSystemClientCreateWithType(kCFAllocatorDefault, kIOHIDEventSystemClientTypeMonitor, (__bridge CFDictionaryRef)attributes);

HIDXCTAssertAndThrowTrue(_eventSystem != NULL);

}

- (void)tearDown {
[self.sourceController invalidate];

@autoreleasepool {
self.sourceController = nil;
}

IOHIDEventSystemClientUnscheduleWithRunLoop(_eventSystem, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);

if (_eventSystem) {
CFRelease(_eventSystem);
}

[super tearDown];
}
IOHIDEventBlock keyboardEventBlock = ^(void * target __unused, __unused void * refcon, void * sender __unused, IOHIDEventRef event)
{
TestIOHIDConnectionFilterPlugin *me = (__bridge TestIOHIDConnectionFilterPlugin*)target;
[me handleEvent:event];
};
- (void)testIOHIDConnectionFilterPlugin {

IOReturn status;

IOHIDEventSystemClientRegisterEventBlock(_eventSystem, keyboardEventBlock, (__bridge void*)self, NULL);

// set property for which you want to filter

// Set usage page you want to filter
// Set usage for usage page you want to filter

usageFilter = @[@{@kUsagePage : @(kHIDPage_KeyboardOrKeypad)},@{@kUsages : @[@(kHIDUsage_KeyboardEqualSign)]}];

IOHIDEventSystemClientSetProperty(_eventSystem, CFSTR(kIOHIDServiceDeviceDebugUsageFilter), (__bridge CFTypeRef)usageFilter);

IOHIDEventSystemClientScheduleWithRunLoop(_eventSystem, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
IOHIDEventSystemClientCopyProperty(_eventSystem, CFSTR (kIOHIDEventSystemClientIsUnresponsive));

//set report
HIDKeyboardDescriptorInputReport inReport = { 0 };
inReport.KB_Keyboard[0] = kHIDUsage_KeyboardEqualSign;
status = [self.sourceController handleReport: (uint8_t*)&inReport Length:sizeof(inReport) andInterval:0];

XCTAssert(status == KERN_SUCCESS);

inReport.KB_Keyboard[0] = 0x00;
status = [self.sourceController handleReport: (uint8_t*)&inReport Length:sizeof(inReport) andInterval:0];

XCTAssert(status == KERN_SUCCESS);

//inject other event
inReport.KB_Keyboard[0] = kHIDUsage_KeyboardHyphen;
status = [self.sourceController handleReport: (uint8_t*)&inReport Length:sizeof(inReport) andInterval:0];
XCTAssert(status == KERN_SUCCESS);

inReport.KB_Keyboard[0] = 0x00;
status = [self.sourceController handleReport: (uint8_t*)&inReport Length:sizeof(inReport) andInterval:0];

XCTAssert(status == KERN_SUCCESS);

CFRunLoopRunInMode(kCFRunLoopDefaultMode, kDefaultRunLoopTime, false);
TestLog("Event Count %u",(unsigned int)_eventCount);
XCTAssert(_eventCount == 2);

}
-(void) handleEvent:(IOHIDEventRef) event
{
_eventCount++;
UInt32 usagePage = (UInt32)IOHIDEventGetIntegerValue(event, kIOHIDEventFieldKeyboardUsagePage);
UInt32 usage = (UInt32)IOHIDEventGetIntegerValue(event, kIOHIDEventFieldKeyboardUsage);

TestLog("Usage %u UsagePage %u",(unsigned int)usage, (unsigned int)usagePage);

XCTAssert(usagePage == kHIDPage_KeyboardOrKeypad);
XCTAssert(usage == kHIDUsage_KeyboardEqualSign);
}
@end