Android之Input子系统按键repeat

  Android系统中长按键部分:Linux驱动只是在起初按下时上报个down事件,在抬起后再报个up事件;其中,不会在有按键上报。对长按键的处理是在Android上层的InputDispatcher中,具体实现还未研究;如下是repeat的时间间隔设定地方。有空在对具体机制做分析。

一、repeat的时间间隔设定

1.Android2.3系统

frameworks/base/libs/ui/InputDispatcher.cpp
void 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.cpp
InputDispatcher::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;
}


你可能感兴趣的:(移动操作系统之Android)