原英文链接:IOHIDFamily
IOHIDFamily是一个内核扩展,它提供了与人类接口设备(HID)的抽象接口,例如触摸屏、按钮、加速度计等。在用户层级,有两种类型的API与IOHIDFamily相关:
(1).公开的,旨在为HID驱动程序编写者;
(2).私有的, 用于事件处理。此文档仅概述私有API。
公开的API文档可以在这里查看 documentation.
Class structure
IOHID的用户总是首先创建一个与整个HID系统接口的IOHIDEventSystem
对象。一个事件系统由多个IHIDService
和IOHIDDisplay
组成。
服务(Services)是 IOHIDLibPlugin
内核插件的各种接口(位于/System/Library/Extensions/IOHIDFamily.kext/PlugIns/IOHIDLib.plugin/IOHIDLib)。它们接受直接的事件输入(比如触摸事件),并且是所有IOHIDEvent
事件输入的来源。
显示 (Displays) 显然是指LCD显示屏,IOHIDDisplay
类只能控制亮度,不能控制单个像素的颜色(绘图是由VRAM负责). 你只能通过改变事件系统的属性来间接地控制显示。
IOHID定义了20种事件类型,其中SpringBoard 只处理4种事件:键盘(用于按钮)、数字化器(即触摸屏)、加速度计和靠近事件(温度事件由IOKit直接处理)。每个事件可能包含子事件。
iOS事件是由SpringBoard负责处理的。
例子
#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.
//创建和打开一个EventSystem
IOHIDEventSystemRef system = IOHIDEventSystemCreate(NULL);
IOHIDEventSystemOpen(system, handle_event, NULL, NULL, NULL);
//HID Event system 正在运行,点击屏幕接收到事件可触发handle_event 方法,
//然后Event system会停止运行并退出main方法。
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)
至少从iOS 6.1开始在IOHIDEventSystemCreate的函数中有一个检查,该检查将bundle identifier与“com.apple.springboard”进行比较。如果该检查失败,函数将返回NULL。因此,除非你绕过这个检查,否则你就不能再在应用程序中使用HID系统了,苹果应该偷偷换成别的方式创建事件系统了。
__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
要访问这些服务,您必须首先使用IOHIDEventSystemCopyMatchingServices匹配它们。这些标准可以使用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键盘事件
iOS按钮事件实际上被视为“键盘”事件,这里的按钮事件并不是指UIButton的点击事件。下面显示有哪些事件是按钮事件。
Usage page | Usage | Button |
---|---|---|
1 | 0x83 | Wake up 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耳机可用性改变 |
SpringBoard
SpringBoard是iPhone的应用程序启动器;它提供所有应用程序启动服务、图标管理、状态栏控制,等等,SpringBoard 是一个单例类管理着SpringBoard 应用。
。
从iOS 6开始,一些SpringBoard的功能现在在backboardd.
Workflow logging
SpringBoard保留UNIX信号31(SIGUSR2)来切换工作流日志记录。它可以记录来自显示堆栈的按下/弹出显示、应用程序启动等。从iOS 6.0开始,这个信号将切换SBWorkspace日志记录;它将输出到/tmp/SBWorkspaceLogs-date.log和syslog。
向SpringBoard发送信号31将在这4种日志类型之间切换:
- Stop logging.
- Start silent logging.
- Start logging to syslog.
- Dump workflow log.
HID logging
跳板保留UNIX信号30(SIGUSR1)来切换HID日志记录。它可以记录多点触摸事件、加速度计事件、按钮按下等。
向SpringBoard发送信号30将在这6种日志类型之间切换:
- Off.
- SpringBoard Events
- MultiTouch Gesture Events 多点触摸手势事件
- MultiTouch HID Events 多点触摸事件
- MultiTouch HID & Gesture Events 多点触摸HID和手势事件
- Accelerometer events 加速计事件
Monitoring Orientation of Top App
每当当前应用程序的方向发生改变时,[SpringBoard noteUIOrientationChanged:display:]
被调用。因此,可以挂钩(hook)此方法以做事件通知。
你也可以挂钩SpringBoard的方法
-(void)noteInterfaceOrientationChanged:(int)arg1 duration:(float)arg2
Orientation
activeInterfaceOrientation
显示当前应用方向
interfaceOrientationForCurrentDeviceOrientation
显示设备方向
问:什么时候会有所不同?
答:如果你把设备在portrait方向锁定,但是有一个游戏在landscape中运行,这两个值就会不同。activeInterfaceOrientation将处于landscape方向,而interfaceOrientationForCurrentDeviceOrientation仍将处于锁定的portrait方向。
Sending messages to SpringBoard
因为SpringBoard是从UIApplication继承的,所以您可以按照以下方式向它发送消息:
[[SpringBoard sharedApplication] aMethod]
Getting the top SBApplication
可以使用以下方法获得顶部SBApplication的引用:[[SpringBoard sharedApplication] _accessibilityFrontMostApplication].
Monitoring when a new app or the homescreen is displayed
无论app什么时候被显示 frontDisplayDidChange:(id)newDisplay
会被调用,newDisplay
是当前的被切换显示的app的引用(类型是SBApplication
指针),如果显示的是桌面屏幕则newDisplay
为nil
;然而,在某些情况下,它可能是一个UIViewController
的引用,比如当前进入锁屏状态时,newDisplay
会是一个SBLockScreenViewController
实例对象的引用。