一 概述
上一篇文章介绍了输入系统的大体运作流程,这篇文章详细介绍 Input 系统的启动。
Input 模块的主要组成:
- Native 层的 InputReader 负责从 EventHub 取出事件并处理,再交给 InputDispatcher
- Native 层的 InputDispatcher 接收来自 InputReader 传递过来的输入事件,并记录 WMS 的窗口信息,用于派发事件到合适的窗口
- Java 层的 InputManagerService 跟 WMS 交互,WMS 记录所有窗口信息,并同步更新到 IMS,为 InputDispatcher 正确派发事件到 ViewRootImpl 提供保障
Input 相关的动态库:
libinputflinger.so:frameworks/native/services/inputflinger/
libinputservice.so:frameworks/base/libs/input/
libinput.so: frameworks/native/libs/input/
涉及代码如下:
frameworks/native/services/inputflinger/
- InputDispatcher.cpp
- InputReader.cpp
- InputManager.cpp
- EventHub.cpp
- InputListener.cpp
frameworks/native/libs/input/
- InputTransport.cpp
- Input.cpp
- InputDevice.cpp
- Keyboard.cpp
- KeyCharacterMap.cpp
- IInputFlinger.cpp
frameworks/base/services/core/
- java/com/android/server/input/InputManagerService.java
- jni/com_android_server_input_InputManagerService.cpp
1.1 整体框架类图
InputManagerService 作为 system_server 中的重要服务,继承于 IInputManager.Stub, 作为 Binder 服务端,那么 Client 位于 InputManager 的内部通过 IInputManager.Stub.asInterface() 获取 Binder 代理端,C/S 两端通信的协议是由 IInputManager.aidl 来定义的。
Input 模块所涉及的重要类的关系如下:
- InputManagerService 位于 Java 层的 InputManagerService.java 文件,其成员 mPtr 指向 Native 层的 NativeInputManager 对象
- NativeInputManager 位于 Native 层的 com_android_server_input_InputManagerService.cpp 文件,其成员 mServiceObj 指向 Java 层的 IMS 对象;其成员 mLooper 是指 “android.display” 线程的 Looper
- InputManager 位于 libinputflinger 中的 InputManager.cpp 文件
InputDispatcher 和 InputReader 的成员变量 mPolicy 都是指 NativeInputManager 对象
InputReader 的成员 mQueuedListener,数据类型为 QueuedInputListener;通过其内部成员变量 mInnerListener 指向 InputDispatcher 对象;这便是 InputReader 跟 InputDispatcher 交互的中间枢纽。
1.2 启动调用栈
IMS 服务是伴随着 system_server 进程的启动而启动的,整个调用过程如下:
InputManagerService(初始化)
nativeInit
NativeInputManager
InputManager
InputDispatcher
Looper
InputReader
EventHub
QueuedInputListener
InputReaderThread
InputDispatcherThread
IMS.start(启动)
nativeStart
InputManager.start
InputReaderThread->run
InputDispatcherThread->run
整个过程首先创建如下对象:NativeInputManager,EventHub,InputManager, InputDispatcher,InputReader,InputReaderThread,InputDispatcherThread。 接着便是启动两个工作线程 InputReaderThread 和 InputDispatcherThread。
二 启动过程
private void startOtherServices() {
......
InputManagerService inputManager = null;
//初始化IMS对象
inputManager = new InputManagerService(context);
//把inputManager的引用放到WMS中,建立联系
wm = WindowManagerService.main(context, inputManager,
mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
!mFirstBoot, mOnlyCore, new PhoneWindowManager());
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
//设置回调,将WMS中的InputManagerCallback设置到inputManager中
//这里说明了最终如何回调到PhoneWindowManager
inputManager.setWindowManagerCallbacks(wm.getInputManagerCallback());
inputManager.start();
......
}
2.1 InputManagerService
public InputManagerService(Context context) {
this.mContext = context;
// 创建了InputManagerHandler,其Looper是DisplayThead的Looper
// 运行在线程"android.display"
this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());
......
//初始化native对象
mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
LocalServices.addService(InputManagerInternal.class, new LocalService());
}
2.2 nativeInit
static jlong nativeInit(JNIEnv* env, jclass /* clazz */,
jobject serviceObj, jobject contextObj, jobject messageQueueObj) {
//获取native消息队列
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(
env, messageQueueObj);
......
//创建Native的InputManager
NativeInputManager* im = new NativeInputManager(contextObj, serviceObj,
messageQueue->getLooper());
im->incStrong(0);
//返回Native对象的指针给IMS,IMS后续会用到。IMS保存在mPtr
return reinterpret_cast<jlong>(im);
}
2.3 NativeInputManager
NativeInputManager::NativeInputManager(jobject contextObj,
jobject serviceObj, const sp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mServiceObj = env->NewGlobalRef(serviceObj);//上层IMS对象
......
// 创建InputManager对象
mInputManager = new InputManager(this, this);
defaultServiceManager()->addService(String16("inputflinger"),
mInputManager, false);
}
此处的 mLooper 是指 “android.display” 线程的 Looper。
2.4 InputManager
sp<InputReaderInterface> mReader;
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
//创建InputDispatcher对象
mDispatcher = new InputDispatcher(dispatcherPolicy);
mClassifier = new InputClassifier(mDispatcher);
//创建InputReader对象
mReader = createInputReader(readerPolicy, mClassifier);
initialize();
}
InputDispatcher 和 InputReader 的 mPolicy 成员变量都是指 NativeInputManager 对象:
class NativeInputManager : public virtual RefBase,
public virtual InputReaderPolicyInterface,
public virtual InputDispatcherPolicyInterface,
public virtual PointerControllerPolicyInterface {
......
}
2.5 createInputReader
framework/native/services/inputflinger/InputReaderFactory.cpp
sp<InputReaderInterface> createInputReader(
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
return new InputReader(new EventHub(), policy, listener);
}
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) :
mContext(this), mEventHub(eventHub), mPolicy(policy),
mNextSequenceNum(1), mGlobalMetaState(0), mGeneration(1),
mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX),
mConfigurationChangesToRefresh(0) {
// 创建输入监听对象
mQueuedListener = new QueuedInputListener(listener);
{
AutoMutex _l(mLock);
refreshConfigurationLocked(0);
updateGlobalMetaStateLocked();
}
}
此处的 listener 便是 InputDispatcher 对象,赋值给了 mQueuedListener 的成员变量 mInnerListener,这样 InputDispatcher 和 InputReader 便建立起了联系。同时我们可以看到在生成 InputReader 的时候,new 了一个 EventHub 对象。
2.6 EventHub
EventHub::EventHub(void) :
mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
mOpeningDevices(nullptr), mClosingDevices(nullptr),
mNeedToSendFinishedDeviceScan(false),
mNeedToReopenDevices(false), mNeedToScanDevices(true),
mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID);
//创建epoll对象,mEpollFd为epoll对象的描述符
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
//创建inotify对象,mINotifyFd为inotify对象的描述符
mINotifyFd = inotify_init();
//此处DEVICE_PATH为"/dev/input",监听该目录下的设备节点创建与删除操作。通过read函数读取事件
mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
......
struct epoll_event eventItem;
memset(&eventItem, 0, sizeof(eventItem));
eventItem.events = EPOLLIN;//监听可读事件
eventItem.data.fd = mINotifyFd;
//添加INotify到epoll实例
//EPOLL_CTL_ADD表示增加事件
//epoll_ctl将事件监听添加到epoll对象中去。
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
int wakeFds[2];
result = pipe(wakeFds); //创建管道
mWakeReadPipeFd = wakeFds[0];
mWakeWritePipeFd = wakeFds[1];
//将pipe的读和写都设置为非阻塞方式
result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK);
result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK);
eventItem.data.fd = mWakeReadPipeFd;
//添加管道的读端到epoll实例
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
......
}
该方法主要功能:
- 初始化一些成员变量
- 创建 epoll 对象
- 创建 INotify 对象,监听 ”/dev/input” 下设备节点的增删
- 将 mINotifyFd 添加到 epoll 中,作为一个监控对象
- 创建非阻塞模式的管道,将管道读取端的可读事件添加到 epoll 中,使 epoll_wait() 返回,唤醒 InputReader 线程
2.7 InputDispatcher
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
mPolicy(policy),
mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED),
mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
mNextUnblockedEvent(nullptr),
mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
mLooper = new Looper(false);//创建Looper对象
mReporter = createInputReporter();
mKeyRepeatState.lastKeyEntry = nullptr;
//获取分发超时参数
policy->getDispatcherConfiguration(&mConfig);
}
该方法主要工作:
- 创建属于自己线程的 Looper 对象
- 超时参数来自于 IMS,参数默认值 keyRepeatTimeout = 500,keyRepeatDelay = 50
2.8 initialize
void InputManager::initialize() {
mReaderThread = new InputReaderThread(mReader);
mDispatcherThread = new InputDispatcherThread(mDispatcher);
}
InputReaderThread::InputReaderThread(
const sp<InputReaderInterface>& reader) :
Thread(/*canCallJava*/ true), mReader(reader) {
}
InputDispatcherThread::InputDispatcherThread(
const sp<InputDispatcherInterface>& dispatcher) :
Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}
初始化的主要工作就是创建 InputReaderThread 和 InputDispatcherThread 两个线程,一个用于对输入事件的读取,另一个用于对输入事件的分发。
到此整个 InputManagerService 对象的初始化过程已经分析完毕,接下来分析其 start 方法。
2.9 IMS.start
public void start() {
// 启动native对象
nativeStart(mPtr);
Watchdog.getInstance().addMonitor(this);
//注册触摸点速度和是否显示功能的观察者
registerPointerSpeedSettingObserver();
registerShowTouchesSettingObserver();
registerAccessibilityLargePointerSettingObserver();
registerLongPressTimeoutObserver();
mContext.registerReceiver(new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
updatePointerSpeedFromSettings();
updateShowTouchesFromSettings();
updateAccessibilityLargePointerFromSettings();
updateDeepPressStatusFromSettings("user switched");
}
}, new IntentFilter(Intent.ACTION_USER_SWITCHED), null, mHandler);
updatePointerSpeedFromSettings(); //更新触摸点的速度
updateShowTouchesFromSettings(); //是否在屏幕上显示触摸点
updateAccessibilityLargePointerFromSettings();
updateDeepPressStatusFromSettings("just booted");
}
2.10 nativeStart
com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) {
//此处ptr记录的便是NativeInputManager
NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
status_t result = im->getInputManager()->start();
if (result) {
jniThrowRuntimeException(env, "Input manager could not be started.");
}
}
2.11 InputManager.start
status_t InputManager::start() {
status_t result =
mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);
result =
mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);
......
return OK;
}
可以看到该方法的主要功能是启动 InputReader 和 InputDispatcher 两个线程。
三 总结
分层视角
- Java 层 InputManagerService:采用 android.display 线程处理 Message
- JNI 的 NativeInputManager:采用 android.display 线程处理 Message
- Native 的 InputManager:创建 InputReaderThread 和 InputDispatcherThread 两个线程,以及创建 EventHub
主要功能
- IMS 服务中的成员变量 mPtr 记录 Native 层的 NativeInputManager 对象
- IMS 对象的初始化过程的重点在于 native 的初始化,分别创建了以下对象:
NativeInputManager
EventHub, InputManager
InputReader,InputDispatcher
InputReaderThread,InputDispatcherThread - IMS 启动过程的主要功能是启动以下两个线程:
InputReader:从 EventHub 取出事件并处理,再交给 InputDispatcher
InputDispatcher:接收来自 InputReader 的输入事件,并派发事件到合适的窗口
从 IMS 的整个启动过程中可知 system_server 进程中有3个线程跟 Input 输入系统息息相关,分别是 android.display,InputReader 和 InputDispatcher。
- InputDispatcher 线程:属于 Looper 线程,会创建属于自己的 Looper,循环分发消息
- InputReader 线程:通过 getEvents() 调用 EventHub 读取输入事件,循环读取消息
- android.display 线程:属于 Looper 线程,用于处理 Java 层的 IMS.InputManagerHandler 和 JNI 层的 NativeInputManager 中指定的 MessageHandler 消息
Input 事件流程:Linux Kernel -> IMS(InputReader -> InputDispatcher) -> WMS -> ViewRootImpl, 后续再进一步介绍。
四 附录
最后列举下整个 input 处理流程中常见的重要对象或结构体,方便查看。
4.1 InputReader.h
4.1.1 InputDevice
class InputDevice {
public:
InputDevice(InputReaderContext* context, int32_t id,
int32_t generation, int32_t controllerNumber,
const InputDeviceIdentifier& identifier, uint32_t classes);
......
private:
InputReaderContext* mContext;
int32_t mId;
int32_t mGeneration;
int32_t mControllerNumber;
InputDeviceIdentifier mIdentifier;
std::string mAlias;
uint32_t mClasses;
std::vector<InputMapper*> mMappers;
uint32_t mSources;
bool mIsExternal;
std::optional<uint8_t> mAssociatedDisplayPort;
bool mHasMic;
bool mDropUntilNextSync;
typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask,
int32_t code);
int32_t getState(uint32_t sourceMask, int32_t code,
GetStateFunc getStateFunc);
PropertyMap mConfiguration;
};
4.2 InputDispatcher.h
4.2.1 DropReason
enum DropReason {
DROP_REASON_NOT_DROPPED = 0,
DROP_REASON_POLICY = 1,
DROP_REASON_APP_SWITCH = 2,
DROP_REASON_DISABLED = 3,
DROP_REASON_BLOCKED = 4,
DROP_REASON_STALE = 5,
};
enum InputTargetWaitCause {
INPUT_TARGET_WAIT_CAUSE_NONE,
INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY,
INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY,
};
sp<Looper> mLooper;
EventEntry* mPendingEvent GUARDED_BY(mLock);
Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>
mWindowHandlesByDisplay GUARDED_BY(mLock);
// Get window handles by display, return an empty vector if not found.
std::vector<sp<InputWindowHandle>> getWindowHandlesLocked(int32_t displayId)
const REQUIRES(mLock);
sp<InputWindowHandle> getWindowHandleLocked(const sp<IBinder>& windowHandleToken)
const REQUIRES(mLock);
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken)
const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle)
const REQUIRES(mLock);
// Focus tracking for keys, trackball, etc.
std::unordered_map<int32_t, sp<InputWindowHandle>>
mFocusedWindowHandlesByDisplay GUARDED_BY(mLock);
InputTargetWaitCause mInputTargetWaitCause GUARDED_BY(mLock);
nsecs_t mInputTargetWaitStartTime GUARDED_BY(mLock);
nsecs_t mInputTargetWaitTimeoutTime GUARDED_BY(mLock);
bool mInputTargetWaitTimeoutExpired GUARDED_BY(mLock);
//目标等待的应用
sp<IBinder> mInputTargetWaitApplicationToken GUARDED_BY(mLock);
4.2.2 Connection
class Connection : public RefBase {
protected:
virtual ~Connection();
public:
enum Status {
STATUS_NORMAL,//正常状态
STATUS_BROKEN,//发生无法恢复的错误
STATUS_ZOMBIE//input channel被注销掉
};
Status status;//状态
sp<InputChannel> inputChannel; //永不为空
bool monitor;
InputPublisher inputPublisher;
InputState inputState;
// True if the socket is full and no further events can be
// published until the application consumes some of the input.
//当socket占满的同时,应用消费某些输入事件之前无法发布事件,则值为true.
bool inputPublisherBlocked;
// Queue of events that need to be published to the connection.
//需要被发布到connection的事件队列
Queue<DispatchEntry> outboundQueue;
// Queue of events that have been published to the
// connection but that have not yet received a "finished" response
// from the application.
//已发布到connection,但还没有收到来自应用的“finished”响应的事件队列
Queue<DispatchEntry> waitQueue;
};
4.2.3 EventEntry
struct EventEntry : Link<EventEntry> {
//type的取值
enum {
TYPE_CONFIGURATION_CHANGED,
TYPE_DEVICE_RESET,
TYPE_KEY,//按键事件
TYPE_MOTION//触摸事件
};
uint32_t sequenceNum;
mutable int32_t refCount;
int32_t type;//事件类型
nsecs_t eventTime;//事件时间
uint32_t policyFlags;
InjectionState* injectionState;
bool dispatchInProgress; //初始值为false, 分发过程则设置成true
};
4.2.4 INPUT_EVENT_INJECTION
enum {
// 内部使用, 正在执行注入操作
INPUT_EVENT_INJECTION_PENDING = -1,
// 事件注入成功
INPUT_EVENT_INJECTION_SUCCEEDED = 0,
// 事件注入失败, 由于injector没有权限将聚焦的input事件注入到应用
INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1,
// 事件注入失败, 由于没有可用的input target
INPUT_EVENT_INJECTION_FAILED = 2,
// 事件注入失败, 由于超时
INPUT_EVENT_INJECTION_TIMED_OUT = 3
};
4.2.5 InputTarget
struct InputTarget {
enum {
FLAG_FOREGROUND = 1 << 0, //事件分发到前台app
FLAG_WINDOW_IS_OBSCURED = 1 << 1,
FLAG_SPLIT = 1 << 2, //MotionEvent被拆分成多窗口
FLAG_ZERO_COORDS = 1 << 3,
FLAG_DISPATCH_AS_IS = 1 << 8, //
FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, //
FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, //
FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, //
FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, //
FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, //
FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 1 << 14,
//所有分发模式的掩码
FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS
| FLAG_DISPATCH_AS_OUTSIDE
| FLAG_DISPATCH_AS_HOVER_ENTER
| FLAG_DISPATCH_AS_HOVER_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_EXIT
| FLAG_DISPATCH_AS_SLIPPERY_ENTER,
};
sp<InputChannel> inputChannel; //目标的inputChannel
int32_t flags;
float xOffset, yOffset; //用于MotionEvent
float globalScaleFactor; //用于MotionEvent
BitSet32 pointerIds;
};
4.3 InputTransport.h
4.3.1 InputChannel
class InputChannel : public RefBase {
// 创建一对input channels
static status_t openInputChannelPair(const String8& name,
sp<InputChannel>& outServerChannel,
sp<InputChannel>& outClientChannel);
status_t sendMessage(const InputMessage* msg); //发送消息
status_t receiveMessage(InputMessage* msg); //接收消息
//获取InputChannel的fd的拷贝
sp<InputChannel> dup() const;
private:
void setFd(int fd);
std::string mName;
int mFd = -1;
sp<IBinder> mToken = nullptr;
};
sendMessage 的返回值
- OK:代表成功
- WOULD_BLOCK:代表 Channel 已满
- DEAD_OBJECT:代表 Channel 已关闭
receiveMessage 的返回值
- OK:代表成功
- WOULD_BLOCK:代表 Channel 为空
- DEAD_OBJECT:代表 Channel 已关闭
4.3.2 InputPublisher
class InputPublisher {
public:
//获取输入通道
inline sp<InputChannel> getChannel() { return mChannel; }
status_t publishKeyEvent(...); //将key event发送到input channel
status_t publishMotionEvent(...); //将motion event发送到input channel
//接收来自InputConsumer发送的完成信号
status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
sp<InputChannel> mChannel;
};
4.3.3 InputConsumer
class InputConsumer {
public:
inline sp<InputChannel> getChannel() { return mChannel; }
status_t consume(...); //消费input channel的事件
//向InputPublisher发送完成信号
status_t sendFinishedSignal(uint32_t seq, bool handled);
bool hasDeferredEvent() const;
bool hasPendingBatch() const;
private:
sp<InputChannel> mChannel;
InputMessage mMsg; //当前input消息
bool mMsgDeferred;
Vector<Batch> mBatches; //input批量消息
Vector<TouchState> mTouchStates;
Vector<SeqChain> mSeqChains;
status_t consumeBatch(...);
status_t consumeSamples(...);
static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
}
4.4 input.h
4.4.1 KeyEvent
class KeyEvent : public InputEvent {
......
protected:
int32_t mAction;
int32_t mFlags;
int32_t mKeyCode;
int32_t mScanCode;
int32_t mMetaState;
int32_t mRepeatCount;
nsecs_t mDownTime; //专指按下时间
nsecs_t mEventTime; //事件发生时间(包括down/up等事件)
}
4.4.2 MotionEvent
class MotionEvent : public InputEvent {
......
protected:
int32_t mAction;
int32_t mActionButton;
int32_t mFlags;
int32_t mEdgeFlags;
int32_t mMetaState;
int32_t mButtonState;
float mXOffset;
float mYOffset;
float mXPrecision;
float mYPrecision;
nsecs_t mDownTime; //按下时间
Vector<PointerProperties> mPointerProperties;
Vector<nsecs_t> mSampleEventTimes;
Vector<PointerCoords> mSamplePointerCoords;
};
}
4.5 InputListener.h
4.5.1 NotifyKeyArgs
struct NotifyKeyArgs : public NotifyArgs {
int32_t deviceId;
uint32_t source;
uint32_t policyFlags;
int32_t action;
int32_t flags;
int32_t keyCode;
int32_t scanCode;
int32_t metaState;
nsecs_t downTime; //按下时间
......
};