| /* |
| * Copyright (C) 2019 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // clang-format off |
| #include "../Macros.h" |
| // clang-format on |
| |
| #include "CursorInputMapper.h" |
| |
| #include <com_android_input_flags.h> |
| #include <optional> |
| |
| #include "CursorButtonAccumulator.h" |
| #include "CursorScrollAccumulator.h" |
| #include "PointerControllerInterface.h" |
| #include "TouchCursorInputMapperCommon.h" |
| |
| #include "input/PrintTools.h" |
| |
| namespace input_flags = com::android::input::flags; |
| |
| namespace android { |
| |
| // The default velocity control parameters that has no effect. |
| static const VelocityControlParameters FLAT_VELOCITY_CONTROL_PARAMS{}; |
| |
| // --- CursorMotionAccumulator --- |
| |
| CursorMotionAccumulator::CursorMotionAccumulator() { |
| clearRelativeAxes(); |
| } |
| |
| void CursorMotionAccumulator::reset(InputDeviceContext& deviceContext) { |
| clearRelativeAxes(); |
| } |
| |
| void CursorMotionAccumulator::clearRelativeAxes() { |
| mRelX = 0; |
| mRelY = 0; |
| } |
| |
| void CursorMotionAccumulator::process(const RawEvent* rawEvent) { |
| if (rawEvent->type == EV_REL) { |
| switch (rawEvent->code) { |
| case REL_X: |
| mRelX = rawEvent->value; |
| break; |
| case REL_Y: |
| mRelY = rawEvent->value; |
| break; |
| } |
| } |
| } |
| |
| void CursorMotionAccumulator::finishSync() { |
| clearRelativeAxes(); |
| } |
| |
| // --- CursorInputMapper --- |
| |
| CursorInputMapper::CursorInputMapper(InputDeviceContext& deviceContext, |
| const InputReaderConfiguration& readerConfig) |
| : InputMapper(deviceContext, readerConfig), |
| mLastEventTime(std::numeric_limits<nsecs_t>::min()), |
| mEnablePointerChoreographer(input_flags::enable_pointer_choreographer()) {} |
| |
| CursorInputMapper::~CursorInputMapper() { |
| if (mPointerController != nullptr) { |
| mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); |
| } |
| } |
| |
| uint32_t CursorInputMapper::getSources() const { |
| return mSource; |
| } |
| |
| void CursorInputMapper::populateDeviceInfo(InputDeviceInfo& info) { |
| InputMapper::populateDeviceInfo(info); |
| |
| if (mParameters.mode == Parameters::Mode::POINTER) { |
| if (!mBoundsInLogicalDisplay.isEmpty()) { |
| info.addMotionRange(AMOTION_EVENT_AXIS_X, mSource, mBoundsInLogicalDisplay.left, |
| mBoundsInLogicalDisplay.right, 0.0f, 0.0f, 0.0f); |
| info.addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, mBoundsInLogicalDisplay.top, |
| mBoundsInLogicalDisplay.bottom, 0.0f, 0.0f, 0.0f); |
| } |
| } else { |
| info.addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); |
| info.addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); |
| info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, |
| 0.0f); |
| info.addMotionRange(AMOTION_EVENT_AXIS_RELATIVE_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, |
| 0.0f); |
| } |
| info.addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); |
| |
| if (mCursorScrollAccumulator.haveRelativeVWheel()) { |
| info.addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); |
| } |
| if (mCursorScrollAccumulator.haveRelativeHWheel()) { |
| info.addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); |
| } |
| } |
| |
| void CursorInputMapper::dump(std::string& dump) { |
| dump += INDENT2 "Cursor Input Mapper:\n"; |
| dumpParameters(dump); |
| dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale); |
| dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale); |
| dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision); |
| dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision); |
| dump += StringPrintf(INDENT3 "HaveVWheel: %s\n", |
| toString(mCursorScrollAccumulator.haveRelativeVWheel())); |
| dump += StringPrintf(INDENT3 "HaveHWheel: %s\n", |
| toString(mCursorScrollAccumulator.haveRelativeHWheel())); |
| dump += StringPrintf(INDENT3 "WheelYVelocityControlParameters: %s", |
| mWheelYVelocityControl.getParameters().dump().c_str()); |
| dump += StringPrintf(INDENT3 "WheelXVelocityControlParameters: %s", |
| mWheelXVelocityControl.getParameters().dump().c_str()); |
| dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); |
| dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); |
| dump += StringPrintf(INDENT3 "DisplayId: %s\n", toString(mDisplayId).c_str()); |
| dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation); |
| dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState); |
| dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); |
| dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime); |
| } |
| |
| std::list<NotifyArgs> CursorInputMapper::reconfigure(nsecs_t when, |
| const InputReaderConfiguration& readerConfig, |
| ConfigurationChanges changes) { |
| std::list<NotifyArgs> out = InputMapper::reconfigure(when, readerConfig, changes); |
| |
| if (!changes.any()) { // first time only |
| configureBasicParams(); |
| } |
| |
| const bool configurePointerCapture = !changes.any() || |
| (mParameters.mode != Parameters::Mode::NAVIGATION && |
| changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE)); |
| if (configurePointerCapture) { |
| configureOnPointerCapture(readerConfig); |
| out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId())); |
| } |
| |
| if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || |
| configurePointerCapture) { |
| configureOnChangePointerSpeed(readerConfig); |
| } |
| |
| if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || |
| configurePointerCapture) { |
| configureOnChangeDisplayInfo(readerConfig); |
| } |
| return out; |
| } |
| |
| CursorInputMapper::Parameters CursorInputMapper::computeParameters( |
| const InputDeviceContext& deviceContext) { |
| Parameters parameters; |
| parameters.mode = Parameters::Mode::POINTER; |
| const PropertyMap& config = deviceContext.getConfiguration(); |
| std::optional<std::string> cursorModeString = config.getString("cursor.mode"); |
| if (cursorModeString.has_value()) { |
| if (*cursorModeString == "navigation") { |
| parameters.mode = Parameters::Mode::NAVIGATION; |
| } else if (*cursorModeString != "pointer" && *cursorModeString != "default") { |
| ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString->c_str()); |
| } |
| } |
| |
| parameters.orientationAware = config.getBool("cursor.orientationAware").value_or(false); |
| |
| parameters.hasAssociatedDisplay = false; |
| if (parameters.mode == Parameters::Mode::POINTER || parameters.orientationAware) { |
| parameters.hasAssociatedDisplay = true; |
| } |
| return parameters; |
| } |
| |
| void CursorInputMapper::dumpParameters(std::string& dump) { |
| dump += INDENT3 "Parameters:\n"; |
| dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n", |
| toString(mParameters.hasAssociatedDisplay)); |
| dump += StringPrintf(INDENT4 "Mode: %s\n", ftl::enum_string(mParameters.mode).c_str()); |
| dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware)); |
| } |
| |
| std::list<NotifyArgs> CursorInputMapper::reset(nsecs_t when) { |
| mButtonState = 0; |
| mDownTime = 0; |
| mLastEventTime = std::numeric_limits<nsecs_t>::min(); |
| |
| mPointerVelocityControl.reset(); |
| mWheelXVelocityControl.reset(); |
| mWheelYVelocityControl.reset(); |
| |
| mCursorButtonAccumulator.reset(getDeviceContext()); |
| mCursorMotionAccumulator.reset(getDeviceContext()); |
| mCursorScrollAccumulator.reset(getDeviceContext()); |
| |
| return InputMapper::reset(when); |
| } |
| |
| std::list<NotifyArgs> CursorInputMapper::process(const RawEvent* rawEvent) { |
| std::list<NotifyArgs> out; |
| mCursorButtonAccumulator.process(rawEvent); |
| mCursorMotionAccumulator.process(rawEvent); |
| mCursorScrollAccumulator.process(rawEvent); |
| |
| if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { |
| const auto [eventTime, readTime] = |
| applyBluetoothTimestampSmoothening(getDeviceContext().getDeviceIdentifier(), |
| rawEvent->when, rawEvent->readTime, |
| mLastEventTime); |
| out += sync(eventTime, readTime); |
| mLastEventTime = eventTime; |
| } |
| return out; |
| } |
| |
| std::list<NotifyArgs> CursorInputMapper::sync(nsecs_t when, nsecs_t readTime) { |
| std::list<NotifyArgs> out; |
| if (!mDisplayId) { |
| // Ignore events when there is no target display configured. |
| return out; |
| } |
| |
| int32_t lastButtonState = mButtonState; |
| int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); |
| mButtonState = currentButtonState; |
| |
| bool wasDown = isPointerDown(lastButtonState); |
| bool down = isPointerDown(currentButtonState); |
| bool downChanged; |
| if (!wasDown && down) { |
| mDownTime = when; |
| downChanged = true; |
| } else if (wasDown && !down) { |
| downChanged = true; |
| } else { |
| downChanged = false; |
| } |
| nsecs_t downTime = mDownTime; |
| bool buttonsChanged = currentButtonState != lastButtonState; |
| int32_t buttonsPressed = currentButtonState & ~lastButtonState; |
| int32_t buttonsReleased = lastButtonState & ~currentButtonState; |
| |
| float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; |
| float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; |
| bool moved = deltaX != 0 || deltaY != 0; |
| |
| // Rotate delta according to orientation. |
| rotateDelta(mOrientation, &deltaX, &deltaY); |
| |
| // Move the pointer. |
| PointerProperties pointerProperties; |
| pointerProperties.clear(); |
| pointerProperties.id = 0; |
| pointerProperties.toolType = ToolType::MOUSE; |
| |
| PointerCoords pointerCoords; |
| pointerCoords.clear(); |
| |
| float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); |
| float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); |
| bool scrolled = vscroll != 0 || hscroll != 0; |
| |
| mWheelYVelocityControl.move(when, nullptr, &vscroll); |
| mWheelXVelocityControl.move(when, &hscroll, nullptr); |
| |
| mPointerVelocityControl.move(when, &deltaX, &deltaY); |
| |
| float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; |
| float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION; |
| if (mSource == AINPUT_SOURCE_MOUSE) { |
| if (!mEnablePointerChoreographer) { |
| if (moved || scrolled || buttonsChanged) { |
| mPointerController->setPresentation( |
| PointerControllerInterface::Presentation::POINTER); |
| |
| if (moved) { |
| mPointerController->move(deltaX, deltaY); |
| } |
| mPointerController->unfade(PointerControllerInterface::Transition::IMMEDIATE); |
| } |
| |
| std::tie(xCursorPosition, yCursorPosition) = mPointerController->getPosition(); |
| |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition); |
| } |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); |
| } else { |
| // Pointer capture and navigation modes |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY); |
| } |
| |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); |
| |
| // Moving an external trackball or mouse should wake the device. |
| // We don't do this for internal cursor devices to prevent them from waking up |
| // the device in your pocket. |
| // TODO: Use the input device configuration to control this behavior more finely. |
| uint32_t policyFlags = 0; |
| if ((buttonsPressed || moved || scrolled) && getDeviceContext().isExternal()) { |
| policyFlags |= POLICY_FLAG_WAKE; |
| } |
| |
| // Synthesize key down from buttons if needed. |
| out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, readTime, getDeviceId(), |
| mSource, *mDisplayId, policyFlags, lastButtonState, |
| currentButtonState); |
| |
| // Send motion event. |
| if (downChanged || moved || scrolled || buttonsChanged) { |
| int32_t metaState = getContext()->getGlobalMetaState(); |
| int32_t buttonState = lastButtonState; |
| int32_t motionEventAction; |
| if (downChanged) { |
| motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; |
| } else if (down || (mSource != AINPUT_SOURCE_MOUSE)) { |
| motionEventAction = AMOTION_EVENT_ACTION_MOVE; |
| } else { |
| motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; |
| } |
| |
| if (buttonsReleased) { |
| BitSet32 released(buttonsReleased); |
| while (!released.isEmpty()) { |
| int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit()); |
| buttonState &= ~actionButton; |
| out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, |
| getDeviceId(), mSource, *mDisplayId, policyFlags, |
| AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0, |
| metaState, buttonState, MotionClassification::NONE, |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, |
| &pointerCoords, mXPrecision, mYPrecision, |
| xCursorPosition, yCursorPosition, downTime, |
| /*videoFrames=*/{})); |
| } |
| } |
| |
| out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), |
| mSource, *mDisplayId, policyFlags, motionEventAction, 0, 0, |
| metaState, currentButtonState, MotionClassification::NONE, |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, |
| &pointerCoords, mXPrecision, mYPrecision, xCursorPosition, |
| yCursorPosition, downTime, |
| /*videoFrames=*/{})); |
| |
| if (buttonsPressed) { |
| BitSet32 pressed(buttonsPressed); |
| while (!pressed.isEmpty()) { |
| int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit()); |
| buttonState |= actionButton; |
| out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, |
| getDeviceId(), mSource, *mDisplayId, policyFlags, |
| AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0, |
| metaState, buttonState, MotionClassification::NONE, |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, |
| &pointerCoords, mXPrecision, mYPrecision, |
| xCursorPosition, yCursorPosition, downTime, |
| /*videoFrames=*/{})); |
| } |
| } |
| |
| ALOG_ASSERT(buttonState == currentButtonState); |
| |
| // Send hover move after UP to tell the application that the mouse is hovering now. |
| if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) { |
| out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), |
| mSource, *mDisplayId, policyFlags, |
| AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState, |
| currentButtonState, MotionClassification::NONE, |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, |
| &pointerCoords, mXPrecision, mYPrecision, |
| xCursorPosition, yCursorPosition, downTime, |
| /*videoFrames=*/{})); |
| } |
| |
| // Send scroll events. |
| if (scrolled) { |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); |
| |
| out.push_back(NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), |
| mSource, *mDisplayId, policyFlags, |
| AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, |
| currentButtonState, MotionClassification::NONE, |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, |
| &pointerCoords, mXPrecision, mYPrecision, |
| xCursorPosition, yCursorPosition, downTime, |
| /*videoFrames=*/{})); |
| } |
| } |
| |
| // Synthesize key up from buttons if needed. |
| out += synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, readTime, getDeviceId(), |
| mSource, *mDisplayId, policyFlags, lastButtonState, |
| currentButtonState); |
| |
| mCursorMotionAccumulator.finishSync(); |
| mCursorScrollAccumulator.finishSync(); |
| return out; |
| } |
| |
| int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { |
| if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { |
| return getDeviceContext().getScanCodeState(scanCode); |
| } else { |
| return AKEY_STATE_UNKNOWN; |
| } |
| } |
| |
| std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() { |
| return mDisplayId; |
| } |
| |
| void CursorInputMapper::configureBasicParams() { |
| mCursorScrollAccumulator.configure(getDeviceContext()); |
| |
| // Configure basic parameters. |
| mParameters = computeParameters(getDeviceContext()); |
| |
| // Configure device mode. |
| switch (mParameters.mode) { |
| case Parameters::Mode::POINTER_RELATIVE: |
| // Should not happen during first time configuration. |
| ALOGE("Cannot start a device in MODE_POINTER_RELATIVE, starting in MODE_POINTER"); |
| mParameters.mode = Parameters::Mode::POINTER; |
| [[fallthrough]]; |
| case Parameters::Mode::POINTER: |
| mSource = AINPUT_SOURCE_MOUSE; |
| mXPrecision = 1.0f; |
| mYPrecision = 1.0f; |
| mXScale = 1.0f; |
| mYScale = 1.0f; |
| mPointerController = getContext()->getPointerController(getDeviceId()); |
| break; |
| case Parameters::Mode::NAVIGATION: |
| mSource = AINPUT_SOURCE_TRACKBALL; |
| mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; |
| mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; |
| mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; |
| mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; |
| break; |
| } |
| |
| mVWheelScale = 1.0f; |
| mHWheelScale = 1.0f; |
| } |
| |
| void CursorInputMapper::configureOnPointerCapture(const InputReaderConfiguration& config) { |
| if (config.pointerCaptureRequest.enable) { |
| if (mParameters.mode == Parameters::Mode::POINTER) { |
| mParameters.mode = Parameters::Mode::POINTER_RELATIVE; |
| mSource = AINPUT_SOURCE_MOUSE_RELATIVE; |
| // Keep PointerController around in order to preserve the pointer position. |
| mPointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); |
| } else { |
| ALOGE("Cannot request pointer capture, device is not in MODE_POINTER"); |
| } |
| } else { |
| if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) { |
| mParameters.mode = Parameters::Mode::POINTER; |
| mSource = AINPUT_SOURCE_MOUSE; |
| } else { |
| ALOGE("Cannot release pointer capture, device is not in MODE_POINTER_RELATIVE"); |
| } |
| } |
| bumpGeneration(); |
| } |
| |
| void CursorInputMapper::configureOnChangePointerSpeed(const InputReaderConfiguration& config) { |
| if (mParameters.mode == Parameters::Mode::POINTER_RELATIVE) { |
| // Disable any acceleration or scaling for the pointer when Pointer Capture is enabled. |
| mPointerVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); |
| mWheelXVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); |
| mWheelYVelocityControl.setParameters(FLAT_VELOCITY_CONTROL_PARAMS); |
| } else { |
| mPointerVelocityControl.setParameters(config.pointerVelocityControlParameters); |
| mWheelXVelocityControl.setParameters(config.wheelVelocityControlParameters); |
| mWheelYVelocityControl.setParameters(config.wheelVelocityControlParameters); |
| } |
| } |
| |
| void CursorInputMapper::configureOnChangeDisplayInfo(const InputReaderConfiguration& config) { |
| const bool isPointer = mParameters.mode == Parameters::Mode::POINTER; |
| |
| mDisplayId = ADISPLAY_ID_NONE; |
| std::optional<DisplayViewport> resolvedViewport; |
| bool isBoundsSet = false; |
| if (auto assocViewport = mDeviceContext.getAssociatedViewport(); assocViewport) { |
| // This InputDevice is associated with a viewport. |
| // Only generate events for the associated display. |
| mDisplayId = assocViewport->displayId; |
| resolvedViewport = *assocViewport; |
| if (!mEnablePointerChoreographer) { |
| const bool mismatchedPointerDisplay = |
| isPointer && (assocViewport->displayId != mPointerController->getDisplayId()); |
| if (mismatchedPointerDisplay) { |
| // This device's associated display doesn't match PointerController's current |
| // display. Do not associate it with any display. |
| mDisplayId.reset(); |
| } |
| } |
| } else if (isPointer) { |
| // The InputDevice is not associated with a viewport, but it controls the mouse pointer. |
| if (mEnablePointerChoreographer) { |
| // Always use DISPLAY_ID_NONE for mouse events. |
| // PointerChoreographer will make it target the correct the displayId later. |
| resolvedViewport = getContext()->getPolicy()->getPointerViewportForAssociatedDisplay(); |
| mDisplayId = resolvedViewport ? std::make_optional(ADISPLAY_ID_NONE) : std::nullopt; |
| } else { |
| mDisplayId = mPointerController->getDisplayId(); |
| if (auto v = config.getDisplayViewportById(*mDisplayId); v) { |
| resolvedViewport = *v; |
| } |
| if (auto bounds = mPointerController->getBounds(); bounds) { |
| mBoundsInLogicalDisplay = *bounds; |
| isBoundsSet = true; |
| } |
| } |
| } |
| |
| mOrientation = (mParameters.orientationAware && mParameters.hasAssociatedDisplay) || |
| mParameters.mode == Parameters::Mode::POINTER_RELATIVE || !resolvedViewport |
| ? ui::ROTATION_0 |
| : getInverseRotation(resolvedViewport->orientation); |
| |
| if (!isBoundsSet) { |
| mBoundsInLogicalDisplay = resolvedViewport |
| ? FloatRect{static_cast<float>(resolvedViewport->logicalLeft), |
| static_cast<float>(resolvedViewport->logicalTop), |
| static_cast<float>(resolvedViewport->logicalRight - 1), |
| static_cast<float>(resolvedViewport->logicalBottom - 1)} |
| : FloatRect{0, 0, 0, 0}; |
| } |
| |
| bumpGeneration(); |
| } |
| |
| } // namespace android |