//
// services.m
// IOHIDFamily
//
// Created by YG on 4/14/16.
//
//
#import <Foundation/Foundation.h>
#include <IOKit/hid/IOHIDEventSystemKeys.h>
#include "hdutil.h"
#include "AssertMacros.h"
#include <getopt.h>
#include "utility.h"
int property (int argc __unused, const char * argv[] __unused);
int propertySetOnEventSystem (IOHIDEventSystemClientRef client, NSDictionary * propertiesDicitonary);
int propertySetOnServices (IOHIDEventSystemClientRef client, NSDictionary * propertiesDicitonary);
int propertyGetEventSystemProperty (IOHIDEventSystemClientRef client, NSString* key);
int propertyGetServicesProperty (IOHIDEventSystemClientRef client, NSString* key);
void propertyPrint (NSString *str);
#define PROPERTY_USAGE_LIST \
" ProductID - numeric value (decimal or hex)\n" \
" VendorID - numeric value (decimal or hex)\n" \
" LocationID - numeric value (decimal or hex)\n" \
" PrimaryUsagePage - numeric value (decimal or hex)\n" \
" PrimaryUsage - numeric value (decimal or hex)\n" \
" Trasport - string value\n" \
" Product - string value\n"
int list (int argc, const char * argv[] __unused);
void listPrintService (IOHIDServiceClientRef service);
static const char listOptionShort[] = "hf:";
static const struct option listOptionLong[] =
{
{ "help", 0, NULL, 'h' },
{ "filter", required_argument, NULL, 'f' },
{ NULL, 0, NULL, 0 }
};
const char listUsage[] =
"\nList HID Event System services\n"
"\nUsage:\n\n"
" hidutil list [object] [flags]\n"
"\nExamples:\n\n"
" hidutil list\n"
" hidutil list --filter '{\"ProductID\":0x54c}'\n"
" hidutil list --filter '{\"ProductID\":0x54c,\"VendorID\":746}'\n"
"\nFlags:\n\n"
" --filter dictionary.........Filter services by properties (key/value pair JSON style dictionary)\n"
" Supported property:\n"
PROPERTY_USAGE_LIST;
static const char propertyOptionShort[] = "hf:g:s:";
static const struct option propertyOptionLong[] =
{
{ "help", 0 , NULL, 'h' },
{ "filter", required_argument, NULL, 'f' },
{ "get", required_argument, NULL, 'g' },
{ "set", required_argument, NULL, 's' },
{ NULL, 0, NULL, 0 }
};
const char propertyUsage[] =
"\nRead/Write HID Event System property\n"
"\nUsage:\n\n"
" hidutil property [--filter <value> ] <--get <key> |--write <dictionary>>\n"
"\nExamples:\n\n"
" hidutil property --filter '{\"ProductID\":0x54c}' --get \"HIDPointerAcceleration\"\n"
" hidutil property --filter '{\"ProductID\":0x54c,\"VendorID\":746}' --set '{\"HIDPointerAcceleration\":0}'\n"
" hidutil property --get \"HIDPointerAcceleration\"\n"
"\nFlags:\n\n"
" --filter dictionary.........Filter services by properties (key/value pair JSON style dictionary)\n"
" Supported property:\n"
PROPERTY_USAGE_LIST
" --get key...................Get property with key (where key is string value)\n"
" --set dictionary............Set property (key/value pair JSON style dictionary)\n";
void listPrintService (IOHIDServiceClientRef service) {
NSDictionary *serviceInfo = createServiceInfoDictionary (service);
if (!serviceInfo) {
return ;
}
printf (" ((NSNumber *)serviceInfo[@kIOHIDVendorIDKey]).unsignedIntValue,
((NSNumber *)serviceInfo[@kIOHIDProductIDKey]).unsignedIntValue,
((NSNumber *)serviceInfo[@kIOHIDLocationIDKey]).unsignedIntValue,
((NSNumber *)serviceInfo[@kIOHIDPrimaryUsagePageKey]).unsignedIntValue,
((NSNumber *)serviceInfo[@kIOHIDPrimaryUsageKey]).unsignedIntValue,
((NSNumber *)serviceInfo[@"RegistryID"]).unsignedLongValue,
[((NSString *)serviceInfo[@kIOHIDTransportKey]) cStringUsingEncoding: NSASCIIStringEncoding],
[((NSString *)serviceInfo[@kIOHIDProductKey]) cStringUsingEncoding: NSASCIIStringEncoding]
);
}
int list (int argc __unused, const char * argv[] __unused) {
int status = STATUS_SUCCESS;
int arg;
IOHIDEventSystemClientRef client = NULL;
NSDictionary *filterDictionary = NULL;
NSArray *services;
while ((arg = getopt_long(argc, (char **) argv, listOptionShort, listOptionLong, NULL)) != -1) {
switch (arg) {
case 'h':
printf (" return STATUS_SUCCESS;
case 'f':
filterDictionary = createFilterDictionary (createFilterString(optarg));
if (filterDictionary == NULL) {
printf ("\nERROR!!!! Unable to create service filter for \'%s\'\n", optarg);
}
break;
default:
return STATUS_ERROR;
}
}
client = IOHIDEventSystemClientCreateWithType(kCFAllocatorDefault, kIOHIDEventSystemClientTypeMonitor, NULL);
require_action (client, exit, status = STATUS_ERROR;);
if (filterDictionary) {
IOHIDEventSystemClientSetMatching (client, (__bridge CFDictionaryRef)(filterDictionary));
}
services = (NSArray *)CFBridgingRelease(IOHIDEventSystemClientCopyServices(client));
if (services) {
printf ("%-8s %-8s %-10s %-10s %-6s %-10s %-12s %s\n", "VendorID", "ProductID", "LocationID", "PUsagePage", "PUsage", "RegistryID", "Transport", "Product" );
for (id service in services) {
listPrintService ((__bridge IOHIDServiceClientRef)service);
}
}
exit:
if (client) {
CFRelease (client);
}
return status;
}
void propertyPrint (NSString *str) {
// [str writeToFile: @"/dev/stdout" atomically: NO];
const char * c_str = [str UTF8String];
if (c_str) {
printf ("%s" , [str UTF8String]);
}
}
int propertySetOnEventSystem (IOHIDEventSystemClientRef client, NSDictionary * propertiesDicitonary) {
[propertiesDicitonary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop __unused) {
propertyPrint ([NSString stringWithFormat:@"%@:%@\n", key, value]);
IOHIDEventSystemClientSetProperty (client, (__bridge CFStringRef) key, (__bridge CFStringRef) value);
}];
return STATUS_SUCCESS;
}
int propertySetOnServices (IOHIDEventSystemClientRef client, NSDictionary * propertiesDicitonary) {
NSArray *services = (NSArray *)CFBridgingRelease(IOHIDEventSystemClientCopyServices(client));
if (services) {
printf ("%-8s %-20s %s\n", "RegistryID", "Key", "Value");
for (id service in services) {
NSDictionary *serviceInfo = createServiceInfoDictionary((__bridge IOHIDServiceClientRef)service);
[propertiesDicitonary enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL* stop __unused) {
propertyPrint ([NSString stringWithFormat:@"%-8lx %-20@ %@\n", ((NSNumber *)serviceInfo[@"RegistryID"]).unsignedLongValue, key, value]);
IOHIDServiceClientSetProperty ((__bridge IOHIDServiceClientRef)service, (__bridge CFStringRef) key, (__bridge CFStringRef) value);
}];
}
}
return STATUS_SUCCESS;
}
int propertyGetEventSystemProperty (IOHIDEventSystemClientRef client, NSString* key) {
id value = CFBridgingRelease(IOHIDEventSystemClientCopyProperty (client, (__bridge CFStringRef) key));
propertyPrint ([NSString stringWithFormat:@"%@\n",value]);
return STATUS_SUCCESS;
}
int propertyGetServicesProperty (IOHIDEventSystemClientRef client, NSString* key) {
NSArray *services = (NSArray *)CFBridgingRelease(IOHIDEventSystemClientCopyServices(client));
if (services) {
printf ("%-8s %-20s %s\n", "RegistryID", "Key", "Value");
for (id service in services) {
NSDictionary *serviceInfo = createServiceInfoDictionary((__bridge IOHIDServiceClientRef)service);
id value = CFBridgingRelease(IOHIDServiceClientCopyProperty ((__bridge IOHIDServiceClientRef)service, (__bridge CFStringRef) key));
propertyPrint ([NSString stringWithFormat:@"%-8lx %-20@ %@\n", ((NSNumber *)serviceInfo[@"RegistryID"]).unsignedLongValue, key, value]);
}
}
return STATUS_SUCCESS;
}
int property (int argc, const char * argv[]) {
int arg;
int status = STATUS_SUCCESS;
IOHIDEventSystemClientRef client = NULL;
id propertyDicitonary = NULL;
NSString *propertyKey = NULL;
NSDictionary *filterDictionary = NULL;
while ((arg = getopt_long(argc, (char **) argv, propertyOptionShort, propertyOptionLong, NULL)) != -1) {
switch (arg) {
case 'h':
printf (" return STATUS_SUCCESS;
case 'f':
filterDictionary = createFilterDictionary (createFilterString(optarg));
if (filterDictionary == NULL) {
printf ("\nERROR!!!! Unable to create service filter for \'%s\'\n", optarg);
}
break;
case 's':
propertyDicitonary = createPropertiesDicitonary (createPropertiesString(optarg));
if (propertyDicitonary == NULL || ![propertyDicitonary isKindOfClass:[NSDictionary class]]) {
printf ("\nERROR!!!! Unable to create property object for \'%s\'\n", optarg);
}
break;
case 'g':
propertyKey = [NSString stringWithUTF8String:optarg];
break;
default:
return STATUS_ERROR;
}
}
require_action (!(propertyKey == NULL && propertyDicitonary == NULL) || (propertyKey != NULL && propertyDicitonary != NULL), exit, status = STATUS_ERROR;);
client = IOHIDEventSystemClientCreateWithType(kCFAllocatorDefault, kIOHIDEventSystemClientTypeMonitor, NULL);
require_action (client, exit, status = STATUS_ERROR;);
if (filterDictionary) {
IOHIDEventSystemClientSetMatching (client, (__bridge CFDictionaryRef)(filterDictionary));
}
if (propertyDicitonary) {
if (filterDictionary) {
status = propertySetOnServices (client, propertyDicitonary);
} else {
status = propertySetOnEventSystem (client, propertyDicitonary);
}
} else {
if (filterDictionary == NULL) {
status = propertyGetEventSystemProperty (client, propertyKey);
} else {
status = propertyGetServicesProperty (client, propertyKey);
}
}
exit:
if (client) {
CFRelease (client);
}
return status;
}