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