blob: 82f92767d9d04f6832b821a9ffb683848fb2146e [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001/*
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
Prabir Pradhan9244aea2020-02-05 20:31:40 -080017#include "../Macros.h"
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070018
Prabir Pradhanf4d65b12022-02-10 07:15:38 -080019#include <android/sysprop/InputProperties.sysprop.h>
Siarhei Vishniakou9faa4462022-12-06 11:45:04 -080020#include "MultiTouchInputMapper.h"
Prabir Pradhanf4d65b12022-02-10 07:15:38 -080021
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070022namespace android {
23
24// --- Constants ---
25
26// Maximum number of slots supported when using the slot-based Multitouch Protocol B.
27static constexpr size_t MAX_SLOTS = 32;
28
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070029// --- MultiTouchInputMapper ---
30
Arpit Singh8e6fb252023-04-06 11:49:17 +000031MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext,
32 const InputReaderConfiguration& readerConfig)
33 : TouchInputMapper(deviceContext, readerConfig) {}
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070034
35MultiTouchInputMapper::~MultiTouchInputMapper() {}
36
Siarhei Vishniakou2935db72022-09-22 13:35:22 -070037std::list<NotifyArgs> MultiTouchInputMapper::reset(nsecs_t when) {
Prabir Pradhanf8d9e442023-12-06 22:06:13 +000038 // TODO(b/291626046): Sync the MT state with the kernel using EVIOCGMTSLOTS.
39 mMultiTouchMotionAccumulator.reset(getDeviceContext());
40 mPointerIdBits.clear();
41
Siarhei Vishniakou2935db72022-09-22 13:35:22 -070042 return TouchInputMapper::reset(when);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070043}
44
Siarhei Vishniakou2935db72022-09-22 13:35:22 -070045std::list<NotifyArgs> MultiTouchInputMapper::process(const RawEvent* rawEvent) {
46 std::list<NotifyArgs> out = TouchInputMapper::process(rawEvent);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070047
48 mMultiTouchMotionAccumulator.process(rawEvent);
Siarhei Vishniakou2935db72022-09-22 13:35:22 -070049 return out;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070050}
51
arthurhungcc7f9802020-04-30 17:55:40 +080052std::optional<int32_t> MultiTouchInputMapper::getActiveBitId(
53 const MultiTouchMotionAccumulator::Slot& inSlot) {
54 if (mHavePointerIds) {
55 int32_t trackingId = inSlot.getTrackingId();
56 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
57 int32_t n = idBits.clearFirstMarkedBit();
58 if (mPointerTrackingIdMap[n] == trackingId) {
59 return std::make_optional(n);
60 }
61 }
62 }
63 return std::nullopt;
64}
65
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070066void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) {
67 size_t inCount = mMultiTouchMotionAccumulator.getSlotCount();
68 size_t outCount = 0;
69 BitSet32 newPointerIdBits;
70 mHavePointerIds = true;
71
72 for (size_t inIndex = 0; inIndex < inCount; inIndex++) {
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -080073 const MultiTouchMotionAccumulator::Slot& inSlot =
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070074 mMultiTouchMotionAccumulator.getSlot(inIndex);
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -080075 if (!inSlot.isInUse()) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070076 continue;
77 }
78
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -070079 if (inSlot.getToolType() == ToolType::PALM) {
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -080080 std::optional<int32_t> id = getActiveBitId(inSlot);
arthurhungcc7f9802020-04-30 17:55:40 +080081 if (id) {
82 outState->rawPointerData.canceledIdBits.markBit(id.value());
Arthur Hung421eb1c2020-01-16 00:09:42 +080083 }
Siarhei Vishniakoue3ce49d2020-09-29 19:08:13 -050084 if (DEBUG_POINTERS) {
85 ALOGI("Stop processing slot %zu for it received a palm event from device %s",
86 inIndex, getDeviceName().c_str());
87 }
arthurhungbf89a482020-04-17 17:37:55 +080088 continue;
Arthur Hung421eb1c2020-01-16 00:09:42 +080089 }
90
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070091 if (outCount >= MAX_POINTERS) {
Siarhei Vishniakoue3ce49d2020-09-29 19:08:13 -050092 if (DEBUG_POINTERS) {
Siarhei Vishniakou01747382022-01-20 13:23:27 -080093 ALOGD("MultiTouch device %s emitted more than maximum of %zu pointers; "
Siarhei Vishniakoue3ce49d2020-09-29 19:08:13 -050094 "ignoring the rest.",
95 getDeviceName().c_str(), MAX_POINTERS);
96 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070097 break; // too many fingers!
98 }
99
100 RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount];
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -0800101 outPointer.x = inSlot.getX();
102 outPointer.y = inSlot.getY();
103 outPointer.pressure = inSlot.getPressure();
104 outPointer.touchMajor = inSlot.getTouchMajor();
105 outPointer.touchMinor = inSlot.getTouchMinor();
106 outPointer.toolMajor = inSlot.getToolMajor();
107 outPointer.toolMinor = inSlot.getToolMinor();
108 outPointer.orientation = inSlot.getOrientation();
109 outPointer.distance = inSlot.getDistance();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700110 outPointer.tiltX = 0;
111 outPointer.tiltY = 0;
112
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -0800113 outPointer.toolType = inSlot.getToolType();
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700114 if (outPointer.toolType == ToolType::UNKNOWN) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700115 outPointer.toolType = mTouchButtonAccumulator.getToolType();
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700116 if (outPointer.toolType == ToolType::UNKNOWN) {
117 outPointer.toolType = ToolType::FINGER;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700118 }
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700119 } else if (outPointer.toolType == ToolType::STYLUS && !mStylusMtToolSeen) {
Prabir Pradhan5d0d97d2022-11-17 01:06:01 +0000120 mStylusMtToolSeen = true;
121 // The multi-touch device produced a stylus event with MT_TOOL_PEN. Dynamically
122 // re-configure this input device so that we add SOURCE_STYLUS if we haven't already.
123 // This is to cover the case where we cannot reliably detect whether a multi-touch
124 // device will ever produce stylus events when it is initially being configured.
125 if (!isFromSource(mSource, AINPUT_SOURCE_STYLUS)) {
126 // Add the stylus source immediately so that it is included in any events generated
127 // before we have a chance to re-configure the device.
128 mSource |= AINPUT_SOURCE_STYLUS;
129 bumpGeneration();
130 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700131 }
Prabir Pradhan522758a2023-11-14 23:55:51 +0000132 if (mShouldSimulateStylusWithTouch && outPointer.toolType == ToolType::FINGER) {
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700133 outPointer.toolType = ToolType::STYLUS;
Prabir Pradhanf4d65b12022-02-10 07:15:38 -0800134 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700135
Siarhei Vishniakou6d73f832022-07-21 17:27:03 -0700136 bool isHovering = mTouchButtonAccumulator.getToolType() != ToolType::MOUSE &&
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700137 (mTouchButtonAccumulator.isHovering() ||
Siarhei Vishniakoubaf0b162022-02-16 11:12:36 -0800138 (mRawPointerAxes.pressure.valid && inSlot.getPressure() <= 0));
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700139 outPointer.isHovering = isHovering;
140
141 // Assign pointer id using tracking id if available.
142 if (mHavePointerIds) {
Linnan Li3db547c2024-04-26 11:13:00 +0000143 const int32_t trackingId = inSlot.getTrackingId();
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700144 int32_t id = -1;
145 if (trackingId >= 0) {
146 for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty();) {
147 uint32_t n = idBits.clearFirstMarkedBit();
148 if (mPointerTrackingIdMap[n] == trackingId) {
149 id = n;
Linnan Li3db547c2024-04-26 11:13:00 +0000150 break;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700151 }
152 }
153
154 if (id < 0 && !mPointerIdBits.isFull()) {
155 id = mPointerIdBits.markFirstUnmarkedBit();
156 mPointerTrackingIdMap[id] = trackingId;
157 }
158 }
159 if (id < 0) {
160 mHavePointerIds = false;
161 outState->rawPointerData.clearIdBits();
162 newPointerIdBits.clear();
163 } else {
164 outPointer.id = id;
165 outState->rawPointerData.idToIndex[id] = outCount;
166 outState->rawPointerData.markIdBit(id, isHovering);
167 newPointerIdBits.markBit(id);
168 }
169 }
170 outCount += 1;
171 }
172
173 outState->rawPointerData.pointerCount = outCount;
174 mPointerIdBits = newPointerIdBits;
175
176 mMultiTouchMotionAccumulator.finishSync();
177}
178
Prabir Pradhan522758a2023-11-14 23:55:51 +0000179std::list<NotifyArgs> MultiTouchInputMapper::reconfigure(nsecs_t when,
180 const InputReaderConfiguration& config,
181 ConfigurationChanges changes) {
182 const bool simulateStylusWithTouch =
183 sysprop::InputProperties::simulate_stylus_with_touch().value_or(false);
184 if (simulateStylusWithTouch != mShouldSimulateStylusWithTouch) {
185 mShouldSimulateStylusWithTouch = simulateStylusWithTouch;
186 bumpGeneration();
187 }
188 return TouchInputMapper::reconfigure(when, config, changes);
189}
190
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700191void MultiTouchInputMapper::configureRawPointerAxes() {
192 TouchInputMapper::configureRawPointerAxes();
193
194 getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x);
195 getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y);
196 getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor);
197 getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor);
198 getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor);
199 getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor);
200 getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation);
201 getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure);
202 getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance);
203 getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId);
204 getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot);
205
206 if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid &&
207 mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
208 size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
209 if (slotCount > MAX_SLOTS) {
210 ALOGW("MultiTouch Device %s reported %zu slots but the framework "
211 "only supports a maximum of %zu slots at this time.",
212 getDeviceName().c_str(), slotCount, MAX_SLOTS);
213 slotCount = MAX_SLOTS;
214 }
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800215 mMultiTouchMotionAccumulator.configure(getDeviceContext(), slotCount,
Harry Cutts33476232023-01-30 19:57:29 +0000216 /*usingSlotsProtocol=*/true);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700217 } else {
Nathaniel R. Lewis26ec2222020-01-10 16:30:54 -0800218 mMultiTouchMotionAccumulator.configure(getDeviceContext(), MAX_POINTERS,
Harry Cutts33476232023-01-30 19:57:29 +0000219 /*usingSlotsProtocol=*/false);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700220 }
221}
222
223bool MultiTouchInputMapper::hasStylus() const {
Prabir Pradhan5d0d97d2022-11-17 01:06:01 +0000224 return mStylusMtToolSeen || mTouchButtonAccumulator.hasStylus() ||
Prabir Pradhan522758a2023-11-14 23:55:51 +0000225 mShouldSimulateStylusWithTouch;
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700226}
227
228} // namespace android