diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-03-03 02:09:54 -0800 |
---|---|---|
committer | Jeff Brown <jeffbrown@google.com> | 2011-03-09 02:46:45 -0800 |
commit | 9626b14a283ef82d16636cf5fb5ba8bb4d30381e (patch) | |
tree | ad6e1a8c87412308cff13d5a727b179ab301dfee /services/input | |
parent | 924c4d47774fa7d8a5ce659d12291ef7df82ee05 (diff) | |
download | frameworks_base-9626b14a283ef82d16636cf5fb5ba8bb4d30381e.zip frameworks_base-9626b14a283ef82d16636cf5fb5ba8bb4d30381e.tar.gz frameworks_base-9626b14a283ef82d16636cf5fb5ba8bb4d30381e.tar.bz2 |
Fix off by one errors in touch motion ranges. (DO NOT MERGE)
Report inclusive minimum and maximum ranges for all
axes including X and Y.
Set mouse pointer bounds to 0..width-1, 0..height-1.
Rotate touch and mouse positions more carefully, paying attention
to the maximum bounds when calculating the complement of an axis.
Simplified the InputReader somewhat and removed support for a
couple of poorly defined input device configuration parameters.
We now assume that the touch device provides useful absolute axis
ranges for the X and Y axes since the alternative does not actually
make sense.
Bug: 3413541
Change-Id: I121d28a125c4f9618cb283dc460d33ff1a907023
Diffstat (limited to 'services/input')
-rw-r--r-- | services/input/EventHub.h | 2 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 268 | ||||
-rw-r--r-- | services/input/InputReader.h | 12 | ||||
-rw-r--r-- | services/input/PointerController.cpp | 61 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 44 |
5 files changed, 193 insertions, 194 deletions
diff --git a/services/input/EventHub.h b/services/input/EventHub.h index ab42a1f..7053a94 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -85,8 +85,6 @@ struct RawAbsoluteAxisInfo { int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise - inline int32_t getRange() const { return maxValue - minValue; } - inline void clear() { valid = false; minValue = 0; diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index ab43a20..c620c44 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -88,6 +88,18 @@ static inline const char* toString(bool value) { return value ? "true" : "false"; } +static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, + const int32_t map[][4], size_t mapSize) { + if (orientation != DISPLAY_ORIENTATION_0) { + for (size_t i = 0; i < mapSize; i++) { + if (value == map[i][0]) { + return map[i][orientation]; + } + } + } + return value; +} + static const int32_t keyCodeRotationMap[][4] = { // key codes enumerated counter-clockwise with the original (unrotated) key first // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation @@ -96,18 +108,32 @@ static const int32_t keyCodeRotationMap[][4] = { { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, }; -static const int keyCodeRotationMapSize = +static const size_t keyCodeRotationMapSize = sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (int i = 0; i < keyCodeRotationMapSize; i++) { - if (keyCode == keyCodeRotationMap[i][0]) { - return keyCodeRotationMap[i][orientation]; - } - } - } - return keyCode; + return rotateValueUsingRotationMap(keyCode, orientation, + keyCodeRotationMap, keyCodeRotationMapSize); +} + +static const int32_t edgeFlagRotationMap[][4] = { + // edge flags enumerated counter-clockwise with the original (unrotated) edge flag first + // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation + { AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT, + AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT }, + { AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP, + AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM }, + { AMOTION_EVENT_EDGE_FLAG_TOP, AMOTION_EVENT_EDGE_FLAG_LEFT, + AMOTION_EVENT_EDGE_FLAG_BOTTOM, AMOTION_EVENT_EDGE_FLAG_RIGHT }, + { AMOTION_EVENT_EDGE_FLAG_LEFT, AMOTION_EVENT_EDGE_FLAG_BOTTOM, + AMOTION_EVENT_EDGE_FLAG_RIGHT, AMOTION_EVENT_EDGE_FLAG_TOP }, +}; +static const size_t edgeFlagRotationMapSize = + sizeof(edgeFlagRotationMap) / sizeof(edgeFlagRotationMap[0]); + +static int32_t rotateEdgeFlag(int32_t edgeFlag, int32_t orientation) { + return rotateValueUsingRotationMap(edgeFlag, orientation, + edgeFlagRotationMap, edgeFlagRotationMapSize); } static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { @@ -1290,7 +1316,8 @@ void CursorInputMapper::sync(nsecs_t when) { return; // no new state changes, so nothing to do } - int motionEventAction; + int32_t motionEventAction; + int32_t motionEventEdgeFlags; PointerCoords pointerCoords; nsecs_t downTime; float vscroll, hscroll; @@ -1361,6 +1388,8 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.clear(); + motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; + if (mPointerController != NULL) { mPointerController->move(deltaX, deltaY); if (downChanged) { @@ -1370,6 +1399,22 @@ void CursorInputMapper::sync(nsecs_t when) { mPointerController->getPosition(&x, &y); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + + if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { + float minX, minY, maxX, maxY; + if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + if (x <= minX) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; + } else if (x >= maxX) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; + } + if (y <= minY) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; + } else if (y >= maxY) { + motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; + } + } + } } else { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); @@ -1404,7 +1449,7 @@ void CursorInputMapper::sync(nsecs_t when) { int32_t metaState = mContext->getGlobalMetaState(); int32_t pointerId = 0; getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, - motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, + motionEventAction, 0, metaState, motionEventEdgeFlags, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); mAccumulator.clear(); @@ -1507,8 +1552,6 @@ void TouchInputMapper::dump(String8& dump) { dumpCalibration(dump); dumpSurfaceLocked(dump); dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XOrigin: %d\n", mLocked.xOrigin); - dump.appendFormat(INDENT4 "YOrigin: %d\n", mLocked.yOrigin); dump.appendFormat(INDENT4 "XScale: %0.3f\n", mLocked.xScale); dump.appendFormat(INDENT4 "YScale: %0.3f\n", mLocked.yScale); dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mLocked.xPrecision); @@ -1654,10 +1697,17 @@ void TouchInputMapper::dumpRawAxes(String8& dump) { } bool TouchInputMapper::configureSurfaceLocked() { + // Ensure we have valid X and Y axes. + if (!mRawAxes.x.valid || !mRawAxes.y.valid) { + LOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " + "The device will be inoperable.", getDeviceName().string()); + return false; + } + // Update orientation and dimensions if needed. int32_t orientation = DISPLAY_ORIENTATION_0; - int32_t width = mRawAxes.x.getRange(); - int32_t height = mRawAxes.y.getRange(); + int32_t width = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1; + int32_t height = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1; if (mParameters.associatedDisplayId >= 0) { bool wantSize = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; @@ -1685,32 +1735,12 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.surfaceHeight = height; // Configure X and Y factors. - if (mRawAxes.x.valid && mRawAxes.y.valid) { - mLocked.xOrigin = mCalibration.haveXOrigin - ? mCalibration.xOrigin - : mRawAxes.x.minValue; - mLocked.yOrigin = mCalibration.haveYOrigin - ? mCalibration.yOrigin - : mRawAxes.y.minValue; - mLocked.xScale = mCalibration.haveXScale - ? mCalibration.xScale - : float(width) / mRawAxes.x.getRange(); - mLocked.yScale = mCalibration.haveYScale - ? mCalibration.yScale - : float(height) / mRawAxes.y.getRange(); - mLocked.xPrecision = 1.0f / mLocked.xScale; - mLocked.yPrecision = 1.0f / mLocked.yScale; - - configureVirtualKeysLocked(); - } else { - LOGW(INDENT "Touch device did not report support for X or Y axis!"); - mLocked.xOrigin = 0; - mLocked.yOrigin = 0; - mLocked.xScale = 1.0f; - mLocked.yScale = 1.0f; - mLocked.xPrecision = 1.0f; - mLocked.yPrecision = 1.0f; - } + mLocked.xScale = float(width) / (mRawAxes.x.maxValue - mRawAxes.x.minValue + 1); + mLocked.yScale = float(height) / (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1); + mLocked.xPrecision = 1.0f / mLocked.xScale; + mLocked.yPrecision = 1.0f / mLocked.yScale; + + configureVirtualKeysLocked(); // Scale factor for terms that are not oriented in a particular axis. // If the pixels are square then xScale == yScale otherwise we fake it @@ -1844,38 +1874,51 @@ bool TouchInputMapper::configureSurfaceLocked() { } if (orientationChanged || sizeChanged) { - // Compute oriented surface dimensions, precision, and scales. - float orientedXScale, orientedYScale; + // Compute oriented surface dimensions, precision, scales and ranges. + // Note that the maximum value reported is an inclusive maximum value so it is one + // unit less than the total width or height of surface. switch (mLocked.surfaceOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: mLocked.orientedSurfaceWidth = mLocked.surfaceHeight; mLocked.orientedSurfaceHeight = mLocked.surfaceWidth; + mLocked.orientedXPrecision = mLocked.yPrecision; mLocked.orientedYPrecision = mLocked.xPrecision; - orientedXScale = mLocked.yScale; - orientedYScale = mLocked.xScale; + + mLocked.orientedRanges.x.min = 0; + mLocked.orientedRanges.x.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue) + * mLocked.yScale; + mLocked.orientedRanges.x.flat = 0; + mLocked.orientedRanges.x.fuzz = mLocked.yScale; + + mLocked.orientedRanges.y.min = 0; + mLocked.orientedRanges.y.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue) + * mLocked.xScale; + mLocked.orientedRanges.y.flat = 0; + mLocked.orientedRanges.y.fuzz = mLocked.xScale; break; + default: mLocked.orientedSurfaceWidth = mLocked.surfaceWidth; mLocked.orientedSurfaceHeight = mLocked.surfaceHeight; + mLocked.orientedXPrecision = mLocked.xPrecision; mLocked.orientedYPrecision = mLocked.yPrecision; - orientedXScale = mLocked.xScale; - orientedYScale = mLocked.yScale; + + mLocked.orientedRanges.x.min = 0; + mLocked.orientedRanges.x.max = (mRawAxes.x.maxValue - mRawAxes.x.minValue) + * mLocked.xScale; + mLocked.orientedRanges.x.flat = 0; + mLocked.orientedRanges.x.fuzz = mLocked.xScale; + + mLocked.orientedRanges.y.min = 0; + mLocked.orientedRanges.y.max = (mRawAxes.y.maxValue - mRawAxes.y.minValue) + * mLocked.yScale; + mLocked.orientedRanges.y.flat = 0; + mLocked.orientedRanges.y.fuzz = mLocked.yScale; break; } - - // Configure position ranges. - mLocked.orientedRanges.x.min = 0; - mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth; - mLocked.orientedRanges.x.flat = 0; - mLocked.orientedRanges.x.fuzz = orientedXScale; - - mLocked.orientedRanges.y.min = 0; - mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight; - mLocked.orientedRanges.y.flat = 0; - mLocked.orientedRanges.y.fuzz = orientedYScale; } return true; @@ -1888,8 +1931,6 @@ void TouchInputMapper::dumpSurfaceLocked(String8& dump) { } void TouchInputMapper::configureVirtualKeysLocked() { - assert(mRawAxes.x.valid && mRawAxes.y.valid); - Vector<VirtualKeyDefinition> virtualKeyDefinitions; getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); @@ -1903,8 +1944,8 @@ void TouchInputMapper::configureVirtualKeysLocked() { int32_t touchScreenLeft = mRawAxes.x.minValue; int32_t touchScreenTop = mRawAxes.y.minValue; - int32_t touchScreenWidth = mRawAxes.x.getRange(); - int32_t touchScreenHeight = mRawAxes.y.getRange(); + int32_t touchScreenWidth = mRawAxes.x.maxValue - mRawAxes.x.minValue + 1; + int32_t touchScreenHeight = mRawAxes.y.maxValue - mRawAxes.y.minValue + 1; for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { const VirtualKeyDefinition& virtualKeyDefinition = @@ -1939,7 +1980,6 @@ void TouchInputMapper::configureVirtualKeysLocked() { * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - } } @@ -1962,12 +2002,6 @@ void TouchInputMapper::parseCalibration() { const PropertyMap& in = getDevice()->getConfiguration(); Calibration& out = mCalibration; - // Position - out.haveXOrigin = in.tryGetProperty(String8("touch.position.xOrigin"), out.xOrigin); - out.haveYOrigin = in.tryGetProperty(String8("touch.position.yOrigin"), out.yOrigin); - out.haveXScale = in.tryGetProperty(String8("touch.position.xScale"), out.xScale); - out.haveYScale = in.tryGetProperty(String8("touch.position.yScale"), out.yScale); - // Touch Size out.touchSizeCalibration = Calibration::TOUCH_SIZE_CALIBRATION_DEFAULT; String8 touchSizeCalibrationString; @@ -2179,20 +2213,6 @@ void TouchInputMapper::resolveCalibration() { void TouchInputMapper::dumpCalibration(String8& dump) { dump.append(INDENT3 "Calibration:\n"); - // Position - if (mCalibration.haveXOrigin) { - dump.appendFormat(INDENT4 "touch.position.xOrigin: %d\n", mCalibration.xOrigin); - } - if (mCalibration.haveYOrigin) { - dump.appendFormat(INDENT4 "touch.position.yOrigin: %d\n", mCalibration.yOrigin); - } - if (mCalibration.haveXScale) { - dump.appendFormat(INDENT4 "touch.position.xScale: %0.3f\n", mCalibration.xScale); - } - if (mCalibration.haveYScale) { - dump.appendFormat(INDENT4 "touch.position.yScale: %0.3f\n", mCalibration.yScale); - } - // Touch Size switch (mCalibration.touchSizeCalibration) { case Calibration::TOUCH_SIZE_CALIBRATION_NONE: @@ -2620,7 +2640,7 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, int32_t motionEventAction) { int32_t pointerIds[MAX_POINTERS]; PointerCoords pointerCoords[MAX_POINTERS]; - int32_t motionEventEdgeFlags = 0; + int32_t motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; float xPrecision, yPrecision; { // acquire lock @@ -2635,10 +2655,6 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, const PointerData& in = touch->pointers[inIndex]; - // X and Y - float x = float(in.x - mLocked.xOrigin) * mLocked.xScale; - float y = float(in.y - mLocked.yOrigin) * mLocked.yScale; - // ToolMajor and ToolMinor float toolMajor, toolMinor; switch (mCalibration.toolSizeCalibration) { @@ -2776,33 +2792,34 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, orientation = 0; } - // Adjust coords for orientation. + // X and Y + // Adjust coords for surface orientation. + float x, y; switch (mLocked.surfaceOrientation) { - case DISPLAY_ORIENTATION_90: { - float xTemp = x; - x = y; - y = mLocked.surfaceWidth - xTemp; + case DISPLAY_ORIENTATION_90: + x = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; + y = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; orientation -= M_PI_2; if (orientation < - M_PI_2) { orientation += M_PI; } break; - } - case DISPLAY_ORIENTATION_180: { - x = mLocked.surfaceWidth - x; - y = mLocked.surfaceHeight - y; + case DISPLAY_ORIENTATION_180: + x = float(mRawAxes.x.maxValue - in.x) * mLocked.xScale; + y = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; break; - } - case DISPLAY_ORIENTATION_270: { - float xTemp = x; - x = mLocked.surfaceHeight - y; - y = xTemp; + case DISPLAY_ORIENTATION_270: + x = float(mRawAxes.y.maxValue - in.y) * mLocked.yScale; + y = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; orientation += M_PI_2; if (orientation > M_PI_2) { orientation -= M_PI; } break; - } + default: + x = float(in.x - mRawAxes.x.minValue) * mLocked.xScale; + y = float(in.y - mRawAxes.y.minValue) * mLocked.yScale; + break; } // Write output coords. @@ -2828,18 +2845,22 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, // Check edge flags by looking only at the first pointer since the flags are // global to the event. if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { - float x = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X); - float y = pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y); + uint32_t inIndex = touch->idToIndex[pointerIds[0]]; + const PointerData& in = touch->pointers[inIndex]; - if (x <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; - } else if (x >= mLocked.orientedSurfaceWidth) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; + if (in.x <= mRawAxes.x.minValue) { + motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_LEFT, + mLocked.surfaceOrientation); + } else if (in.x >= mRawAxes.x.maxValue) { + motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_RIGHT, + mLocked.surfaceOrientation); } - if (y <= 0) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; - } else if (y >= mLocked.orientedSurfaceHeight) { - motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; + if (in.y <= mRawAxes.y.minValue) { + motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_TOP, + mLocked.surfaceOrientation); + } else if (in.y >= mRawAxes.y.maxValue) { + motionEventEdgeFlags |= rotateEdgeFlag(AMOTION_EVENT_EDGE_FLAG_BOTTOM, + mLocked.surfaceOrientation); } } @@ -2854,11 +2875,8 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, } bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) { - if (mRawAxes.x.valid && mRawAxes.y.valid) { - return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue - && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; - } - return true; + return x >= mRawAxes.x.minValue && x <= mRawAxes.x.maxValue + && y >= mRawAxes.y.minValue && y <= mRawAxes.y.maxValue; } const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked( @@ -3066,11 +3084,6 @@ void TouchInputMapper::calculatePointerIds() { * points has moved more than a screen height from the last position, * then drop it. */ bool TouchInputMapper::applyBadTouchFilter() { - // This hack requires valid axis parameters. - if (! mRawAxes.y.valid) { - return false; - } - uint32_t pointerCount = mCurrentTouch.pointerCount; // Nothing to do if there are no points. @@ -3089,7 +3102,7 @@ bool TouchInputMapper::applyBadTouchFilter() { // the long size of the screen to be bad. This was a magic value // determined by looking at the maximum distance it is feasible // to actually move in one sample. - int32_t maxDeltaY = mRawAxes.y.getRange() * 7 / 16; + int32_t maxDeltaY = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) * 7 / 16; // XXX The original code in InputDevice.java included commented out // code for testing the X axis. Note that when we drop a point @@ -3150,11 +3163,6 @@ bool TouchInputMapper::applyBadTouchFilter() { * the coordinate value for one axis has jumped to the other pointer's location. */ bool TouchInputMapper::applyJumpyTouchFilter() { - // This hack requires valid axis parameters. - if (! mRawAxes.y.valid) { - return false; - } - uint32_t pointerCount = mCurrentTouch.pointerCount; if (mLastTouch.pointerCount != pointerCount) { #if DEBUG_HACKS @@ -3211,7 +3219,7 @@ bool TouchInputMapper::applyJumpyTouchFilter() { } if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) { - int jumpyEpsilon = mRawAxes.y.getRange() / JUMPY_EPSILON_DIVISOR; + int jumpyEpsilon = (mRawAxes.y.maxValue - mRawAxes.y.minValue + 1) / JUMPY_EPSILON_DIVISOR; // We only replace the single worst jumpy point as characterized by pointer distance // in a single axis. diff --git a/services/input/InputReader.h b/services/input/InputReader.h index e2cf08e..b9e3494 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -650,16 +650,6 @@ protected: // Immutable calibration parameters in parsed form. struct Calibration { - // Position - bool haveXOrigin; - int32_t xOrigin; - bool haveYOrigin; - int32_t yOrigin; - bool haveXScale; - float xScale; - bool haveYScale; - float yScale; - // Touch Size enum TouchSizeCalibration { TOUCH_SIZE_CALIBRATION_DEFAULT, @@ -756,11 +746,9 @@ protected: int32_t surfaceWidth, surfaceHeight; // Translation and scaling factors, orientation-independent. - int32_t xOrigin; float xScale; float xPrecision; - int32_t yOrigin; float yScale; float yPrecision; diff --git a/services/input/PointerController.cpp b/services/input/PointerController.cpp index 954872b..a4ee295 100644 --- a/services/input/PointerController.cpp +++ b/services/input/PointerController.cpp @@ -109,12 +109,12 @@ bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, switch (mLocked.displayOrientation) { case DISPLAY_ORIENTATION_90: case DISPLAY_ORIENTATION_270: - *outMaxX = mLocked.displayHeight; - *outMaxY = mLocked.displayWidth; + *outMaxX = mLocked.displayHeight - 1; + *outMaxY = mLocked.displayWidth - 1; break; default: - *outMaxX = mLocked.displayWidth; - *outMaxY = mLocked.displayHeight; + *outMaxX = mLocked.displayWidth - 1; + *outMaxY = mLocked.displayHeight - 1; break; } return true; @@ -309,48 +309,53 @@ void PointerController::setDisplayOrientation(int32_t orientation) { AutoMutex _l(mLock); if (mLocked.displayOrientation != orientation) { - float absoluteX, absoluteY; - - // Map from oriented display coordinates to absolute display coordinates. + // Apply offsets to convert from the pixel top-left corner position to the pixel center. + // This creates an invariant frame of reference that we can easily rotate when + // taking into account that the pointer may be located at fractional pixel offsets. + float x = mLocked.pointerX + 0.5f; + float y = mLocked.pointerY + 0.5f; + float temp; + + // Undo the previous rotation. switch (mLocked.displayOrientation) { case DISPLAY_ORIENTATION_90: - absoluteX = mLocked.displayWidth - mLocked.pointerY; - absoluteY = mLocked.pointerX; + temp = x; + x = mLocked.displayWidth - y; + y = temp; break; case DISPLAY_ORIENTATION_180: - absoluteX = mLocked.displayWidth - mLocked.pointerX; - absoluteY = mLocked.displayHeight - mLocked.pointerY; + x = mLocked.displayWidth - x; + y = mLocked.displayHeight - y; break; case DISPLAY_ORIENTATION_270: - absoluteX = mLocked.pointerY; - absoluteY = mLocked.displayHeight - mLocked.pointerX; - break; - default: - absoluteX = mLocked.pointerX; - absoluteY = mLocked.pointerY; + temp = x; + x = y; + y = mLocked.displayHeight - temp; break; } - // Map from absolute display coordinates to oriented display coordinates. + // Perform the new rotation. switch (orientation) { case DISPLAY_ORIENTATION_90: - mLocked.pointerX = absoluteY; - mLocked.pointerY = mLocked.displayWidth - absoluteX; + temp = x; + x = y; + y = mLocked.displayWidth - x; break; case DISPLAY_ORIENTATION_180: - mLocked.pointerX = mLocked.displayWidth - absoluteX; - mLocked.pointerY = mLocked.displayHeight - absoluteY; + x = mLocked.displayWidth - x; + y = mLocked.displayHeight - y; break; case DISPLAY_ORIENTATION_270: - mLocked.pointerX = mLocked.displayHeight - absoluteY; - mLocked.pointerY = absoluteX; - break; - default: - mLocked.pointerX = absoluteX; - mLocked.pointerY = absoluteY; + temp = x; + x = mLocked.displayHeight - y; + y = temp; break; } + // Apply offsets to convert from the pixel center to the pixel top-left corner position + // and save the results. + mLocked.pointerX = x - 0.5f; + mLocked.pointerY = y - 0.5f; mLocked.displayOrientation = orientation; updateLocked(); diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index d77cb2f..f7e1890 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -2007,15 +2007,15 @@ TEST_F(CursorInputMapperTest, WhenModeIsPointer_PopulateDeviceInfo_ReturnsRangeF 0.0f, 1.0f, 0.0f, 0.0f)); // When the bounds are set, then there should be a valid motion range. - mFakePointerController->setBounds(1, 2, 800, 480); + mFakePointerController->setBounds(1, 2, 800 - 1, 480 - 1); InputDeviceInfo info2; mapper->populateDeviceInfo(&info2); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_X, - 1, 800, 0.0f, 0.0f)); + 1, 800 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_Y, - 2, 480, 0.0f, 0.0f)); + 2, 480 - 1, 0.0f, 0.0f)); ASSERT_NO_FATAL_FAILURE(assertMotionRange(info2, AINPUT_MOTION_RANGE_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f)); } @@ -2320,9 +2320,9 @@ protected: }; const int32_t TouchInputMapperTest::RAW_X_MIN = 25; -const int32_t TouchInputMapperTest::RAW_X_MAX = 1020; +const int32_t TouchInputMapperTest::RAW_X_MAX = 1019; const int32_t TouchInputMapperTest::RAW_Y_MIN = 30; -const int32_t TouchInputMapperTest::RAW_Y_MAX = 1010; +const int32_t TouchInputMapperTest::RAW_Y_MAX = 1009; const int32_t TouchInputMapperTest::RAW_TOUCH_MIN = 0; const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31; const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0; @@ -2333,8 +2333,8 @@ const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7; const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7; const int32_t TouchInputMapperTest::RAW_ID_MIN = 0; const int32_t TouchInputMapperTest::RAW_ID_MAX = 9; -const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH; -const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT; +const float TouchInputMapperTest::X_PRECISION = float(RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH; +const float TouchInputMapperTest::Y_PRECISION = float(RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT; const VirtualKeyDefinition TouchInputMapperTest::VIRTUAL_KEYS[2] = { { KEY_HOME, 60, DISPLAY_HEIGHT + 15, 20, 20 }, @@ -2353,19 +2353,19 @@ void TouchInputMapperTest::prepareVirtualKeys() { } int32_t TouchInputMapperTest::toRawX(float displayX) { - return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN) / DISPLAY_WIDTH + RAW_X_MIN); + return int32_t(displayX * (RAW_X_MAX - RAW_X_MIN + 1) / DISPLAY_WIDTH + RAW_X_MIN); } int32_t TouchInputMapperTest::toRawY(float displayY) { - return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN) / DISPLAY_HEIGHT + RAW_Y_MIN); + return int32_t(displayY * (RAW_Y_MAX - RAW_Y_MIN + 1) / DISPLAY_HEIGHT + RAW_Y_MIN); } float TouchInputMapperTest::toDisplayX(int32_t rawX) { - return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN); + return float(rawX - RAW_X_MIN) * DISPLAY_WIDTH / (RAW_X_MAX - RAW_X_MIN + 1); } float TouchInputMapperTest::toDisplayY(int32_t rawY) { - return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN); + return float(rawY - RAW_Y_MIN) * DISPLAY_HEIGHT / (RAW_Y_MAX - RAW_Y_MIN + 1); } @@ -2950,12 +2950,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) // Rotation 90. prepareDisplay(DISPLAY_ORIENTATION_90); - processDown(mapper, toRawX(50), toRawY(75)); + processDown(mapper, RAW_X_MAX - toRawX(75) + RAW_X_MIN, toRawY(50)); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); @@ -2963,12 +2963,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) // Rotation 180. prepareDisplay(DISPLAY_ORIENTATION_180); - processDown(mapper, toRawX(50), toRawY(75)); + processDown(mapper, RAW_X_MAX - toRawX(50) + RAW_X_MIN, RAW_Y_MAX - toRawY(75) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(DISPLAY_WIDTH - 50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); @@ -2976,12 +2976,12 @@ TEST_F(SingleTouchInputMapperTest, Process_WhenOrientationAware_RotatesMotions) // Rotation 270. prepareDisplay(DISPLAY_ORIENTATION_270); - processDown(mapper, toRawX(50), toRawY(75)); + processDown(mapper, toRawX(75), RAW_Y_MAX - toRawY(50) + RAW_Y_MIN); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeDispatcher->assertNotifyMotionWasCalled(&args)); - ASSERT_NEAR(DISPLAY_HEIGHT - 75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); - ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); + ASSERT_NEAR(50, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X), 1); + ASSERT_NEAR(75, args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y), 1); processUp(mapper); processSync(mapper); @@ -3601,8 +3601,8 @@ TEST_F(MultiTouchInputMapperTest, Process_TouchAndToolAxes_GeometricCalibration) float y = toDisplayY(rawY); float pressure = float(rawTouchMajor) / RAW_TOUCH_MAX; float size = avg(rawToolMajor, rawToolMinor) / RAW_TOOL_MAX; - float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN), - float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN)); + float scale = avg(float(DISPLAY_WIDTH) / (RAW_X_MAX - RAW_X_MIN + 1), + float(DISPLAY_HEIGHT) / (RAW_Y_MAX - RAW_Y_MIN + 1)); float toolMajor = float(rawToolMajor) * scale; float toolMinor = float(rawToolMinor) * scale; float touchMajor = min(float(rawTouchMajor) * scale, toolMajor); |