Loading services/inputflinger/reader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ filegroup { "mapper/accumulator/CursorButtonAccumulator.cpp", "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/HidUsageAccumulator.cpp", "mapper/accumulator/MultiTouchMotionAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", ], Loading services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +0 −157 Original line number Diff line number Diff line Loading @@ -28,163 +28,6 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static constexpr size_t MAX_SLOTS = 32; // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {} void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); mSlots = std::vector<Slot>(slotCount); mCurrentSlot = -1; if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot // before we start reading events from the device. It is possible that the // current slot index will not be the same as it was when the first event was // written into the evdev buffer, which means the input mapper could start // out of sync with the initial state of the events in the evdev buffer. // In the extremely unlikely case that this happens, the data from // two slots will be confused until the next ABS_MT_SLOT event is received. // This can cause the touch point to "jump", but at least there will be // no stuck touches. int32_t initialSlot; if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); status == OK) { mCurrentSlot = initialSlot; } else { ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); } } } void MultiTouchMotionAccumulator::resetSlots() { for (Slot& slot : mSlots) { slot.clear(); } mCurrentSlot = -1; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (DEBUG_POINTERS) { if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", mCurrentSlot, mSlots.size() - 1); } } } else { Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: slot.mAbsMTPositionX = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: slot.mAbsMTPositionY = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: slot.mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot.mAbsMTTouchMinor = rawEvent->value; slot.mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot.mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot.mAbsMTWidthMinor = rawEvent->value; slot.mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: slot.mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot.mInUse = false; } else { slot.mInUse = true; slot.mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot.mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot.mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot.mAbsMTToolType = rawEvent->value; slot.mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { resetSlots(); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { if (!slot.mInUse) { ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId); } } // --- MultiTouchMotionAccumulator::Slot --- int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; case MT_TOOL_PALM: return AMOTION_EVENT_TOOL_TYPE_PALM; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext) Loading services/inputflinger/reader/mapper/MultiTouchInputMapper.h +1 −68 Original line number Diff line number Diff line Loading @@ -17,77 +17,10 @@ #pragma once #include "TouchInputMapper.h" #include "accumulator/MultiTouchMotionAccumulator.h" namespace android { /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMTPositionX; } inline int32_t getY() const { return mAbsMTPositionY; } inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } inline int32_t getOrientation() const { return mAbsMTOrientation; } inline int32_t getTrackingId() const { return mAbsMTTrackingId; } inline int32_t getPressure() const { return mAbsMTPressure; } inline int32_t getDistance() const { return mAbsMTDistance; } inline int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse = false; bool mHaveAbsMTTouchMinor = false; bool mHaveAbsMTWidthMinor = false; bool mHaveAbsMTToolType = false; int32_t mAbsMTPositionX = 0; int32_t mAbsMTPositionY = 0; int32_t mAbsMTTouchMajor = 0; int32_t mAbsMTTouchMinor = 0; int32_t mAbsMTWidthMajor = 0; int32_t mAbsMTWidthMinor = 0; int32_t mAbsMTOrientation = 0; int32_t mAbsMTTrackingId = -1; int32_t mAbsMTPressure = 0; int32_t mAbsMTDistance = 0; int32_t mAbsMTToolType = 0; void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlots.size(); } inline const Slot& getSlot(size_t index) const { LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); return mSlots[index]; } private: int32_t mCurrentSlot; std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; void resetSlots(); void warnIfNotInUse(const RawEvent& event, const Slot& slot); }; class MultiTouchInputMapper : public TouchInputMapper { public: explicit MultiTouchInputMapper(InputDeviceContext& deviceContext); Loading services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp 0 → 100644 +176 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "MultiTouchMotionAccumulator.h" namespace android { // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {} void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); mSlots = std::vector<Slot>(slotCount); mCurrentSlot = -1; if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot before we // start reading events from the device. It is possible that the current slot index will // not be the same as it was when the first event was written into the evdev buffer, which // means the input mapper could start out of sync with the initial state of the events in // the evdev buffer. In the extremely unlikely case that this happens, the data from two // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the // touch point to "jump", but at least there will be no stuck touches. int32_t initialSlot; if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); status == OK) { mCurrentSlot = initialSlot; } else { ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); } } } void MultiTouchMotionAccumulator::resetSlots() { for (Slot& slot : mSlots) { slot.clear(); } mCurrentSlot = -1; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (newSlot) { ALOGW_IF(DEBUG_POINTERS, "MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", mCurrentSlot, mSlots.size() - 1); } } else { Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: slot.mAbsMtPositionX = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: slot.mAbsMtPositionY = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: slot.mAbsMtTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot.mAbsMtTouchMinor = rawEvent->value; slot.mHaveAbsMtTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot.mAbsMtWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot.mAbsMtWidthMinor = rawEvent->value; slot.mHaveAbsMtWidthMinor = true; break; case ABS_MT_ORIENTATION: slot.mAbsMtOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot.mInUse = false; } else { slot.mInUse = true; slot.mAbsMtTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot.mAbsMtPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot.mAbsMtDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot.mAbsMtToolType = rawEvent->value; slot.mHaveAbsMtToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { resetSlots(); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { if (!slot.mInUse) { ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", event.code, event.value, mCurrentSlot, slot.mAbsMtTrackingId); } } // --- MultiTouchMotionAccumulator::Slot --- int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMtToolType) { switch (mAbsMtToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; case MT_TOOL_PALM: return AMOTION_EVENT_TOOL_TYPE_PALM; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } } // namespace android services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <linux/input-event-codes.h> #include <stdint.h> #include <vector> #include "EventHub.h" #include "InputDevice.h" namespace android { /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMtPositionX; } inline int32_t getY() const { return mAbsMtPositionY; } inline int32_t getTouchMajor() const { return mAbsMtTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMtTouchMinor ? mAbsMtTouchMinor : mAbsMtTouchMajor; } inline int32_t getToolMajor() const { return mAbsMtWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMtWidthMinor ? mAbsMtWidthMinor : mAbsMtWidthMajor; } inline int32_t getOrientation() const { return mAbsMtOrientation; } inline int32_t getTrackingId() const { return mAbsMtTrackingId; } inline int32_t getPressure() const { return mAbsMtPressure; } inline int32_t getDistance() const { return mAbsMtDistance; } int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse = false; bool mHaveAbsMtTouchMinor = false; bool mHaveAbsMtWidthMinor = false; bool mHaveAbsMtToolType = false; int32_t mAbsMtPositionX = 0; int32_t mAbsMtPositionY = 0; int32_t mAbsMtTouchMajor = 0; int32_t mAbsMtTouchMinor = 0; int32_t mAbsMtWidthMajor = 0; int32_t mAbsMtWidthMinor = 0; int32_t mAbsMtOrientation = 0; int32_t mAbsMtTrackingId = -1; int32_t mAbsMtPressure = 0; int32_t mAbsMtDistance = 0; int32_t mAbsMtToolType = 0; void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlots.size(); } inline const Slot& getSlot(size_t index) const { LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); return mSlots[index]; } private: int32_t mCurrentSlot; std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; void resetSlots(); void warnIfNotInUse(const RawEvent& event, const Slot& slot); }; } // namespace android Loading
services/inputflinger/reader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ filegroup { "mapper/accumulator/CursorButtonAccumulator.cpp", "mapper/accumulator/CursorScrollAccumulator.cpp", "mapper/accumulator/HidUsageAccumulator.cpp", "mapper/accumulator/MultiTouchMotionAccumulator.cpp", "mapper/accumulator/SingleTouchMotionAccumulator.cpp", "mapper/accumulator/TouchButtonAccumulator.cpp", ], Loading
services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp +0 −157 Original line number Diff line number Diff line Loading @@ -28,163 +28,6 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static constexpr size_t MAX_SLOTS = 32; // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {} void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); mSlots = std::vector<Slot>(slotCount); mCurrentSlot = -1; if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot // before we start reading events from the device. It is possible that the // current slot index will not be the same as it was when the first event was // written into the evdev buffer, which means the input mapper could start // out of sync with the initial state of the events in the evdev buffer. // In the extremely unlikely case that this happens, the data from // two slots will be confused until the next ABS_MT_SLOT event is received. // This can cause the touch point to "jump", but at least there will be // no stuck touches. int32_t initialSlot; if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); status == OK) { mCurrentSlot = initialSlot; } else { ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); } } } void MultiTouchMotionAccumulator::resetSlots() { for (Slot& slot : mSlots) { slot.clear(); } mCurrentSlot = -1; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (DEBUG_POINTERS) { if (newSlot) { ALOGW("MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", mCurrentSlot, mSlots.size() - 1); } } } else { Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: slot.mAbsMTPositionX = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: slot.mAbsMTPositionY = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: slot.mAbsMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot.mAbsMTTouchMinor = rawEvent->value; slot.mHaveAbsMTTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot.mAbsMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot.mAbsMTWidthMinor = rawEvent->value; slot.mHaveAbsMTWidthMinor = true; break; case ABS_MT_ORIENTATION: slot.mAbsMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot.mInUse = false; } else { slot.mInUse = true; slot.mAbsMTTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot.mAbsMTPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot.mAbsMTDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot.mAbsMTToolType = rawEvent->value; slot.mHaveAbsMTToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { resetSlots(); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { if (!slot.mInUse) { ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", event.code, event.value, mCurrentSlot, slot.mAbsMTTrackingId); } } // --- MultiTouchMotionAccumulator::Slot --- int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMTToolType) { switch (mAbsMTToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; case MT_TOOL_PALM: return AMOTION_EVENT_TOOL_TYPE_PALM; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDeviceContext& deviceContext) Loading
services/inputflinger/reader/mapper/MultiTouchInputMapper.h +1 −68 Original line number Diff line number Diff line Loading @@ -17,77 +17,10 @@ #pragma once #include "TouchInputMapper.h" #include "accumulator/MultiTouchMotionAccumulator.h" namespace android { /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMTPositionX; } inline int32_t getY() const { return mAbsMTPositionY; } inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } inline int32_t getOrientation() const { return mAbsMTOrientation; } inline int32_t getTrackingId() const { return mAbsMTTrackingId; } inline int32_t getPressure() const { return mAbsMTPressure; } inline int32_t getDistance() const { return mAbsMTDistance; } inline int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse = false; bool mHaveAbsMTTouchMinor = false; bool mHaveAbsMTWidthMinor = false; bool mHaveAbsMTToolType = false; int32_t mAbsMTPositionX = 0; int32_t mAbsMTPositionY = 0; int32_t mAbsMTTouchMajor = 0; int32_t mAbsMTTouchMinor = 0; int32_t mAbsMTWidthMajor = 0; int32_t mAbsMTWidthMinor = 0; int32_t mAbsMTOrientation = 0; int32_t mAbsMTTrackingId = -1; int32_t mAbsMTPressure = 0; int32_t mAbsMTDistance = 0; int32_t mAbsMTToolType = 0; void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlots.size(); } inline const Slot& getSlot(size_t index) const { LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); return mSlots[index]; } private: int32_t mCurrentSlot; std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; void resetSlots(); void warnIfNotInUse(const RawEvent& event, const Slot& slot); }; class MultiTouchInputMapper : public TouchInputMapper { public: explicit MultiTouchInputMapper(InputDeviceContext& deviceContext); Loading
services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.cpp 0 → 100644 +176 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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 "MultiTouchMotionAccumulator.h" namespace android { // --- MultiTouchMotionAccumulator --- MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : mCurrentSlot(-1), mUsingSlotsProtocol(false), mHaveStylus(false) {} void MultiTouchMotionAccumulator::configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol) { mUsingSlotsProtocol = usingSlotsProtocol; mHaveStylus = deviceContext.hasAbsoluteAxis(ABS_MT_TOOL_TYPE); mSlots = std::vector<Slot>(slotCount); mCurrentSlot = -1; if (mUsingSlotsProtocol) { // Query the driver for the current slot index and use it as the initial slot before we // start reading events from the device. It is possible that the current slot index will // not be the same as it was when the first event was written into the evdev buffer, which // means the input mapper could start out of sync with the initial state of the events in // the evdev buffer. In the extremely unlikely case that this happens, the data from two // slots will be confused until the next ABS_MT_SLOT event is received. This can cause the // touch point to "jump", but at least there will be no stuck touches. int32_t initialSlot; if (const auto status = deviceContext.getAbsoluteAxisValue(ABS_MT_SLOT, &initialSlot); status == OK) { mCurrentSlot = initialSlot; } else { ALOGD("Could not retrieve current multi-touch slot index. status=%d", status); } } } void MultiTouchMotionAccumulator::resetSlots() { for (Slot& slot : mSlots) { slot.clear(); } mCurrentSlot = -1; } void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { if (rawEvent->type == EV_ABS) { bool newSlot = false; if (mUsingSlotsProtocol) { if (rawEvent->code == ABS_MT_SLOT) { mCurrentSlot = rawEvent->value; newSlot = true; } } else if (mCurrentSlot < 0) { mCurrentSlot = 0; } if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlots.size()) { if (newSlot) { ALOGW_IF(DEBUG_POINTERS, "MultiTouch device emitted invalid slot index %d but it " "should be between 0 and %zd; ignoring this slot.", mCurrentSlot, mSlots.size() - 1); } } else { Slot& slot = mSlots[mCurrentSlot]; // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of // ABS_MT_TRACKING_ID and ABS_MT_SLOT, so driver should send a valid trackingId while // updating the slot. if (!mUsingSlotsProtocol) { slot.mInUse = true; } switch (rawEvent->code) { case ABS_MT_POSITION_X: slot.mAbsMtPositionX = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_POSITION_Y: slot.mAbsMtPositionY = rawEvent->value; warnIfNotInUse(*rawEvent, slot); break; case ABS_MT_TOUCH_MAJOR: slot.mAbsMtTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: slot.mAbsMtTouchMinor = rawEvent->value; slot.mHaveAbsMtTouchMinor = true; break; case ABS_MT_WIDTH_MAJOR: slot.mAbsMtWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: slot.mAbsMtWidthMinor = rawEvent->value; slot.mHaveAbsMtWidthMinor = true; break; case ABS_MT_ORIENTATION: slot.mAbsMtOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: if (mUsingSlotsProtocol && rawEvent->value < 0) { // The slot is no longer in use but it retains its previous contents, // which may be reused for subsequent touches. slot.mInUse = false; } else { slot.mInUse = true; slot.mAbsMtTrackingId = rawEvent->value; } break; case ABS_MT_PRESSURE: slot.mAbsMtPressure = rawEvent->value; break; case ABS_MT_DISTANCE: slot.mAbsMtDistance = rawEvent->value; break; case ABS_MT_TOOL_TYPE: slot.mAbsMtToolType = rawEvent->value; slot.mHaveAbsMtToolType = true; break; } } } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. mCurrentSlot += 1; } } void MultiTouchMotionAccumulator::finishSync() { if (!mUsingSlotsProtocol) { resetSlots(); } } bool MultiTouchMotionAccumulator::hasStylus() const { return mHaveStylus; } void MultiTouchMotionAccumulator::warnIfNotInUse(const RawEvent& event, const Slot& slot) { if (!slot.mInUse) { ALOGW("Received unexpected event (0x%0x, 0x%0x) for slot %i with tracking id %i", event.code, event.value, mCurrentSlot, slot.mAbsMtTrackingId); } } // --- MultiTouchMotionAccumulator::Slot --- int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { if (mHaveAbsMtToolType) { switch (mAbsMtToolType) { case MT_TOOL_FINGER: return AMOTION_EVENT_TOOL_TYPE_FINGER; case MT_TOOL_PEN: return AMOTION_EVENT_TOOL_TYPE_STYLUS; case MT_TOOL_PALM: return AMOTION_EVENT_TOOL_TYPE_PALM; } } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; } } // namespace android
services/inputflinger/reader/mapper/accumulator/MultiTouchMotionAccumulator.h 0 → 100644 +96 −0 Original line number Diff line number Diff line /* * Copyright (C) 2022 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. */ #pragma once #include <linux/input-event-codes.h> #include <stdint.h> #include <vector> #include "EventHub.h" #include "InputDevice.h" namespace android { /* Keeps track of the state of multi-touch protocol. */ class MultiTouchMotionAccumulator { public: class Slot { public: inline bool isInUse() const { return mInUse; } inline int32_t getX() const { return mAbsMtPositionX; } inline int32_t getY() const { return mAbsMtPositionY; } inline int32_t getTouchMajor() const { return mAbsMtTouchMajor; } inline int32_t getTouchMinor() const { return mHaveAbsMtTouchMinor ? mAbsMtTouchMinor : mAbsMtTouchMajor; } inline int32_t getToolMajor() const { return mAbsMtWidthMajor; } inline int32_t getToolMinor() const { return mHaveAbsMtWidthMinor ? mAbsMtWidthMinor : mAbsMtWidthMajor; } inline int32_t getOrientation() const { return mAbsMtOrientation; } inline int32_t getTrackingId() const { return mAbsMtTrackingId; } inline int32_t getPressure() const { return mAbsMtPressure; } inline int32_t getDistance() const { return mAbsMtDistance; } int32_t getToolType() const; private: friend class MultiTouchMotionAccumulator; bool mInUse = false; bool mHaveAbsMtTouchMinor = false; bool mHaveAbsMtWidthMinor = false; bool mHaveAbsMtToolType = false; int32_t mAbsMtPositionX = 0; int32_t mAbsMtPositionY = 0; int32_t mAbsMtTouchMajor = 0; int32_t mAbsMtTouchMinor = 0; int32_t mAbsMtWidthMajor = 0; int32_t mAbsMtWidthMinor = 0; int32_t mAbsMtOrientation = 0; int32_t mAbsMtTrackingId = -1; int32_t mAbsMtPressure = 0; int32_t mAbsMtDistance = 0; int32_t mAbsMtToolType = 0; void clear() { *this = Slot(); } }; MultiTouchMotionAccumulator(); void configure(InputDeviceContext& deviceContext, size_t slotCount, bool usingSlotsProtocol); void process(const RawEvent* rawEvent); void finishSync(); bool hasStylus() const; inline size_t getSlotCount() const { return mSlots.size(); } inline const Slot& getSlot(size_t index) const { LOG_ALWAYS_FATAL_IF(index < 0 || index >= mSlots.size(), "Invalid index: %zu", index); return mSlots[index]; } private: int32_t mCurrentSlot; std::vector<Slot> mSlots; bool mUsingSlotsProtocol; bool mHaveStylus; void resetSlots(); void warnIfNotInUse(const RawEvent& event, const Slot& slot); }; } // namespace android