TestKeyboardServicePlugin.m [plain text]
//
// TestKeyRepeats.m
// IOHIDFamily
//
// Created by YG on 10/31/16.
//
//
#import <XCTest/XCTest.h>
#include "IOHIDUnitTestUtility.h"
#import "IOHIDEventSystemTestController.h"
#import "IOHIDUserDeviceTestController.h"
#import "IOHIDDeviceTestController.h"
#import "IOHIDUnitTestDescriptors.h"
typedef struct {
uint32_t initialDelay;
uint32_t repeatDelay;
} DELAY_RANGE;
static uint8_t descriptor[] = {
HIDKeyboardDescriptor
};
@interface TestKeyboardServicePlugin : XCTestCase
@property IOHIDEventSystemTestController * eventController;
@property IOHIDUserDeviceTestController * sourceController;
@property dispatch_queue_t rootQueue;
@property dispatch_queue_t eventControllerQueue;
@end
@implementation TestKeyboardServicePlugin
- (void)setUp {
[super setUp];
self.rootQueue = IOHIDUnitTestCreateRootQueue(31, 2);
self.eventControllerQueue = dispatch_queue_create_with_target ("IOHIDEventSystemTestController", DISPATCH_QUEUE_SERIAL, self.rootQueue);
HIDXCTAssertAndThrowTrue(self.eventControllerQueue != nil);
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);
self.eventController = [[IOHIDEventSystemTestController alloc] initWithDeviceUniqueID:uniqueID AndQueue:self.eventControllerQueue];
HIDXCTAssertAndThrowTrue(self.eventController != nil);
}
- (void)tearDown {
[self.eventController invalidate];
[self.sourceController invalidate];
@autoreleasepool {
self.sourceController = nil;
self.eventController = nil;
}
[super tearDown];
}
- (void)checkRepeats: (uint32_t) initialDelayMS :(uint32_t) repeatDelayMS {
IOReturn status;
HIDKeyboardDescriptorInputReport report;
memset(&report, 0, sizeof(report));
NSNumber *valueInitialRepeat = @(MS_TO_NS(initialDelayMS));
NSNumber *valueRepeatDelay = @(MS_TO_NS(repeatDelayMS));
uint32_t numberOfRepeats = 10;
// Allow event to be dispatched
usleep(kDefaultReportDispatchCompletionTime);
TestLog("initialDelayMS:
IOHIDServiceClientSetProperty(self.eventController.eventService, CFSTR(kIOHIDServiceInitialKeyRepeatDelayKey), (__bridge CFTypeRef _Nonnull)(valueInitialRepeat));
IOHIDServiceClientSetProperty(self.eventController.eventService, CFSTR(kIOHIDServiceKeyRepeatDelayKey), (__bridge CFTypeRef _Nonnull)(valueRepeatDelay));
report.KB_Keyboard[0] = kHIDUsage_KeypadEqualSignAS400;
status = [self.sourceController handleReport: (uint8_t*)&report Length:sizeof(report) andInterval:0];
XCTAssert(status == kIOReturnSuccess, "handleReport:
report.KB_Keyboard[0] = 0x00;
status = [self.sourceController handleReport: (uint8_t*)&report Length:sizeof(report) andInterval: (MS_TO_US(initialDelayMS) + numberOfRepeats * MS_TO_US(repeatDelayMS))];
XCTAssert(status == kIOReturnSuccess, "handleReport:
sleep (2);
// Make copy
NSArray *events = nil;
@synchronized (self.eventController.events) {
events = [self.eventController.events copy];
}
// Check if event system reset occur
XCTAssert(self.eventController.eventSystemResetCount == 0, "IOHIDEventSystem resetCount:
EVENTS_STATS stats = [IOHIDEventSystemTestController getEventsStats:events];
HIDTestEventLatency(stats);
XCTAssertTrue(VALUE_IN_RANGE(stats.counts[kIOHIDEventTypeKeyboard], numberOfRepeats , numberOfRepeats + 3),
"keyboard events count: (unsigned long)stats.counts[kIOHIDEventTypeKeyboard],
(numberOfRepeats + 3),
events
);
uint64_t prev = IOHIDEventGetTimeStamp((IOHIDEventRef)events[0]);
uint64_t initialDelayNS = MS_TO_NS(initialDelayMS);
uint64_t repeatDelayNS = MS_TO_NS(repeatDelayMS);
for (size_t index = 1; index < (events.count - 1); index++) {
uint64_t next = IOHIDEventGetTimeStamp((IOHIDEventRef)events[index]);
uint64_t delta = IOHIDInitTestAbsoluteTimeToNanosecond (next) - IOHIDInitTestAbsoluteTimeToNanosecond (prev);
if (index == 1) {
XCTAssertTrue (VALUE_IN_RANGE(delta , VALUE_PST(initialDelayNS,-20) , VALUE_PST(initialDelayNS,+20)) ,
"Index: index,
delta ,
VALUE_PST(initialDelayNS,-20),
VALUE_PST(initialDelayNS,+20),
events
);
} else {
XCTAssertTrue (VALUE_IN_RANGE(delta , VALUE_PST(repeatDelayNS,-20) , VALUE_PST(repeatDelayNS,+20)),
"Index: index,
delta ,
VALUE_PST(repeatDelayNS,-20),
VALUE_PST(repeatDelayNS,+20),
events
);
}
prev = next;
}
}
- (void) MAC_OS_ONLY_TEST_CASE(testKeyRepeat) {
DELAY_RANGE ranges [] = {
{250 , 33},
{500 , 66}
};
for (size_t index = 0; index < (sizeof (ranges) / sizeof(ranges[0]));index++){
[self. eventController.events removeAllObjects];
[self checkRepeats:ranges[index].initialDelay :ranges[index].repeatDelay];
}
}
@end