Android系统中长按键部分:Linux驱动只是在起初按下时上报个down事件,在抬起后再报个up事件;其中,不会在有按键上报。对长按键的处理是在Android上层的InputDispatcher中,具体实现还未研究;如下是repeat的时间间隔设定地方。有空在对具体机制做分析。
一、repeat的时间间隔设定1.Android2.3系统
frameworks/base/libs/ui/InputDispatcher.cppvoid InputDispatcher::dispatchOnce() { nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout(); nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay(); nsecs_t nextWakeupTime = LONG_LONG_MAX; }frameworks/base/libs/ui/InputManager.cpp
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); }
frameworks/base/service/jni/com_android_server_InputManager.cpp
NativeInputManager::NativeInputManager(jobject callbacksObj) : mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mMaxEventsPerSecond(-1), mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) { mInputManager = new InputManager(eventHub, this, this); } nsecs_t NativeInputManager::getKeyRepeatTimeout() { return milliseconds_to_nanoseconds(500); } nsecs_t NativeInputManager::getKeyRepeatDelay() { return milliseconds_to_nanoseconds(50); }
2.Android4.0系统
frameworks/base/services/input/InputDispatcher.cppInputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) : mPolicy(policy), mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(NULL), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); mKeyRepeatState.lastKeyEntry = NULL; policy->getDispatcherConfiguration(&mConfig); }frameworks/base/services/input/InputManager.cpp
InputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); }frameworks/base/services/jni/com_android_server_input_InputManagerService.cpp
NativeInputManager::NativeInputManager(jobject contextObj, jobject serviceObj, const sp<Looper>& looper) : mLooper(looper) { sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); } void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) { jint keyRepeatTimeout = env->CallIntMethod(mServiceObj, gServiceClassInfo.getKeyRepeatTimeout); outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout); jint keyRepeatDelay = env->CallIntMethod(mServiceObj, gServiceClassInfo.getKeyRepeatDelay); outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay); } FIND_CLASS(clazz, "com/android/server/input/InputManagerService"); GET_METHOD_ID(gServiceClassInfo.getKeyRepeatDelay, clazz, "getKeyRepeatDelay", "()I");frameworks/base/services/java/com/android/server/input/InputManagerService.java
private int getKeyRepeatDelay() { return ViewConfiguration.getKeyRepeatDelay(); }
frameworks/base/core/java/android/view/ViewConfiguration.java
public static int getKeyRepeatDelay() { return KEY_REPEAT_DELAY; } private static final int KEY_REPEAT_DELAY = 150; //50 change by tank
二、项目问题
目前遇到问题是:我们的一个面板设备发送按键给上层,并在PhoneWindowManager做截断;完后重新写入另外一个设备,完成上报。调试中发现,当这两个不同设备的按键值一样时、Android的repeat不起作用。后调试发现是repeat只支持一个设备的。后经过改动,ok;请看如下add by tankai部分:
frameworks/base/service/input/InputDispatcher.cpp
void InputDispatcher::dispatchOnce() { dispatchOnceInnerLocked(&nextWakeupTime); } void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { if (mKeyRepeatState.lastKeyEntry) { if (currentTime >= mKeyRepeatState.nextRepeatTime) { //必须是下一个repeat时间到了 mPendingEvent = synthesizeKeyRepeatLocked(currentTime); /* InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { entry->syntheticRepeat = true; entry->refCount += 1; mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; } */ } } done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { if (mKeyRepeatState.lastKeyEntry && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode /*add by tankai*/&& mKeyRepeatState.lastKeyEntry->deviceId == entry->deviceId) { } mKeyRepeatState.lastKeyEntry = entry; if (entry->repeatCount == 1) { entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; } else { entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; } }
另外一种修改方法,不让该设备进入repeat:
frameworks/base/service/input/EventHub.cpp
status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t* outKeycode, uint32_t* outFlags) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); if (device) { // Check the key character map first. sp<KeyCharacterMap> kcm = device->getKeyCharacterMap(); if (kcm != NULL) { if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { *outFlags = 0; return NO_ERROR; } } // Check the key layout next. if (device->keyMap.haveKeyLayout()) { if (!device->keyMap.keyLayoutMap->mapKey( scanCode, usageCode, outKeycode, outFlags)) { //add by tankai if(!strncmp(device->identifier.name.string(),"Smart_TV_Keypad",15)){ (*outFlags) |= POLICY_FLAG_DISABLE_KEY_REPEAT; ALOGD("TK--->>this is Smart_TV_Keypad\n"); } //end tankai return NO_ERROR; } } } *outKeycode = 0; *outFlags = 0; return NAME_NOT_FOUND; }