| /* | |
| * 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 "RotaryEncoderInputMapper.h" | |
| #include "CursorScrollAccumulator.h" | |
| namespace android { | |
| RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext) | |
| : InputMapper(deviceContext), mOrientation(DISPLAY_ORIENTATION_0) { | |
| mSource = AINPUT_SOURCE_ROTARY_ENCODER; | |
| } | |
| RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} | |
| uint32_t RotaryEncoderInputMapper::getSources() { | |
| return mSource; | |
| } | |
| void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo* info) { | |
| InputMapper::populateDeviceInfo(info); | |
| if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) { | |
| float res = 0.0f; | |
| if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.res"), res)) { | |
| ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n"); | |
| } | |
| if (!getDeviceContext().getConfiguration().tryGetProperty(String8("device.scalingFactor"), | |
| mScalingFactor)) { | |
| ALOGW("Rotary Encoder device configuration file didn't specify scaling factor," | |
| "default to 1.0!\n"); | |
| mScalingFactor = 1.0f; | |
| } | |
| info->addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, | |
| res * mScalingFactor); | |
| } | |
| } | |
| void RotaryEncoderInputMapper::dump(std::string& dump) { | |
| dump += INDENT2 "Rotary Encoder Input Mapper:\n"; | |
| dump += StringPrintf(INDENT3 "HaveWheel: %s\n", | |
| toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel())); | |
| } | |
| void RotaryEncoderInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, | |
| uint32_t changes) { | |
| InputMapper::configure(when, config, changes); | |
| if (!changes) { | |
| mRotaryEncoderScrollAccumulator.configure(getDeviceContext()); | |
| } | |
| if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { | |
| std::optional<DisplayViewport> internalViewport = | |
| config->getDisplayViewportByType(ViewportType::INTERNAL); | |
| if (internalViewport) { | |
| mOrientation = internalViewport->orientation; | |
| } else { | |
| mOrientation = DISPLAY_ORIENTATION_0; | |
| } | |
| } | |
| } | |
| void RotaryEncoderInputMapper::reset(nsecs_t when) { | |
| mRotaryEncoderScrollAccumulator.reset(getDeviceContext()); | |
| InputMapper::reset(when); | |
| } | |
| void RotaryEncoderInputMapper::process(const RawEvent* rawEvent) { | |
| mRotaryEncoderScrollAccumulator.process(rawEvent); | |
| if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { | |
| sync(rawEvent->when); | |
| } | |
| } | |
| void RotaryEncoderInputMapper::sync(nsecs_t when) { | |
| PointerCoords pointerCoords; | |
| pointerCoords.clear(); | |
| PointerProperties pointerProperties; | |
| pointerProperties.clear(); | |
| pointerProperties.id = 0; | |
| pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; | |
| float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); | |
| bool scrolled = scroll != 0; | |
| // This is not a pointer, so it's not associated with a display. | |
| int32_t displayId = ADISPLAY_ID_NONE; | |
| // Moving the rotary encoder should wake the device (if specified). | |
| uint32_t policyFlags = 0; | |
| if (scrolled && getDeviceContext().isExternal()) { | |
| policyFlags |= POLICY_FLAG_WAKE; | |
| } | |
| if (mOrientation == DISPLAY_ORIENTATION_180) { | |
| scroll = -scroll; | |
| } | |
| // Send motion event. | |
| if (scrolled) { | |
| int32_t metaState = getContext()->getGlobalMetaState(); | |
| pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor); | |
| NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource, | |
| displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, | |
| metaState, /* buttonState */ 0, MotionClassification::NONE, | |
| AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, | |
| &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION, | |
| AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); | |
| getListener()->notifyMotion(&scrollArgs); | |
| } | |
| mRotaryEncoderScrollAccumulator.finishSync(); | |
| } | |
| } // namespace android |