Loading services/inputflinger/reader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ filegroup { "mapper/RotaryEncoderInputMapper.cpp", "mapper/SensorInputMapper.cpp", "mapper/SingleTouchInputMapper.cpp", "mapper/SlopController.cpp", "mapper/SwitchInputMapper.cpp", "mapper/TouchCursorInputMapperCommon.cpp", "mapper/TouchInputMapper.cpp", Loading services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,14 @@ RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceCon const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; const PropertyMap& config = getDeviceContext().getConfiguration(); float slopThreshold = config.getInt("rotary_encoder.slop_threshold").value_or(0); int32_t slopDurationMs = config.getInt("rotary_encoder.slop_duration_ms").value_or(0); if (slopThreshold > 0 && slopDurationMs > 0) { mSlopController = std::make_unique<SlopController>(slopThreshold, (nsecs_t)(slopDurationMs * 1000000)); } } RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} Loading Loading @@ -103,6 +111,10 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT std::list<NotifyArgs> out; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); if (mSlopController) { scroll = mSlopController->consumeEvent(when, scroll); } bool scrolled = scroll != 0; // Send motion event. Loading services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +2 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "CursorScrollAccumulator.h" #include "InputMapper.h" #include "SlopController.h" namespace android { Loading @@ -46,6 +47,7 @@ private: int32_t mSource; float mScalingFactor; ui::Rotation mOrientation; std::unique_ptr<SlopController> mSlopController = nullptr; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); Loading services/inputflinger/reader/mapper/SlopController.cpp 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright 2023 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 "SlopController.h" namespace { int signOf(float value) { if (value == 0) return 0; if (value > 0) return 1; return -1; } } // namespace namespace android { SlopController::SlopController(float slopThreshold, nsecs_t slopDurationNanos) : mSlopThreshold(slopThreshold), mSlopDurationNanos(slopDurationNanos) {} SlopController::~SlopController() {} float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { if (mSlopDurationNanos == 0) { return value; } if (shouldResetSlopTracking(eventTimeNanos, value)) { mCumulativeValue = 0; mHasSlopBeenMet = false; } mLastEventTimeNanos = eventTimeNanos; if (mHasSlopBeenMet) { // Since slop has already been met, we know that all of the current value would pass the // slop threshold. So return that, without any further processing. return value; } mCumulativeValue += value; if (abs(mCumulativeValue) >= mSlopThreshold) { mHasSlopBeenMet = true; // Return the amount of value that exceeds the slop. return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold); } return 0; } bool SlopController::shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) { const nsecs_t ageNanos = eventTimeNanos - mLastEventTimeNanos; if (ageNanos >= mSlopDurationNanos) { return true; } if (value == 0) { return false; } if (signOf(mCumulativeValue) != signOf(value)) { return true; } return false; } } // namespace android services/inputflinger/reader/mapper/SlopController.h 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright 2023 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 <utils/Timers.h> namespace android { /** * Controls a slop logic. Slop here refers to an approach to try and drop insignificant input * events. This is helpful in cases where unintentional input events may cause unintended outcomes, * like scrolling a screen or keeping the screen awake. * * Current slop logic: * "If time since last event > Xns, then discard the next N values." */ class SlopController { public: SlopController(float slopThreshold, nsecs_t slopDurationNanos); virtual ~SlopController(); /** * Consumes an event with a given time and value for slop processing. * Returns an amount <=value that should be consumed. */ float consumeEvent(nsecs_t eventTime, float value); private: bool shouldResetSlopTracking(nsecs_t eventTimeNanos, float value); /** The amount of event values ignored after an inactivity of the slop duration. */ const float mSlopThreshold; /** The duration of inactivity that resets slop controlling. */ const nsecs_t mSlopDurationNanos; nsecs_t mLastEventTimeNanos = 0; float mCumulativeValue = 0; bool mHasSlopBeenMet = false; }; } // namespace android Loading
services/inputflinger/reader/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ filegroup { "mapper/RotaryEncoderInputMapper.cpp", "mapper/SensorInputMapper.cpp", "mapper/SingleTouchInputMapper.cpp", "mapper/SlopController.cpp", "mapper/SwitchInputMapper.cpp", "mapper/TouchCursorInputMapperCommon.cpp", "mapper/TouchInputMapper.cpp", Loading
services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp +12 −0 Original line number Diff line number Diff line Loading @@ -30,6 +30,14 @@ RotaryEncoderInputMapper::RotaryEncoderInputMapper(InputDeviceContext& deviceCon const InputReaderConfiguration& readerConfig) : InputMapper(deviceContext, readerConfig), mOrientation(ui::ROTATION_0) { mSource = AINPUT_SOURCE_ROTARY_ENCODER; const PropertyMap& config = getDeviceContext().getConfiguration(); float slopThreshold = config.getInt("rotary_encoder.slop_threshold").value_or(0); int32_t slopDurationMs = config.getInt("rotary_encoder.slop_duration_ms").value_or(0); if (slopThreshold > 0 && slopDurationMs > 0) { mSlopController = std::make_unique<SlopController>(slopThreshold, (nsecs_t)(slopDurationMs * 1000000)); } } RotaryEncoderInputMapper::~RotaryEncoderInputMapper() {} Loading Loading @@ -103,6 +111,10 @@ std::list<NotifyArgs> RotaryEncoderInputMapper::sync(nsecs_t when, nsecs_t readT std::list<NotifyArgs> out; float scroll = mRotaryEncoderScrollAccumulator.getRelativeVWheel(); if (mSlopController) { scroll = mSlopController->consumeEvent(when, scroll); } bool scrolled = scroll != 0; // Send motion event. Loading
services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h +2 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ #include "CursorScrollAccumulator.h" #include "InputMapper.h" #include "SlopController.h" namespace android { Loading @@ -46,6 +47,7 @@ private: int32_t mSource; float mScalingFactor; ui::Rotation mOrientation; std::unique_ptr<SlopController> mSlopController = nullptr; explicit RotaryEncoderInputMapper(InputDeviceContext& deviceContext, const InputReaderConfiguration& readerConfig); Loading
services/inputflinger/reader/mapper/SlopController.cpp 0 → 100644 +81 −0 Original line number Diff line number Diff line /* * Copyright 2023 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 "SlopController.h" namespace { int signOf(float value) { if (value == 0) return 0; if (value > 0) return 1; return -1; } } // namespace namespace android { SlopController::SlopController(float slopThreshold, nsecs_t slopDurationNanos) : mSlopThreshold(slopThreshold), mSlopDurationNanos(slopDurationNanos) {} SlopController::~SlopController() {} float SlopController::consumeEvent(nsecs_t eventTimeNanos, float value) { if (mSlopDurationNanos == 0) { return value; } if (shouldResetSlopTracking(eventTimeNanos, value)) { mCumulativeValue = 0; mHasSlopBeenMet = false; } mLastEventTimeNanos = eventTimeNanos; if (mHasSlopBeenMet) { // Since slop has already been met, we know that all of the current value would pass the // slop threshold. So return that, without any further processing. return value; } mCumulativeValue += value; if (abs(mCumulativeValue) >= mSlopThreshold) { mHasSlopBeenMet = true; // Return the amount of value that exceeds the slop. return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold); } return 0; } bool SlopController::shouldResetSlopTracking(nsecs_t eventTimeNanos, float value) { const nsecs_t ageNanos = eventTimeNanos - mLastEventTimeNanos; if (ageNanos >= mSlopDurationNanos) { return true; } if (value == 0) { return false; } if (signOf(mCumulativeValue) != signOf(value)) { return true; } return false; } } // namespace android
services/inputflinger/reader/mapper/SlopController.h 0 → 100644 +55 −0 Original line number Diff line number Diff line /* * Copyright 2023 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 <utils/Timers.h> namespace android { /** * Controls a slop logic. Slop here refers to an approach to try and drop insignificant input * events. This is helpful in cases where unintentional input events may cause unintended outcomes, * like scrolling a screen or keeping the screen awake. * * Current slop logic: * "If time since last event > Xns, then discard the next N values." */ class SlopController { public: SlopController(float slopThreshold, nsecs_t slopDurationNanos); virtual ~SlopController(); /** * Consumes an event with a given time and value for slop processing. * Returns an amount <=value that should be consumed. */ float consumeEvent(nsecs_t eventTime, float value); private: bool shouldResetSlopTracking(nsecs_t eventTimeNanos, float value); /** The amount of event values ignored after an inactivity of the slop duration. */ const float mSlopThreshold; /** The duration of inactivity that resets slop controlling. */ const nsecs_t mSlopDurationNanos; nsecs_t mLastEventTimeNanos = 0; float mCumulativeValue = 0; bool mHasSlopBeenMet = false; }; } // namespace android