void InputReader::loopOnce() {
int32_t oldGeneration;
int32_t timeoutMillis;
// Copy some state so that we can access it outside the lock later.
bool inputDevicesChanged = false;
std::vector<InputDeviceInfo> inputDevices;
std::list<NotifyArgs> notifyArgs;
{ // acquire lock
std::scoped_lock _l(mLock);
oldGeneration = mGeneration;
timeoutMillis = -1;
auto changes = mConfigurationChangesToRefresh;
if (changes.any()) {
mConfigurationChangesToRefresh.clear();
timeoutMillis = 0;
refreshConfigurationLocked(changes);
} else if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
}
} // release lock
std::vector<RawEvent> events = mEventHub->getEvents(timeoutMillis);
{ // acquire lock
std::scoped_lock _l(mLock);
mReaderIsAliveCondition.notify_all();
if (!events.empty()) {
mPendingArgs += processEventsLocked(events.data(), events.size());
}
if (mNextTimeout != LLONG_MAX) {
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (now >= mNextTimeout) {
if (debugRawEvents()) {
ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
}
mNextTimeout = LLONG_MAX;
mPendingArgs += timeoutExpiredLocked(now);
}
}
if (oldGeneration != mGeneration) {
inputDevicesChanged = true;
inputDevices = getInputDevicesLocked();
mPendingArgs.emplace_back(
NotifyInputDevicesChangedArgs{mContext.getNextId(), inputDevices});
}
std::swap(notifyArgs, mPendingArgs);
// Keep track of the last used device
for (const NotifyArgs& args : notifyArgs) {
mLastUsedDeviceId = getDeviceIdOfNewGesture(args).value_or(mLastUsedDeviceId);
}
} // release lock
// Flush queued events out to the listener.
// This must happen outside of the lock because the listener could potentially call
// back into the InputReader's methods, such as getScanCodeState, or become blocked
// on another thread similarly waiting to acquire the InputReader lock thereby
// resulting in a deadlock. This situation is actually quite plausible because the
// listener is actually the input dispatcher, which calls into the window manager,
// which occasionally calls into the input reader.
for (const NotifyArgs& args : notifyArgs) {
mNextListener.notify(args);
}
// Notify the policy that input devices have changed.
// This must be done after flushing events down the listener chain to ensure that the rest of
// the listeners are synchronized with the changes before the policy reacts to them.
if (inputDevicesChanged) {
mPolicy->notifyInputDevicesChanged(inputDevices);
}
// Notify the policy of configuration change. This must be after policy is notified about input
// device changes so that policy can fetch newly added input devices on configuration change.
for (const auto& args : notifyArgs) {
const auto* configArgs = std::get_if<NotifyConfigurationChangedArgs>(&args);
if (configArgs != nullptr) {
mPolicy->notifyConfigurationChanged(configArgs->eventTime);
}
}
// Notify the policy of the start of every new stylus gesture.
for (const auto& args : notifyArgs) {
const auto* motionArgs = std::get_if<NotifyMotionArgs>(&args);
if (motionArgs != nullptr && isStylusPointerGestureStart(*motionArgs)) {
mPolicy->notifyStylusGestureStarted(motionArgs->deviceId, motionArgs->eventTime);
}
}
}
std::list<NotifyArgs> InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {
std::list<NotifyArgs> out;
for (const RawEvent* rawEvent = rawEvents; count;) {
int32_t type = rawEvent->type;
size_t batchSize = 1;
if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
int32_t deviceId = rawEvent->deviceId;
while (batchSize < count) {
if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT ||
rawEvent[batchSize].deviceId != deviceId) {
break;
}
batchSize += 1;
}
if (debugRawEvents()) {
ALOGD("BatchSize: %zu Count: %zu", batchSize, count);
}
out += processEventsForDeviceLocked(deviceId, rawEvent, batchSize);
} else {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
addDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::FINISHED_DEVICE_SCAN:
handleConfigurationChangedLocked(rawEvent->when);
break;
default:
ALOG_ASSERT(false); // can't happen
break;
}
}
count -= batchSize;
rawEvent += batchSize;
}
return out;
}
std::list<NotifyArgs> InputReader::processEventsForDeviceLocked(int32_t eventHubId,
const RawEvent* rawEvents,
size_t count) {
auto deviceIt = mDevices.find(eventHubId);
if (deviceIt == mDevices.end()) {
ALOGW("Discarding event for unknown eventHubId %d.", eventHubId);
return {};
}
std::shared_ptr<InputDevice>& device = deviceIt->second;
if (device->isIgnored()) {
// ALOGD("Discarding event for ignored deviceId %d.", deviceId);
return {};
}
//#ifdef OPLUS_EXTENSION_HOOK
//yang.y.liu@Game.Joystick, 2021/07/14, Add for joystick adapter
if (!getInputFlingerExt()->processEventsForDeviceLocked(device.get(), eventHubId, rawEvents, count)) {
ALOGV("game code processEventsForDeviceLocked return {}");
return {};
}
//#endif
return device->process(rawEvents, count);
}
std::list<NotifyArgs> InputDevice::process(const RawEvent* rawEvents, size_t count) {
// Process all of the events in order for each mapper.
// We cannot simply ask each mapper to process them in bulk because mappers may
// have side-effects that must be interleaved. For example, joystick movement events and
// gamepad button presses are handled by different mappers but they should be dispatched
// in the order received.
std::list<NotifyArgs> out;
for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
if (debugRawEvents()) {
const auto [type, code, value] =
InputEventLookup::getLinuxEvdevLabel(rawEvent->type, rawEvent->code,
rawEvent->value);
ALOGD("Input event: eventHubDevice=%d type=%s code=%s value=%s when=%" PRId64,
rawEvent->deviceId, type.c_str(), code.c_str(), value.c_str(), rawEvent->when);
}
if (mDropUntilNextSync) {
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
out += reset(rawEvent->when);
mDropUntilNextSync = false;
ALOGD_IF(debugRawEvents(), "Recovered from input event buffer overrun.");
} else {
ALOGD_IF(debugRawEvents(),
"Dropped input event while waiting for next input sync.");
}
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
mDropUntilNextSync = true;
} else {
for_each_mapper_in_subdevice(rawEvent->deviceId, [&](InputMapper& mapper) {
out += mapper.process(*rawEvent);
});
}
--count;
}
postProcess(out);
return out;
}
std::list<NotifyArgs> KeyboardInputMapper::process(const RawEvent& rawEvent) {
std::list<NotifyArgs> out;
mHidUsageAccumulator.process(rawEvent);
switch (rawEvent.type) {
//#ifdef OPLUS_FEATURE_INPUT
// Xingxing.Guo@ANDROID.INPUT, 7251550, 2024/06/06, add for spruce.
case EV_KEY: {
int32_t scanCode = rawEvent.code;
SpruceSwipEnable = false;
if ((scanCode == SPRUCE_SWIP_DOWN_SCAN_CODE || scanCode == SPRUCE_SWIP_UP_SCAN_CODE)
&& (rawEvent.value != 0)) {
SpruceSwipEnable = true;
SpruceScanCode = scanCode;
} else if (isSupportedScanCode(scanCode)) {
out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
}
break;
}
case EV_ABS: {
if (SpruceSwipEnable) {
ALOGI("EV_ABS ScanCode=0x%04x SpruceSwipValue=0x%08x", SpruceScanCode, rawEvent.value);
SpruceSwipValue = rawEvent.value;
out += processKey(rawEvent.when, rawEvent.readTime, true,
SpruceScanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
SpruceSwipEnable = false;
}
break;
}
default: {
SpruceSwipEnable = false;
break;
}
//#else
/* case EV_KEY: {
int32_t scanCode = rawEvent.code;
if (isSupportedScanCode(scanCode)) {
out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
}
} */
//#endif OPLUS_FEATURE_INPUT */
}
return out;
}
std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
int32_t scanCode, int32_t usageCode) {
std::list<NotifyArgs> out;
int32_t keyCode;
int32_t keyMetaState;
uint32_t policyFlags;
int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
&policyFlags)) {
keyCode = AKEYCODE_UNKNOWN;
keyMetaState = mMetaState;
policyFlags = 0;
}
nsecs_t downTime = when;
std::optional<size_t> keyDownIndex = findKeyDownIndex(scanCode);
//#ifdef OPLUS_FEATURE_ROTATE_VOLUMEKEY
//Xiaobo.Ding@ANDROID.Input 2022/09/09, Add for ROTATE_VOLUMEKEY
if (mSupportRotateVolume) {
keyCode = rotateVolumeKeyCode(keyCode, down);
}
//endif /* OPLUS_FEATURE_ROTATE_VOLUMEKEY */
if (down) {
// Rotate key codes according to orientation if needed.
if (mParameters.orientationAware) {
keyCode = rotateKeyCode(keyCode, getOrientation());
}
// Add key down.
if (keyDownIndex) {
// key repeat, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[*keyDownIndex].keyCode;
downTime = mKeyDowns[*keyDownIndex].downTime;
flags = mKeyDowns[*keyDownIndex].flags;
} else {
// key down
if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
return out;
}
if (policyFlags & POLICY_FLAG_GESTURE) {
out += getDeviceContext().cancelTouch(when, readTime);
flags |= AKEY_EVENT_FLAG_KEEP_TOUCH_MODE;
}
KeyDown keyDown;
keyDown.keyCode = keyCode;
keyDown.scanCode = scanCode;
keyDown.downTime = when;
keyDown.flags = flags;
mKeyDowns.push_back(keyDown);
}
onKeyDownProcessed(downTime);
} else {
// Remove key down.
if (keyDownIndex) {
// key up, be sure to use same keycode as before in case of rotation
keyCode = mKeyDowns[*keyDownIndex].keyCode;
downTime = mKeyDowns[*keyDownIndex].downTime;
flags = mKeyDowns[*keyDownIndex].flags;
mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex);
} else {
// key was not actually down
ALOGI("Dropping key up from device %s because the key was not down. "
"keyCode=%d, scanCode=%d",
getDeviceName().c_str(), keyCode, scanCode);
return out;
}
}
if (updateMetaStateIfNeeded(keyCode, down)) {
// If global meta state changed send it along with the key.
// If it has not changed then we'll use what keymap gave us,
// since key replacement logic might temporarily reset a few
// meta bits for given key.
keyMetaState = mMetaState;
}
DeviceId deviceId = getDeviceId();
// On first down: Process key for keyboard classification (will send reconfiguration if the
// keyboard type change)
if (down && !keyDownIndex) {
KeyboardClassifier& classifier = getDeviceContext().getContext()->getKeyboardClassifier();
classifier.processKey(deviceId, scanCode, keyMetaState);
getDeviceContext().setKeyboardType(classifier.getKeyboardType(deviceId));
}
KeyboardType keyboardType = getDeviceContext().getKeyboardType();
// Any key down on an external keyboard should wake the device.
// We don't do this for internal keyboards to prevent them from waking up in your pocket.
// For internal keyboards and devices for which the default wake behavior is explicitly
// prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
// wake key individually.
if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
!(keyboardType != KeyboardType::ALPHABETIC && isMediaKey(keyCode))) {
policyFlags |= POLICY_FLAG_WAKE;
}
//#ifndef OPLUS_FEATURE_INPUT_LASER
//Xingxing.Guo@ANDROID.6722667, 2024/03/04, add for pad laser
if (getDeviceContext().isLaserPencilDevice()) {
ALOGD("Laser from device %s "
"keyCode=%d, scanCode=%d",
getDeviceName().c_str(), keyCode, scanCode);
if (!mKeyboardConfig.oplusConfigParameters.laserEnabled) {
ALOGV("Laser is not supported!");
return out;
} else if (policyFlags & POLICY_FLAG_WAKE) {
policyFlags &= ~POLICY_FLAG_WAKE;
}
}
//#endif /* OPLUS_FEATURE_INPUT_LASER */
if (mParameters.handlesKeyRepeat) {
policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
}
//#ifdef OPLUS_FEATURE_INPUT
// Xingxing.Guo@ANDROID.INPUT, 7251550, 2024/06/06, add for spruce.
if (SpruceSwipEnable) {
SpruceSwipEnable = false;
when = SpruceSwipValue;
}
//#endif OPLUS_FEATURE_INPUT */
out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId, mSource,
getDisplayId(), policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags,
keyCode, scanCode, keyMetaState, downTime));
//#ifdef OPLUS_EXTENSION_DEBUG
//luochuang@ANDROID.INPUT, 2021/05/25, saupwkProcessKey feature
extern void __attribute__((weak)) saupwkProcessKey(int32_t scanCode, bool down);
if(saupwkProcessKey) {
ALOGV("theia start saupwkProcessKey");
saupwkProcessKey(scanCode, down);
}
//#endif /* OPLUS_EXTENSION_DEBUG */
return out;
}
这几段代码是获取按键亮屏中的部分,请告诉我每一个函数在其中的作用以及关键代码解释,在 KeyboardInputMapper::processKey最后的out返回到inputreader之后又要怎么执行,请基于安卓15源码正确详细讲解