1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // clang-format off
18 #include "../Macros.h"
19 // clang-format on
20
21 #include "RotaryEncoderInputMapper.h"
22
23 #include <utils/Timers.h>
24 #include <optional>
25
26 #include "CursorScrollAccumulator.h"
27
28 namespace android {
29
RotaryEncoderInputMapper(InputDeviceContext & deviceContext,const InputReaderConfiguration & readerConfig)30 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext,
31 const InputReaderConfiguration& readerConfig)
32 : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) {
33 mSource = AINPUT_SOURCE_ROTARY_ENCODER;
34 }
35
~RotaryEncoderInputMapper()36 RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {}
37
getSources() const38 uint32_t RotaryEncoderInputMapper::getSources() const {
39 return mSource;
40 }
41
populateDeviceInfo(InputDeviceInfo & info)42 void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
43 InputMapper::populateDeviceInfo(info);
44
45 if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
46 const PropertyMap& config = getDeviceContext().getConfiguration();
47 std::optional<float> res = config.getFloat("device.res");
48 if (!res.has_value()) {
49 ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n");
50 }
51 std::optional<float> scalingFactor = config.getFloat("device.scalingFactor");
52 if (!scalingFactor.has_value()) {
53 ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
54 "default to 1.0!\n");
55 }
56 mScalingFactor = scalingFactor.value_or(1.0f);
57 info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
58 res.value_or(0.0f) * mScalingFactor);
59 }
60 }
61
dump(std::string & dump)62 void RotaryEncoderInputMapper::dump(std::string& dump) {
63 dump += INDENT2 "Rotary Encoder Input Mapper:\n";
64 dump += StringPrintf(INDENT3 "HaveWheel: %s\n",
65 toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
66 dump += StringPrintf(INDENT3 "HaveSlopController: %s\n", toString(mSlopController != nullptr));
67 }
68
reconfigure(nsecs_t when,const InputReaderConfiguration & config,ConfigurationChanges changes)69 std::list<NotifyArgs> RotaryEncoderInputMapper::reconfigure(nsecs_t when,
70 const InputReaderConfiguration& config,
71 ConfigurationChanges changes) {
72 std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
73 if (!changes.any()) {
74 mRotaryEncoderScrollAccumulator.configure(getDeviceContext());
75
76 const PropertyMap& propertyMap = getDeviceContext().getConfiguration();
77 float slopThreshold = propertyMap.getInt("rotary_encoder.slop_threshold").value_or(0);
78 int32_t slopDurationNs = milliseconds_to_nanoseconds(
79 propertyMap.getInt("rotary_encoder.slop_duration_ms").value_or(0));
80 if (slopThreshold > 0 && slopDurationNs > 0) {
81 mSlopController = std::make_unique<SlopController>(slopThreshold, slopDurationNs);
82 } else {
83 mSlopController = nullptr;
84 }
85 }
86 if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
87 std::optional<DisplayViewport> internalViewport =
88 config.getDisplayViewportByType(ViewportType::INTERNAL);
89 if (internalViewport) {
90 mOrientation = internalViewport->orientation;
91 } else {
92 mOrientation = ui::ROTATION_0;
93 }
94 }
95 return out;
96 }
97
reset(nsecs_t when)98 std::list<NotifyArgs> RotaryEncoderInputMapper::reset(nsecs_t when) {
99 mRotaryEncoderScrollAccumulator.reset(getDeviceContext());
100
101 return InputMapper::reset(when);
102 }
103
process(const RawEvent & rawEvent)104 std::list<NotifyArgs> RotaryEncoderInputMapper::process(const RawEvent& rawEvent) {
105 std::list<NotifyArgs> out;
106 mRotaryEncoderScrollAccumulator.process(rawEvent);
107
108 if (rawEvent.type == EV_SYN && rawEvent.code == SYN_REPORT) {
109 out += sync(rawEvent.when, rawEvent.readTime);
110 }
111 return out;
112 }
113
sync(nsecs_t when,nsecs_t readTime)114 std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) {
115 std::list<NotifyArgs> out;
116
117 float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel();
118 if (mSlopController) {
119 scroll = mSlopController->consumeEvent(when, scroll);
120 }
121
122 bool scrolled = scroll != 0;
123
124 // Send motion event.
125 if (scrolled) {
126 int32_t metaState = getContext()->getGlobalMetaState();
127 // This is not a pointer, so it's not associated with a display.
128 ui::LogicalDisplayId displayId = ui::LogicalDisplayId::INVALID;
129
130 if (mOrientation == ui::ROTATION_180) {
131 scroll = -scroll;
132 }
133
134 PointerCoords pointerCoords;
135 pointerCoords.clear();
136 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
137
138 PointerProperties pointerProperties;
139 pointerProperties.clear();
140 pointerProperties.id = 0;
141 pointerProperties.toolType = ToolType::UNKNOWN;
142
143 uint32_t policyFlags = 0;
144 if (getDeviceContext().isExternal()) {
145 policyFlags |= POLICY_FLAG_WAKE;
146 }
147
148 out.push_back(
149 NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
150 displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
151 metaState, /*buttonState=*/0, MotionClassification::NONE,
152 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
153 &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
154 AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /*videoFrames=*/{}));
155 }
156
157 mRotaryEncoderScrollAccumulator.finishSync();
158 return out;
159 }
160
161 } // namespace android
162