1/*
2 *  IOHIDAggdMetricsPlugIn.cpp
3 *  IOHIDEventSystemPlugIns
4 *
5 *  Created by Rob Yepez on 05/21/2013.
6 *  Copyright 2013 Apple Inc. All rights reserved.
7 *
8 */
9
10#include <new>
11#include <AggregateDictionary/ADClient.h>
12#include <CoreFoundation/CoreFoundation.h>
13#include <IOKit/hid/IOHIDSessionFilterPlugIn.h>
14#include <IOKit/hid/IOHIDEventSystemPrivate.h>
15#include <IOKit/hid/IOHIDEventTypes.h>
16#include <IOKit/hid/IOHIDSession.h>
17#include <IOKit/hid/IOHIDService.h>
18#include <IOKit/hid/IOHIDPrivateKeys.h>
19#include <IOKit/hid/IOHIDDisplay.h>
20#include <IOKit/hid/IOHIDEventSystemKeys.h>
21#include <IOKit/hid/IOHIDUsageTables.h>
22#include <IOKit/hid/IOHIDKeys.h>
23#include <pthread.h>
24#include "IOHIDAggdMetricsPlugIn.h"
25
26
27#define kAggregateDictionaryKeyboardEnumerationCountKey "com.apple.iokit.hid.keyboard.enumerationCount"
28#define kAggregateDictionaryHomeButtonWakeCountKey      "com.apple.iokit.hid.homeButton.wakeCount"
29
30// 072BC077-E984-4C2A-BB72-D4769CE44FAF
31#define kIOHIDAggdMetricsPlugInFactory CFUUIDGetConstantUUIDWithBytes(kCFAllocatorSystemDefault, 0x07, 0x2B, 0xC0, 0x77, 0xE9, 0x84, 0x4C, 0x2A, 0xBB, 0x72, 0xD4, 0x76, 0x9C, 0xE4, 0x4F, 0xAF)
32
33extern "C" void * IOHIDAggdMetricsPlugInFactory(CFAllocatorRef allocator, CFUUIDRef typeUUID);
34
35//------------------------------------------------------------------------------
36// IOHIDAggdMetricsPlugInFactory
37//------------------------------------------------------------------------------
38// Implementation of the factory function for this type.
39void *IOHIDAggdMetricsPlugInFactory(CFAllocatorRef allocator __unused, CFUUIDRef typeUUID)
40{
41    // If correct type is being requested, allocate an
42    // instance of TestType and return the IUnknown interface.
43    if (CFEqual(typeUUID, kIOHIDSessionFilterPlugInTypeID)) {
44        void *p = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(IOHIDAggdMetricsPlugIn), 0);
45        return new(p) IOHIDAggdMetricsPlugIn(kIOHIDAggdMetricsPlugInFactory);
46    }
47    // If the requested type is incorrect, return NULL.
48    return NULL;
49}
50// The IOHIDAggdMetricsPlugIn function table.
51IOHIDSessionFilterPlugInInterface IOHIDAggdMetricsPlugIn::sIOHIDAggdMetricsPlugInFtbl =
52{
53    // Required padding for COM
54    NULL,
55    // These three are the required COM functions
56    IOHIDAggdMetricsPlugIn::QueryInterface,
57    IOHIDAggdMetricsPlugIn::AddRef,
58    IOHIDAggdMetricsPlugIn::Release,
59    // IOHIDSimpleSessionFilterPlugInInterface functions
60    IOHIDAggdMetricsPlugIn::filter,
61    IOHIDAggdMetricsPlugIn::filter,      // filterCopyEvent
62    IOHIDAggdMetricsPlugIn::copyEvent,
63    // IOHIDSessionFilterPlugInInterface functions
64    IOHIDAggdMetricsPlugIn::open,
65    IOHIDAggdMetricsPlugIn::close,
66    IOHIDAggdMetricsPlugIn::registerDisplay,
67    IOHIDAggdMetricsPlugIn::unregisterDisplay,
68    IOHIDAggdMetricsPlugIn::registerService,
69    IOHIDAggdMetricsPlugIn::unregisterService,
70    IOHIDAggdMetricsPlugIn::scheduleWithRunLoop,
71    IOHIDAggdMetricsPlugIn::unscheduleFromRunLoop,
72    IOHIDAggdMetricsPlugIn::getPropertyForClient,
73    IOHIDAggdMetricsPlugIn::setPropertyForClient,
74}; // Interface implementation
75//------------------------------------------------------------------------------
76// IOHIDAggdMetricsPlugIn::IOHIDAggdMetricsPlugIn
77//------------------------------------------------------------------------------
78IOHIDAggdMetricsPlugIn::IOHIDAggdMetricsPlugIn(CFUUIDRef factoryID)
79:
80_sessionInterface(&sIOHIDAggdMetricsPlugInFtbl),
81_factoryID( static_cast<CFUUIDRef>( CFRetain(factoryID) ) ),
82_refCount(1),
83_factor(1.0f)
84{
85    CFPlugInAddInstanceForFactory( factoryID );
86}
87//------------------------------------------------------------------------------
88// IOHIDAggdMetricsPlugIn::IOHIDAggdMetricsPlugIn
89//------------------------------------------------------------------------------
90IOHIDAggdMetricsPlugIn::~IOHIDAggdMetricsPlugIn()
91{
92    CFPlugInRemoveInstanceForFactory( _factoryID );
93    CFRelease( _factoryID );
94}
95//------------------------------------------------------------------------------
96// IOHIDAggdMetricsPlugIn::QueryInterface
97//------------------------------------------------------------------------------
98HRESULT IOHIDAggdMetricsPlugIn::QueryInterface( void *self, REFIID iid, LPVOID *ppv )
99{
100    return static_cast<IOHIDAggdMetricsPlugIn *>(self)->QueryInterface(iid, ppv);
101}
102// Implementation of the IUnknown QueryInterface function.
103HRESULT IOHIDAggdMetricsPlugIn::QueryInterface( REFIID iid, LPVOID *ppv )
104{
105    // Create a CoreFoundation UUIDRef for the requested interface.
106    CFUUIDRef interfaceID = CFUUIDCreateFromUUIDBytes( NULL, iid );
107    // Test the requested ID against the valid interfaces.
108    if (CFEqual(interfaceID, kIOHIDSimpleSessionFilterPlugInInterfaceID) || CFEqual(interfaceID, kIOHIDSessionFilterPlugInInterfaceID)) {
109        AddRef();
110        *ppv = this;
111        CFRelease(interfaceID);
112        return S_OK;
113    }
114    if (CFEqual(interfaceID, IUnknownUUID)) {
115        // If the IUnknown interface was requested, same as above.
116        AddRef();
117        *ppv = this;
118        CFRelease(interfaceID);
119        return S_OK;
120    }
121    // Requested interface unknown, bail with error.
122    *ppv = NULL;
123    CFRelease( interfaceID );
124    return E_NOINTERFACE;
125}
126//------------------------------------------------------------------------------
127// IOHIDAggdMetricsPlugIn::AddRef
128//------------------------------------------------------------------------------
129ULONG IOHIDAggdMetricsPlugIn::AddRef( void *self )
130{
131    return static_cast<IOHIDAggdMetricsPlugIn *>(self)->AddRef();
132}
133ULONG IOHIDAggdMetricsPlugIn::AddRef()
134{
135    _refCount += 1;
136    return _refCount;
137}
138//------------------------------------------------------------------------------
139// IOHIDAggdMetricsPlugIn::Release
140//------------------------------------------------------------------------------
141ULONG IOHIDAggdMetricsPlugIn::Release( void *self )
142{
143    return static_cast<IOHIDAggdMetricsPlugIn *>(self)->Release();
144}
145ULONG IOHIDAggdMetricsPlugIn::Release()
146{
147    _refCount -= 1;
148    if (_refCount == 0) {
149        delete this;
150        return 0;
151    }
152    return _refCount;
153}
154//------------------------------------------------------------------------------
155// IOHIDAggdMetricsPlugIn::open
156//------------------------------------------------------------------------------
157boolean_t IOHIDAggdMetricsPlugIn::open(void * self, IOHIDSessionRef session, IOOptionBits options)
158{
159    return true;
160}
161//------------------------------------------------------------------------------
162// IOHIDAggdMetricsPlugIn::close
163//------------------------------------------------------------------------------
164void IOHIDAggdMetricsPlugIn::close(void * self, IOHIDSessionRef inSession, IOOptionBits options)
165{
166}
167//------------------------------------------------------------------------------
168// IOHIDAggdMetricsPlugIn::registerDisplay
169//------------------------------------------------------------------------------
170void IOHIDAggdMetricsPlugIn::registerDisplay(void * self, IOHIDDisplayRef display)
171{
172}
173//------------------------------------------------------------------------------
174// IOHIDAggdMetricsPlugIn::unregisterDisplay
175//------------------------------------------------------------------------------
176void IOHIDAggdMetricsPlugIn::unregisterDisplay(void * self, IOHIDDisplayRef display)
177{
178}
179//------------------------------------------------------------------------------
180// IOHIDAggdMetricsPlugIn::registerService
181//------------------------------------------------------------------------------
182void IOHIDAggdMetricsPlugIn::registerService(void * self, IOHIDServiceRef service)
183{
184    static_cast<IOHIDAggdMetricsPlugIn *>(self)->registerService(service);
185}
186void IOHIDAggdMetricsPlugIn::registerService(IOHIDServiceRef service)
187{
188    if ( IOHIDServiceConformsTo(service, kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard) )
189    {
190        ADClientAddValueForScalarKey(CFSTR(kAggregateDictionaryKeyboardEnumerationCountKey), 1);
191    }
192}
193//------------------------------------------------------------------------------
194// IOHIDAggdMetricsPlugIn::unregisterService
195//------------------------------------------------------------------------------
196void IOHIDAggdMetricsPlugIn::unregisterService(void * self, IOHIDServiceRef inService)
197{
198}
199//------------------------------------------------------------------------------
200// IOHIDAggdMetricsPlugIn::scheduleWithRunLoop
201//------------------------------------------------------------------------------
202void IOHIDAggdMetricsPlugIn::scheduleWithRunLoop(void * self, CFRunLoopRef runLoop, CFStringRef runLoopMode)
203{
204    return;
205}
206//------------------------------------------------------------------------------
207// IOHIDAggdMetricsPlugIn::unscheduleFromRunLoop
208//------------------------------------------------------------------------------
209void IOHIDAggdMetricsPlugIn::unscheduleFromRunLoop(void * self, CFRunLoopRef runLoop, CFStringRef runLoopMode)
210{
211}
212//------------------------------------------------------------------------------
213// IOHIDAggdMetricsPlugIn::getPropertyForClient
214//------------------------------------------------------------------------------
215CFTypeRef IOHIDAggdMetricsPlugIn::getPropertyForClient(void * self, CFStringRef key, CFTypeRef client)
216{
217    return NULL;
218}
219//------------------------------------------------------------------------------
220// IOHIDAggdMetricsPlugIn::setPropertyForClient
221//------------------------------------------------------------------------------
222void IOHIDAggdMetricsPlugIn::setPropertyForClient(void * self, CFStringRef key, CFTypeRef property, CFTypeRef client)
223{
224    static_cast<IOHIDAggdMetricsPlugIn *>(self)->setPropertyForClient(key, property, client);
225}
226void IOHIDAggdMetricsPlugIn::setPropertyForClient(CFStringRef key, CFTypeRef property, CFTypeRef client)
227{
228    Boolean factorChange        = CFEqual(key, CFSTR(kIOHIDDisplayBrightnessFactorKey)) || CFEqual(key, CFSTR(kIOHIDDisplayBrightnessFactorWithFadeKey));
229    if ( factorChange ) {
230        if ( CFGetTypeID(property) == CFNumberGetTypeID() ) {
231            float factor = _factor;
232            CFNumberGetValue((CFNumberRef)property, kCFNumberFloatType, &factor);
233            // After application, did anything change relating to the display
234            if ( factor != _factor ) {
235                _factor = factor;
236           }
237        }
238    }
239}
240//------------------------------------------------------------------------------
241// IOHIDAggdMetricsPlugIn::filter
242//------------------------------------------------------------------------------
243IOHIDEventRef IOHIDAggdMetricsPlugIn::filter(void * self, IOHIDServiceRef sender, IOHIDEventRef event)
244{
245    return static_cast<IOHIDAggdMetricsPlugIn *>(self)->filter(sender, event);
246}
247IOHIDEventRef IOHIDAggdMetricsPlugIn::filter(IOHIDServiceRef sender, IOHIDEventRef event)
248{
249    float factor = _factor;
250    CFRetain(event);
251    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
252
253        if ( event && (IOHIDEventGetType(event) == kIOHIDEventTypeKeyboard)
254            && IOHIDEventGetIntegerValue(event, kIOHIDEventFieldKeyboardDown)
255            && (IOHIDEventGetIntegerValue(event, kIOHIDEventFieldKeyboardUsagePage) == kHIDPage_Consumer)
256            && (IOHIDEventGetIntegerValue(event, kIOHIDEventFieldKeyboardUsage) == kHIDUsage_Csmr_Menu)
257            && (factor == 0.0)) {
258
259            ADClientAddValueForScalarKey(CFSTR(kAggregateDictionaryHomeButtonWakeCountKey), 1);
260        }
261
262        CFRelease(event);
263    });
264
265    return event;
266}
267//------------------------------------------------------------------------------
268// IOHIDAggdMetricsPlugIn::copyEvent
269//------------------------------------------------------------------------------
270IOHIDEventRef IOHIDAggdMetricsPlugIn::copyEvent(void * self, IOHIDEventType type, IOHIDEventRef matching, IOOptionBits options)
271{
272    return NULL;
273}
274