IOHIDFamily is a kernel extension that provides an abstract interface of with human interface devices (HID), e.g. the touchscreen, buttons, accelerometer, etc. In the user-land, there are two kinds of APIs associated to the IOHIDFamily: (1) the "public" ones, which are intended for HID driver writers; (2) the "private" ones, which are intended for event processing. This document will only outline the private APIs. References to the public one can be found in the Mac development documentation.
Class structure
Users of IOHID always first create an IOHIDEventSystem object that interfaces with the whole HID system. An event system consists of multiple IOHIDServices and IOHIDDisplays.
Services are various interfaces to the IOHIDLibPlugin kernel plugin (located at /System/Library/Extensions/IOHIDFamily.kext/PlugIns/IOHIDLib.plugin/IOHIDLib). They accept direct human input, and are the sources of all IOHIDEvents.
Displays are, obviously, the LCD screen. The IOHIDDisplay class can only control the brightness, not colors of individual pixels (Drawing is controlled by the VRAM). You only can control the displays indirectly by changing properties of the event system.
IOHID defines 20 types of events, of which the SpringBoard only handles 4 of them: keyboard (for buttons), digitizer (i.e. touchscreen), accelerometer and proximity events (temperature events are handled by IOKit directly). Each event may contain sub-events.
Example
#include <IOKit/hid/IOHIDEventSystem.h>
#include <stdio.h>
void handle_event (void* target, void* refcon, IOHIDServiceRef service, IOHIDEventRef event) {
// handle the events here.
printf("Received event of type %2d from service %p.\n", IOHIDEventGetType(event), service);
}
int main () {
// Create and open an event system.
IOHIDEventSystemRef system = IOHIDEventSystemCreate(NULL);
IOHIDEventSystemOpen(system, handle_event, NULL, NULL, NULL);
printf("HID Event system should now be running. Hit enter to quit any time.\n");
getchar();
IOHIDEventSystemClose(system, NULL);
CFRelease(system);
return 0;
}
Problems with iOS >= 6.1 (or even earlier)
Since at least iOS 6.1 there is a check in the function IOHIDEventSystemCreate that compares the bundle identifier with "com.apple.springboard". If that check fails, the function will return NULL. Therefore you can no longer use the HID system in apps unless you circumvent this check.
__text:0001561A loc_1561A ; CODE XREF: _IOHIDEventSystemCreate+7E�j
__text:0001561A MOV R0, R4
__text:0001561C MOVS R2, #0xC4 ; ''
__text:0001561E MOVS R3, #0
__text:00015620 MOVS R5, #0
__text:00015622 BLX __CFRuntimeCreateInstance
__text:00015626 MOV R4, R0
__text:00015628 CMP R4, #0
__text:0001562A BEQ.W loc_1584A
__text:0001562E ADD.W R5, R4, #8
__text:00015632 MOVS R1, #0 ; int
__text:00015634 MOV R0, R5 ; void *
__text:00015636 MOVS R2, #0xC4 ; '' ; size_t
__text:00015638 BLX _memset ; Initialize the struct's variables to zero.
__text:0001563C BLX _CFBundleGetMainBundle ; Get the main bundle
__text:00015640 CBZ R0, loc_15660 ; Go to loc_15660 if it returned NULL.
__text:00015642 BLX _CFBundleGetIdentifier ; Get the bundle's identifier.
__text:00015646 CBZ R0, loc_15660 ; Go to loc_15660 if the identifier is NULL.
__text:00015648 MOV R1, #(cfstr_Com_apple_spri - 0x15654) ; "com.apple.springboard"
__text:00015650 ADD R1, PC ; "com.apple.springboard"
__text:00015652 BLX _CFEqual ; Check if the main bundle's identifier is equal to com.apple.springboard.
__text:00015656 CMP R0, #0 ; If the check returned false, return.
__text:00015658 ITT NE
__text:0001565A MOVNE R0, #1
__text:0001565C STRNEB.W R0, [R4,#0xB8]
__text:00015660
__text:00015660 loc_15660 ; CODE XREF: _IOHIDEventSystemCreate+C0�j
__text:00015660 ; _IOHIDEventSystemCreate+C6�j
__text:00015660 ADD.W R8, R4, #0x38
__text:00015664 MOVS R1, #0 ; attr
__text:00015666 MOV R0, R8 ; rwlock
__text:00015668 BLX _pthread_rwlock_init
__text:0001566C CMP R0, #0
__text:0001566E BNE.W loc_15792
Services
To access the services, you have to first match them using IOHIDEventSystemCopyMatchingServices. These criteria can be obtained using ioreg -l.
Service | Name match | CFBundleIdentifier | PrimaryUsagePage | PrimaryUsage |
---|---|---|---|---|
AppleLIS302DL (Accelerometer) | accelerometer,lis302dl | com.apple.driver.AppleEmbeddedAccelerometer | 0xff00 | 3 |
AppleISL29003 (ALS) | als,isl29003 | com.apple.driver.AppleEmbeddedLightSensor | 0xff00 | 4 |
AppleProxShim (ProximitySensor) | als,ct700 | com.apple.driver.AppleIntegratedProxALSSensor | 0xff00 | 8 |
AppleM68Buttons (Buttons) | buttons | com.apple.driver.AppleM68Buttons | 11 | 1 |
AppleMultitouchZ2SPI (Touchscreen) | multi-touch,z2 | com.apple.driver.AppleMultitouchSPI | - | - |
Keyboard events
The iPhoneOS button events are in fact treated as "keyboard" events. The following shows how to identify them[1] or [2]:
Usage page | Usage | Button |
---|---|---|
1 | 0x83 | Wake up (Calls -[SBUIController wakeUp:] in SpringBoard.)
|
7 | - | Hardware keyboard events |
11 | 0x21 | Headset button |
11 | 0x23 | Obsolete hold |
11 | 0x2e | Ringer |
12 | 0x30 | Lock |
12 | 0x40, 0x223 | Menu |
12 | 0xb3 | Fast forward |
12 | 0xb4 | Rewind |
12 | 0xb5 | Scan Next Track |
12 | 0xe2 | Mute |
12 | 0xb8, 0x1ae | Media key (to toggle the soft keyboard) |
12 | 0xe9 | Volume increase |
12 | 0xea | Volume decrease |
0xff01 | ≤0x20 | Apple vender keyboard event |
0xff07 | 1 | Headset availability changed |
References
- ^ http://ftp.sunet.se/pub/os/OpenBSD/src/share/misc/usb_hid_usages[permanent dead link]
- ^ http://www.usb.org/developers/devclass_docs/Hut1_11.pdf [Archived 2011-11-25 at the Wayback Machine]
- Headers for IOHID: http://github.com/kennytm/iphone-private-frameworks/tree/master/IOKit/hid