HIDServicePluginExample.m   [plain text]

//
// HIDServicePluginExample.m
// HIDServicePluginExample
//
// Created by dekom on 10/1/18.
//

#import <Foundation/Foundation.h>
#import "HIDServicePluginExample.h"
#import <IOKit/hid/IOHIDUsageTables.h>
#import <IOKit/hid/AppleHIDUsageTables.h>
#import <IOKit/hid/IOHIDServiceKeys.h>
#import <IOKit/hid/IOHIDEventTypes.h>
#import <IOKit/IOKitLib.h>
#import <AssertMacros.h>
#import <os/log.h>
#import "IOHIDDebug.h"

#ifdef DEBUG_ASSERT_MESSAGE
#undef DEBUG_ASSERT_MESSAGE
#endif

#define DEBUG_ASSERT_MESSAGE(name, assertion, label, message, file, line, value) \
HIDLog("AssertMacros: %s, %s", assertion, (message!=0) ? message : "");

@implementation HIDServicePluginExample {
HIDBlock _cancelHandler;
dispatch_queue_t _queue;
HIDDevice *_device;
NSNumber *_prop;
bool _activated;
bool _clientAdded;
}

+ (BOOL)matchService:(io_service_t)service
options:(NSDictionary *)options
score:(NSInteger *)score
{
if(IOObjectConformsTo(service, "IOHIDUserDevice")) {
*score = 100;

HIDLog("HIDServicePluginExample::matchService: %d options: %@ score: %ld",
service, options, (long)*score);

return true;
}

return false;
}

- (instancetype)initWithService:(io_service_t)service
{
self = [super init];
if (!self) {
return self;
}

_device = [[HIDDevice alloc] initWithService:service];
if (!_device) {
return nil;
}

[_device open];

__weak HIDServicePluginExample *weakSelf = self;
[_device setInputElementHandler:^(HIDElement *element) {
__strong HIDServicePluginExample *strongSelf = weakSelf;
if (!strongSelf) {
return;
}

if (element.usage < kHIDUsage_KeyboardA ||
element.usage > kHIDUsage_KeyboardRightGUI) {
return;
}

HIDLog("HIDServicePluginExample::recevied element: %@", element);

HIDEvent *event = [[HIDEvent alloc] initWithType:kIOHIDEventTypeKeyboard
timestamp:mach_absolute_time()
senderID:1234];

[event setIntegerValue:element.usagePage forField:kIOHIDEventFieldKeyboardUsagePage];
[event setIntegerValue:element.usage forField:kIOHIDEventFieldKeyboardUsage];
[event setIntegerValue:element.integerValue forField:kIOHIDEventFieldKeyboardDown];

[strongSelf->_dispatcher dispatchEvent:event];
}];

HIDLog("HIDServicePluginExample::initWithService: %d", service);

return self;
}

- (void)dealloc
{
HIDLog("HIDServicePluginExample dealloc");
}

- (NSString *)description
{
return @"HIDServicePluginExample";
}

- (nullable id)propertyForKey:(NSString *)key
client:(HIDConnection *)client
{
id result = nil;

if ([key isEqualToString:@"TestHIDServicePluginGetProperty"]) {
result = _prop;
HIDLog("HIDServicePluginExample::propertyForKey %@ value: %@ client: %@", key, result, client);
} else if ([key isEqualToString:@(kIOHIDServicePluginDebugKey)]) {
// debug dictionary that gets captured by hidutil
NSMutableDictionary *debug = [NSMutableDictionary new];

debug[@"PluginName"] = @"HIDServicePluginExample";
debug[@"cancelHandler"] = _cancelHandler ? @YES : @NO;
debug[@"dispatchQueue"] = _queue ? @YES : @NO;
debug[@"activated"] = @(_activated);
debug[@"clientAdded"] = @(_clientAdded);

result = debug;
} else {
result = [_device propertyForKey:key];
}

return result;
}

- (BOOL)setProperty:(id)value
forKey:(NSString *)key
client:(HIDConnection *)client
{
bool result = false;

if ([key isEqualToString:@"TestHIDServicePluginSetProperty"] &&
[value isKindOfClass:[NSNumber class]]) {
_prop = value;
result = true;

HIDLog("HIDServiceFilterExample::setProperty: %@ forKey: %@ client: %@", value, key, client);
} else {
result = [_device setProperty:value forKey:key];
}

return result;
}

- (HIDEvent *)eventMatching:(NSDictionary *)matching
forClient:(HIDConnection *)client
{
HIDEvent *event = nil;
NSNumber *type = nil;

require(matching, exit);

HIDLog("HIDServicePluginExample::eventMatching: %@ client: %@", matching, client);

type = matching[@("EventType")];

if (type && type.unsignedIntValue == kIOHIDEventTypeKeyboard) {
event = [[HIDEvent alloc] initWithType:kIOHIDEventTypeKeyboard
timestamp:1234
senderID:5678];
}

exit:
return event;
}

- (void)setEventDispatcher:(id<HIDEventDispatcher>)dispatcher
{
HIDLog("HIDServicePluginExample::setEventDispatcher %@", dispatcher);
_dispatcher = dispatcher;
}

- (void)setCancelHandler:(HIDBlock)handler
{
HIDLog("HIDServicePluginExample::setCancelHandler %p", handler);
_cancelHandler = handler;

__weak HIDServicePluginExample *weakSelf = self;
[_device setCancelHandler:^{
__strong HIDServicePluginExample *strongSelf = weakSelf;
if (!strongSelf) {
return;
}

HIDLog("HIDServicePluginExample::cancel calling cancel handler");

strongSelf->_cancelHandler();
strongSelf->_cancelHandler = nil;
}];
}

- (void)activate
{
HIDLog("HIDServicePluginExample::activate");
[_device activate];
_activated = true;
}

- (void)cancel
{
HIDLog("HIDServicePluginExample::cancel");
[_device cancel];
[_device close];
}

- (void)setDispatchQueue:(dispatch_queue_t)queue
{
HIDLog("HIDServicePluginExample::setDispatchQueue %p", queue);
_queue = queue;
[_device setDispatchQueue:_queue];
}

- (void)clientNotification:(HIDConnection *)client added:(BOOL)added
{
HIDLog("HIDServicePluginExample::clientNotification %@ added: %d", client, added);

if (added) {
_clientAdded = true;
_client = client;
} else {
_clientAdded = false;
_client = nil;
}
}

@end