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 <optional>
24
25 #include "CursorScrollAccumulator.h"
26
27 namespace android {
28
RotaryEncoderInputMapper(InputDeviceContext & deviceContext,const InputReaderConfiguration & readerConfig)29 RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceContext,
30 const InputReaderConfiguration& readerConfig)
31 : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) {
32 mSource = AINPUT_SOURCE_ROTARY_ENCODER;
33 }
34
~RotaryEncoderInputMapper()35 RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {}
36
getSources() const37 uint32_t RotaryEncoderInputMapper::getSources() const {
38 return mSource;
39 }
40
populateDeviceInfo(InputDeviceInfo & info)41 void RotaryEncoderInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
42 InputMapper::populateDeviceInfo(info);
43
44 if (mRotaryEncoderScrollAccumulator.haveRelativeVWheel()) {
45 const PropertyMap& config = getDeviceContext().getConfiguration();
46 std::optional<float> res = config.getFloat("device.res");
47 if (!res.has_value()) {
48 ALOGW("Rotary Encoder device configuration file didn't specify resolution!\n");
49 }
50 std::optional<float> scalingFactor = config.getFloat("device.scalingFactor");
51 if (!scalingFactor.has_value()) {
52 ALOGW("Rotary Encoder device configuration file didn't specify scaling factor,"
53 "default to 1.0!\n");
54 }
55 mScalingFactor = scalingFactor.value_or(1.0f);
56 info.addMotionRange(AMOTION_EVENT_AXIS_SCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f,
57 res.value_or(0.0f) * mScalingFactor);
58 }
59 }
60
dump(std::string & dump)61 void RotaryEncoderInputMapper::dump(std::string& dump) {
62 dump += INDENT2 "Rotary Encoder Input Mapper:\n";
63 dump += StringPrintf(INDENT3 "HaveWheel: %s\n",
64 toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
65 }
66
reconfigure(nsecs_t when,const InputReaderConfiguration & config,ConfigurationChanges changes)67 std::list<NotifyArgs> RotaryEncoderInputMapper::reconfigure(nsecs_t when,
68 const InputReaderConfiguration& config,
69 ConfigurationChanges changes) {
70 std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
71 if (!changes.any()) {
72 mRotaryEncoderScrollAccumulator.configure(getDeviceContext());
73 }
74 if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
75 std::optional<DisplayViewport> internalViewport =
76 config.getDisplayViewportByType(ViewportType::INTERNAL);
77 if (internalViewport) {
78 mOrientation = internalViewport->orientation;
79 } else {
80 mOrientation = ui::ROTATION_0;
81 }
82 }
83 return out;
84 }
85
reset(nsecs_t when)86 std::list<NotifyArgs> RotaryEncoderInputMapper::reset(nsecs_t when) {
87 mRotaryEncoderScrollAccumulator.reset(getDeviceContext());
88
89 return InputMapper::reset(when);
90 }
91
process(const RawEvent * rawEvent)92 std::list<NotifyArgs> RotaryEncoderInputMapper::process(const RawEvent* rawEvent) {
93 std::list<NotifyArgs> out;
94 mRotaryEncoderScrollAccumulator.process(rawEvent);
95
96 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
97 out += sync(rawEvent->when, rawEvent->readTime);
98 }
99 return out;
100 }
101
sync(nsecs_t when,nsecs_t readTime)102 std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readTime) {
103 std::list<NotifyArgs> out;
104
105 float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel();
106 bool scrolled = scroll != 0;
107
108 // Send motion event.
109 if (scrolled) {
110 int32_t metaState = getContext()->getGlobalMetaState();
111 // This is not a pointer, so it's not associated with a display.
112 int32_t displayId = ADISPLAY_ID_NONE;
113
114 if (mOrientation == ui::ROTATION_180) {
115 scroll = -scroll;
116 }
117
118 PointerCoords pointerCoords;
119 pointerCoords.clear();
120 pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
121
122 PointerProperties pointerProperties;
123 pointerProperties.clear();
124 pointerProperties.id = 0;
125 pointerProperties.toolType = ToolType::UNKNOWN;
126
127 uint32_t policyFlags = 0;
128 if (getDeviceContext().isExternal()) {
129 policyFlags |= POLICY_FLAG_WAKE;
130 }
131
132 out.push_back(
133 NotifyMotionArgs(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
134 displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
135 metaState, /* buttonState */ 0, MotionClassification::NONE,
136 AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
137 &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
138 AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}));
139 }
140
141 mRotaryEncoderScrollAccumulator.finishSync();
142 return out;
143 }
144
145 } // namespace android
146