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& eventHub,
const sp& readerPolicy,
const sp& 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& 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& eventHub,
const sp& readerPolicy,
const sp& 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) :
mLooper(looper) {
sp 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 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;
}