diff options
Diffstat (limited to 'services/input/InputReader.cpp')
-rw-r--r-- | services/input/InputReader.cpp | 726 |
1 files changed, 454 insertions, 272 deletions
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index b92c3b5..3029028 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -33,6 +33,7 @@ // Log debug messages about pointer assignment calculations. #define DEBUG_POINTER_ASSIGNMENT 0 + #include "InputReader.h" #include <cutils/log.h> @@ -88,6 +89,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,24 +109,80 @@ 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) { return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; } +static uint32_t getButtonStateForScanCode(int32_t scanCode) { + // Currently all buttons are mapped to the primary button. + switch (scanCode) { + case BTN_LEFT: + case BTN_RIGHT: + case BTN_MIDDLE: + case BTN_SIDE: + case BTN_EXTRA: + case BTN_FORWARD: + case BTN_BACK: + case BTN_TASK: + return BUTTON_STATE_PRIMARY; + default: + return 0; + } +} + +// Returns true if the pointer should be reported as being down given the specified +// button states. +static bool isPointerDown(uint32_t buttonState) { + return buttonState & BUTTON_STATE_PRIMARY; +} + +static int32_t calculateEdgeFlagsUsingPointerBounds( + const sp<PointerControllerInterface>& pointerController, float x, float y) { + int32_t edgeFlags = 0; + float minX, minY, maxX, maxY; + if (pointerController->getBounds(&minX, &minY, &maxX, &maxY)) { + if (x <= minX) { + edgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT; + } else if (x >= maxX) { + edgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT; + } + if (y <= minY) { + edgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP; + } else if (y >= maxY) { + edgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM; + } + } + return edgeFlags; +} + // --- InputReader --- @@ -244,23 +313,23 @@ InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, ui } // Keyboard-like devices. - uint32_t keyboardSources = 0; + uint32_t keyboardSource = 0; int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSources |= AINPUT_SOURCE_KEYBOARD; + keyboardSource |= AINPUT_SOURCE_KEYBOARD; } if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; } if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSources |= AINPUT_SOURCE_DPAD; + keyboardSource |= AINPUT_SOURCE_DPAD; } if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSources |= AINPUT_SOURCE_GAMEPAD; + keyboardSource |= AINPUT_SOURCE_GAMEPAD; } - if (keyboardSources != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSources, keyboardType)); + if (keyboardSource != 0) { + device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); } // Cursor-like devices. @@ -591,22 +660,22 @@ void InputDevice::dump(String8& dump) { dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - const KeyedVector<int32_t, InputDeviceInfo::MotionRange> ranges = deviceInfo.getMotionRanges(); + const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); if (!ranges.isEmpty()) { dump.append(INDENT2 "Motion Ranges:\n"); for (size_t i = 0; i < ranges.size(); i++) { - int32_t axis = ranges.keyAt(i); - const char* label = getAxisLabel(axis); + const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); + const char* label = getAxisLabel(range.axis); char name[32]; if (label) { strncpy(name, label, sizeof(name)); name[sizeof(name) - 1] = '\0'; } else { - snprintf(name, sizeof(name), "%d", axis); + snprintf(name, sizeof(name), "%d", range.axis); } - const InputDeviceInfo::MotionRange& range = ranges.valueAt(i); - dump.appendFormat(INDENT3 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n", - name, range.min, range.max, range.flat, range.fuzz); + dump.appendFormat(INDENT3 "%s: source=0x%08x, " + "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f\n", + name, range.source, range.min, range.max, range.flat, range.fuzz); } } @@ -811,8 +880,8 @@ int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCod // --- KeyboardInputMapper --- KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t sources, int32_t keyboardType) : - InputMapper(device), mSources(sources), + uint32_t source, int32_t keyboardType) : + InputMapper(device), mSource(source), mKeyboardType(keyboardType) { initializeLocked(); } @@ -826,7 +895,7 @@ void KeyboardInputMapper::initializeLocked() { } uint32_t KeyboardInputMapper::getSources() { - return mSources; + return mSource; } void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -919,6 +988,7 @@ void KeyboardInputMapper::process(const RawEvent* rawEvent) { bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { return scanCode < BTN_MOUSE || scanCode >= KEY_OK + || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); } @@ -1009,10 +1079,7 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getContext()->fadePointer(); } - if (policyFlags & POLICY_FLAG_FUNCTION) { - newMetaState |= AMETA_FUNCTION_ON; - } - getDispatcher()->notifyKey(when, getDeviceId(), mSources, policyFlags, + getDispatcher()->notifyKey(when, getDeviceId(), mSource, policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); } @@ -1092,7 +1159,7 @@ CursorInputMapper::~CursorInputMapper() { } uint32_t CursorInputMapper::getSources() { - return mSources; + return mSource; } void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -1101,20 +1168,20 @@ void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { if (mParameters.mode == Parameters::MODE_POINTER) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, minX, maxX, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, minY, maxY, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f); } } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, -1.0f, 1.0f, 0.0f, mXScale); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, -1.0f, 1.0f, 0.0f, mYScale); + info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale); + info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale); } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, 0.0f, 1.0f, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f); if (mHaveVWheel) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, -1.0f, 1.0f, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } if (mHaveHWheel) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, -1.0f, 1.0f, 0.0f, 0.0f); + info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f); } } @@ -1131,7 +1198,8 @@ void CursorInputMapper::dump(String8& dump) { dump.appendFormat(INDENT3 "HaveHWheel: %s\n", toString(mHaveHWheel)); dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump.appendFormat(INDENT3 "Down: %s\n", toString(mLocked.down)); + dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mLocked.buttonState); + dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mLocked.buttonState))); dump.appendFormat(INDENT3 "DownTime: %lld\n", mLocked.downTime); } // release lock } @@ -1145,7 +1213,7 @@ void CursorInputMapper::configure() { // Configure device mode. switch (mParameters.mode) { case Parameters::MODE_POINTER: - mSources = AINPUT_SOURCE_MOUSE; + mSource = AINPUT_SOURCE_MOUSE; mXPrecision = 1.0f; mYPrecision = 1.0f; mXScale = 1.0f; @@ -1153,7 +1221,7 @@ void CursorInputMapper::configure() { mPointerController = getPolicy()->obtainPointerController(getDeviceId()); break; case Parameters::MODE_NAVIGATION: - mSources = AINPUT_SOURCE_TRACKBALL; + mSource = AINPUT_SOURCE_TRACKBALL; mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; @@ -1210,16 +1278,18 @@ void CursorInputMapper::dumpParameters(String8& dump) { void CursorInputMapper::initializeLocked() { mAccumulator.clear(); - mLocked.down = false; + mLocked.buttonState = 0; mLocked.downTime = 0; } void CursorInputMapper::reset() { for (;;) { + uint32_t buttonState; { // acquire lock AutoMutex _l(mLock); - if (! mLocked.down) { + buttonState = mLocked.buttonState; + if (!buttonState) { initializeLocked(); break; // done } @@ -1227,8 +1297,10 @@ void CursorInputMapper::reset() { // Synthesize button up event on reset. nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC); - mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE; - mAccumulator.btnMouse = false; + mAccumulator.clear(); + mAccumulator.buttonDown = 0; + mAccumulator.buttonUp = buttonState; + mAccumulator.fields = Accumulator::FIELD_BUTTONS; sync(when); } @@ -1237,24 +1309,25 @@ void CursorInputMapper::reset() { void CursorInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->type) { - case EV_KEY: - switch (rawEvent->scanCode) { - case BTN_LEFT: - case BTN_RIGHT: - case BTN_MIDDLE: - case BTN_SIDE: - case BTN_EXTRA: - case BTN_FORWARD: - case BTN_BACK: - case BTN_TASK: - mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE; - mAccumulator.btnMouse = rawEvent->value != 0; + case EV_KEY: { + uint32_t buttonState = getButtonStateForScanCode(rawEvent->scanCode); + if (buttonState) { + if (rawEvent->value) { + mAccumulator.buttonDown = buttonState; + mAccumulator.buttonUp = 0; + } else { + mAccumulator.buttonDown = 0; + mAccumulator.buttonUp = buttonState; + } + mAccumulator.fields |= Accumulator::FIELD_BUTTONS; + // Sync now since BTN_MOUSE is not necessarily followed by SYN_REPORT and // we need to ensure that we report the up/down promptly. sync(rawEvent->when); break; } break; + } case EV_REL: switch (rawEvent->scanCode) { @@ -1293,30 +1366,34 @@ 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; { // acquire lock AutoMutex _l(mLock); - bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE; + bool down, downChanged; + bool wasDown = isPointerDown(mLocked.buttonState); + bool buttonsChanged = fields & Accumulator::FIELD_BUTTONS; + if (buttonsChanged) { + mLocked.buttonState = (mLocked.buttonState | mAccumulator.buttonDown) + & ~mAccumulator.buttonUp; - if (downChanged) { - if (mAccumulator.btnMouse) { - if (!mLocked.down) { - mLocked.down = true; - mLocked.downTime = when; - } else { - downChanged = false; - } + down = isPointerDown(mLocked.buttonState); + + if (!wasDown && down) { + mLocked.downTime = when; + downChanged = true; + } else if (wasDown && !down) { + downChanged = true; } else { - if (mLocked.down) { - mLocked.down = false; - } else { - downChanged = false; - } + downChanged = false; } + } else { + down = wasDown; + downChanged = false; } downTime = mLocked.downTime; @@ -1324,8 +1401,8 @@ void CursorInputMapper::sync(nsecs_t when) { float deltaY = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f; if (downChanged) { - motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (mLocked.down || mPointerController == NULL) { + motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; + } else if (down || mPointerController == NULL) { motionEventAction = AMOTION_EVENT_ACTION_MOVE; } else { motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; @@ -1364,21 +1441,29 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.clear(); + motionEventEdgeFlags = AMOTION_EVENT_EDGE_FLAG_NONE; + if (mPointerController != NULL) { mPointerController->move(deltaX, deltaY); - if (downChanged) { - mPointerController->setButtonState(mLocked.down ? POINTER_BUTTON_1 : 0); + if (buttonsChanged) { + mPointerController->setButtonState(mLocked.buttonState); } + float x, y; mPointerController->getPosition(&x, &y); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); + + if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) { + motionEventEdgeFlags = calculateEdgeFlagsUsingPointerBounds( + mPointerController, x, y); + } } else { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); } - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mLocked.down ? 1.0f : 0.0f); + pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); if (mHaveVWheel && (fields & Accumulator::FIELD_REL_WHEEL)) { vscroll = mAccumulator.relWheel; @@ -1406,8 +1491,8 @@ 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, + getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, + motionEventAction, 0, metaState, motionEventEdgeFlags, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); mAccumulator.clear(); @@ -1416,7 +1501,7 @@ void CursorInputMapper::sync(nsecs_t when) { pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, + getDispatcher()->notifyMotion(when, getDeviceId(), mSource, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerId, &pointerCoords, mXPrecision, mYPrecision, downTime); } @@ -1433,7 +1518,9 @@ int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCod void CursorInputMapper::fadePointer() { { // acquire lock AutoMutex _l(mLock); - mPointerController->fade(); + if (mPointerController != NULL) { + mPointerController->fade(); + } } // release lock } @@ -1453,7 +1540,7 @@ TouchInputMapper::~TouchInputMapper() { } uint32_t TouchInputMapper::getSources() { - return mSources; + return mTouchSource; } void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { @@ -1464,38 +1551,33 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { // Ensure surface information is up to date so that orientation changes are // noticed immediately. - configureSurfaceLocked(); + if (!configureSurfaceLocked()) { + return; + } - info->addMotionRange(AMOTION_EVENT_AXIS_X, mLocked.orientedRanges.x); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mLocked.orientedRanges.y); + info->addMotionRange(mLocked.orientedRanges.x); + info->addMotionRange(mLocked.orientedRanges.y); if (mLocked.orientedRanges.havePressure) { - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, - mLocked.orientedRanges.pressure); + info->addMotionRange(mLocked.orientedRanges.pressure); } if (mLocked.orientedRanges.haveSize) { - info->addMotionRange(AMOTION_EVENT_AXIS_SIZE, - mLocked.orientedRanges.size); + info->addMotionRange(mLocked.orientedRanges.size); } if (mLocked.orientedRanges.haveTouchSize) { - info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MAJOR, - mLocked.orientedRanges.touchMajor); - info->addMotionRange(AMOTION_EVENT_AXIS_TOUCH_MINOR, - mLocked.orientedRanges.touchMinor); + info->addMotionRange(mLocked.orientedRanges.touchMajor); + info->addMotionRange(mLocked.orientedRanges.touchMinor); } if (mLocked.orientedRanges.haveToolSize) { - info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MAJOR, - mLocked.orientedRanges.toolMajor); - info->addMotionRange(AMOTION_EVENT_AXIS_TOOL_MINOR, - mLocked.orientedRanges.toolMinor); + info->addMotionRange(mLocked.orientedRanges.toolMajor); + info->addMotionRange(mLocked.orientedRanges.toolMinor); } if (mLocked.orientedRanges.haveOrientation) { - info->addMotionRange(AMOTION_EVENT_AXIS_ORIENTATION, - mLocked.orientedRanges.orientation); + info->addMotionRange(mLocked.orientedRanges.orientation); } } // release lock } @@ -1509,9 +1591,8 @@ void TouchInputMapper::dump(String8& dump) { dumpRawAxes(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); @@ -1523,7 +1604,10 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "ToolSizeAreaBias: %0.3f\n", mLocked.toolSizeAreaBias); dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mLocked.pressureScale); dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mLocked.sizeScale); - dump.appendFormat(INDENT4 "OrientationSCale: %0.3f\n", mLocked.orientationScale); + dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mLocked.orientationScale); + + dump.appendFormat(INDENT3 "Last Touch:\n"); + dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount); } // release lock } @@ -1557,10 +1641,10 @@ void TouchInputMapper::configure() { // Configure sources. switch (mParameters.deviceType) { case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - mSources = AINPUT_SOURCE_TOUCHSCREEN; + mTouchSource = AINPUT_SOURCE_TOUCHSCREEN; break; case Parameters::DEVICE_TYPE_TOUCH_PAD: - mSources = AINPUT_SOURCE_TOUCHPAD; + mTouchSource = AINPUT_SOURCE_TOUCHPAD; break; default: assert(false); @@ -1593,17 +1677,20 @@ void TouchInputMapper::configureParameters() { deviceTypeString)) { if (deviceTypeString == "touchScreen") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString != "touchPad") { + } else if (deviceTypeString == "touchPad") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else { LOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); } } - bool isTouchScreen = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - mParameters.orientationAware = isTouchScreen; + mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), mParameters.orientationAware); - mParameters.associatedDisplayId = mParameters.orientationAware || isTouchScreen ? 0 : -1; + mParameters.associatedDisplayId = mParameters.orientationAware + || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN + ? 0 : -1; } void TouchInputMapper::dumpParameters(String8& dump) { @@ -1657,21 +1744,36 @@ 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; - bool wantOrientation = mParameters.orientationAware; - // Note: getDisplayInfo is non-reentrant so we can continue holding the lock. if (! getPolicy()->getDisplayInfo(mParameters.associatedDisplayId, - wantSize ? &width : NULL, wantSize ? &height : NULL, - wantOrientation ? &orientation : NULL)) { + &mLocked.associatedDisplayWidth, &mLocked.associatedDisplayHeight, + &mLocked.associatedDisplayOrientation)) { return false; } + + // A touch screen inherits the dimensions of the display. + if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { + width = mLocked.associatedDisplayWidth; + height = mLocked.associatedDisplayHeight; + } + + // The device inherits the orientation of the display if it is orientation aware. + if (mParameters.orientationAware) { + orientation = mLocked.associatedDisplayOrientation; + } } bool orientationChanged = mLocked.surfaceOrientation != orientation; @@ -1681,39 +1783,24 @@ bool TouchInputMapper::configureSurfaceLocked() { bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height; if (sizeChanged) { - LOGI("Device reconfigured: id=%d, name='%s', display size is now %dx%d", + LOGI("Device reconfigured: id=%d, name='%s', surface size is now %dx%d", getDeviceId(), getDeviceName().string(), width, height); mLocked.surfaceWidth = width; 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; + + mLocked.orientedRanges.x.axis = AMOTION_EVENT_AXIS_X; + mLocked.orientedRanges.x.source = mTouchSource; + mLocked.orientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; + mLocked.orientedRanges.y.source = mTouchSource; + + 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 @@ -1726,11 +1813,16 @@ bool TouchInputMapper::configureSurfaceLocked() { // TouchMajor and TouchMinor factors. if (mCalibration.touchSizeCalibration != Calibration::TOUCH_SIZE_CALIBRATION_NONE) { mLocked.orientedRanges.haveTouchSize = true; + + mLocked.orientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; + mLocked.orientedRanges.touchMajor.source = mTouchSource; mLocked.orientedRanges.touchMajor.min = 0; mLocked.orientedRanges.touchMajor.max = diagonalSize; mLocked.orientedRanges.touchMajor.flat = 0; mLocked.orientedRanges.touchMajor.fuzz = 0; + mLocked.orientedRanges.touchMinor = mLocked.orientedRanges.touchMajor; + mLocked.orientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; } // ToolMajor and ToolMinor factors. @@ -1774,11 +1866,16 @@ bool TouchInputMapper::configureSurfaceLocked() { } mLocked.orientedRanges.haveToolSize = true; + + mLocked.orientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; + mLocked.orientedRanges.toolMajor.source = mTouchSource; mLocked.orientedRanges.toolMajor.min = 0; mLocked.orientedRanges.toolMajor.max = diagonalSize; mLocked.orientedRanges.toolMajor.flat = 0; mLocked.orientedRanges.toolMajor.fuzz = 0; + mLocked.orientedRanges.toolMinor = mLocked.orientedRanges.toolMajor; + mLocked.orientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; } // Pressure factors. @@ -1807,6 +1904,9 @@ bool TouchInputMapper::configureSurfaceLocked() { } mLocked.orientedRanges.havePressure = true; + + mLocked.orientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; + mLocked.orientedRanges.pressure.source = mTouchSource; mLocked.orientedRanges.pressure.min = 0; mLocked.orientedRanges.pressure.max = 1.0; mLocked.orientedRanges.pressure.flat = 0; @@ -1823,6 +1923,9 @@ bool TouchInputMapper::configureSurfaceLocked() { } mLocked.orientedRanges.haveSize = true; + + mLocked.orientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; + mLocked.orientedRanges.size.source = mTouchSource; mLocked.orientedRanges.size.min = 0; mLocked.orientedRanges.size.max = 1.0; mLocked.orientedRanges.size.flat = 0; @@ -1839,6 +1942,8 @@ bool TouchInputMapper::configureSurfaceLocked() { } } + mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; + mLocked.orientedRanges.orientation.source = mTouchSource; mLocked.orientedRanges.orientation.min = - M_PI_2; mLocked.orientedRanges.orientation.max = M_PI_2; mLocked.orientedRanges.orientation.flat = 0; @@ -1847,38 +1952,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; @@ -1891,8 +2009,6 @@ void TouchInputMapper::dumpSurfaceLocked(String8& dump) { } void TouchInputMapper::configureVirtualKeysLocked() { - assert(mRawAxes.x.valid && mRawAxes.y.valid); - Vector<VirtualKeyDefinition> virtualKeyDefinitions; getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); @@ -1906,8 +2022,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 = @@ -1942,7 +2058,6 @@ void TouchInputMapper::configureVirtualKeysLocked() { * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop; - } } @@ -1965,12 +2080,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; @@ -2182,20 +2291,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: @@ -2363,8 +2458,10 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { uint32_t policyFlags = 0; if (mLastTouch.pointerCount == 0 && mCurrentTouch.pointerCount != 0) { - // Hide the pointer on an initial down. - getContext()->fadePointer(); + if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) { + // If this is a touch screen, hide the pointer on an initial down. + getContext()->fadePointer(); + } // Initial downs on external touch devices should wake the device. // We don't do this for internal touch screens to prevent them from waking @@ -2378,7 +2475,7 @@ void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) { // Process touches and virtual keys. TouchResult touchResult = consumeOffScreenTouches(when, policyFlags); if (touchResult == DISPATCH_TOUCH) { - detectGestures(when); + suppressSwipeOntoVirtualKeys(when); dispatchTouches(when, policyFlags); } @@ -2505,7 +2602,7 @@ TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches( return touchResult; } -void TouchInputMapper::detectGestures(nsecs_t when) { +void TouchInputMapper::suppressSwipeOntoVirtualKeys(nsecs_t when) { // Disable all virtual key touches that happen within a short time interval of the // most recent touch. The idea is to filter out stray virtual key presses when // interacting with the touch screen. @@ -2623,14 +2720,14 @@ 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 AutoMutex _l(mLock); // Walk through the the active pointers and map touch screen coordinates (TouchData) into - // display coordinates (PointerCoords) and adjust for display orientation. + // display or surface coordinates (PointerCoords) and adjust for display orientation. for (uint32_t outIndex = 0; ! idBits.isEmpty(); outIndex++) { uint32_t id = idBits.firstMarkedBit(); idBits.clearBit(id); @@ -2638,10 +2735,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) { @@ -2779,33 +2872,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. @@ -2831,18 +2925,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); } } @@ -2850,18 +2948,15 @@ void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags, yPrecision = mLocked.orientedYPrecision; } // release lock - getDispatcher()->notifyMotion(when, getDeviceId(), mSources, policyFlags, + getDispatcher()->notifyMotion(when, getDeviceId(), mTouchSource, policyFlags, motionEventAction, 0, getContext()->getGlobalMetaState(), motionEventEdgeFlags, pointerCount, pointerIds, pointerCoords, xPrecision, yPrecision, mDownTime); } 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( @@ -3069,11 +3164,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. @@ -3092,7 +3182,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 @@ -3153,11 +3243,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 @@ -3214,7 +3299,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. @@ -3854,7 +3939,12 @@ void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { for (size_t i = 0; i < mAxes.size(); i++) { const Axis& axis = mAxes.valueAt(i); - info->addMotionRange(axis.axis, axis.min, axis.max, axis.flat, axis.fuzz); + info->addMotionRange(axis.axisInfo.axis, AINPUT_SOURCE_JOYSTICK, + axis.min, axis.max, axis.flat, axis.fuzz); + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + info->addMotionRange(axis.axisInfo.highAxis, AINPUT_SOURCE_JOYSTICK, + axis.min, axis.max, axis.flat, axis.fuzz); + } } } @@ -3865,18 +3955,29 @@ void JoystickInputMapper::dump(String8& dump) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axis); - char name[32]; + const char* label = getAxisLabel(axis.axisInfo.axis); if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; + dump.appendFormat(INDENT4 "%s", label); } else { - snprintf(name, sizeof(name), "%d", axis.axis); + dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + label = getAxisLabel(axis.axisInfo.highAxis); + if (label) { + dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); + } else { + dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, + axis.axisInfo.splitValue); + } + } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { + dump.append(" (invert)"); } - dump.appendFormat(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, " - "scale=%0.3f, offset=%0.3f\n", - name, axis.min, axis.max, axis.flat, axis.fuzz, - axis.scale, axis.offset); + + dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n", + axis.min, axis.max, axis.flat, axis.fuzz); + dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " + "highScale=%0.5f, highOffset=%0.5f\n", + axis.scale, axis.offset, axis.highScale, axis.highOffset); dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n", mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz); @@ -3891,25 +3992,38 @@ void JoystickInputMapper::configure() { RawAbsoluteAxisInfo rawAxisInfo; getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo); if (rawAxisInfo.valid) { - int32_t axisId; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId); + // Map axis. + AxisInfo axisInfo; + bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); if (!explicitlyMapped) { // Axis is not explicitly mapped, will choose a generic axis later. - axisId = -1; + axisInfo.mode = AxisInfo::MODE_NORMAL; + axisInfo.axis = -1; } + // Apply flat override. + int32_t rawFlat = axisInfo.flatOverride < 0 + ? rawAxisInfo.flat : axisInfo.flatOverride; + + // Calculate scaling factors and limits. Axis axis; - if (isCenteredAxis(axisId)) { + if (axisInfo.mode == AxisInfo::MODE_SPLIT) { + float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); + float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, 0.0f, highScale, 0.0f, + 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); + } else if (isCenteredAxis(axisInfo.axis)) { float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisId, explicitlyMapped, - scale, offset, -1.0f, 1.0f, - rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, offset, scale, offset, + -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } else { float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisId, explicitlyMapped, - scale, 0.0f, 0.0f, 1.0f, - rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, 0.0f, scale, 0.0f, + 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } // To eliminate noise while the joystick is at rest, filter out small variations @@ -3934,14 +4048,14 @@ void JoystickInputMapper::configure() { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); - if (axis.axis < 0) { + if (axis.axisInfo.axis < 0) { while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && haveAxis(nextGenericAxisId)) { nextGenericAxisId += 1; } if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axis = nextGenericAxisId; + axis.axisInfo.axis = nextGenericAxisId; nextGenericAxisId += 1; } else { LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " @@ -3954,10 +4068,13 @@ void JoystickInputMapper::configure() { } } -bool JoystickInputMapper::haveAxis(int32_t axis) { +bool JoystickInputMapper::haveAxis(int32_t axisId) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { - if (mAxes.valueAt(i).axis == axis) { + const Axis& axis = mAxes.valueAt(i); + if (axis.axisInfo.axis == axisId + || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT + && axis.axisInfo.highAxis == axisId)) { return true; } } @@ -3987,6 +4104,8 @@ bool JoystickInputMapper::isCenteredAxis(int32_t axis) { case AMOTION_EVENT_AXIS_HAT_X: case AMOTION_EVENT_AXIS_HAT_Y: case AMOTION_EVENT_AXIS_ORIENTATION: + case AMOTION_EVENT_AXIS_RUDDER: + case AMOTION_EVENT_AXIS_WHEEL: return true; default: return false; @@ -4000,7 +4119,7 @@ void JoystickInputMapper::reset() { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); - axis.newValue = 0; + axis.resetValue(); } sync(when, true /*force*/); @@ -4014,10 +4133,34 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) { ssize_t index = mAxes.indexOfKey(rawEvent->scanCode); if (index >= 0) { Axis& axis = mAxes.editValueAt(index); - float newValue = rawEvent->value * axis.scale + axis.offset; - if (newValue != axis.newValue) { - axis.newValue = newValue; + float newValue, highNewValue; + switch (axis.axisInfo.mode) { + case AxisInfo::MODE_INVERT: + newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) + * axis.scale + axis.offset; + highNewValue = 0.0f; + break; + case AxisInfo::MODE_SPLIT: + if (rawEvent->value < axis.axisInfo.splitValue) { + newValue = (axis.axisInfo.splitValue - rawEvent->value) + * axis.scale + axis.offset; + highNewValue = 0.0f; + } else if (rawEvent->value > axis.axisInfo.splitValue) { + newValue = 0.0f; + highNewValue = (rawEvent->value - axis.axisInfo.splitValue) + * axis.highScale + axis.highOffset; + } else { + newValue = 0.0f; + highNewValue = 0.0f; + } + break; + default: + newValue = rawEvent->value * axis.scale + axis.offset; + highNewValue = 0.0f; + break; } + axis.newValue = newValue; + axis.highNewValue = highNewValue; } break; } @@ -4033,7 +4176,7 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) { } void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!force && !haveAxesChangedSignificantly()) { + if (!filterAxes(force)) { return; } @@ -4044,9 +4187,11 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - pointerCoords.setAxisValue(axis.axis, axis.newValue); - axis.oldValue = axis.newValue; + const Axis& axis = mAxes.valueAt(i); + pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue); + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + pointerCoords.setAxisValue(axis.axisInfo.highAxis, axis.highCurrentValue); + } } // Moving a joystick axis should not wake the devide because joysticks can @@ -4061,12 +4206,49 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { 1, &pointerId, &pointerCoords, 0, 0, 0); } -bool JoystickInputMapper::haveAxesChangedSignificantly() { +bool JoystickInputMapper::filterAxes(bool force) { + bool atLeastOneSignificantChange = force; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.newValue != axis.oldValue - && fabs(axis.newValue - axis.oldValue) > axis.filter) { + Axis& axis = mAxes.editValueAt(i); + if (force || hasValueChangedSignificantly(axis.filter, + axis.newValue, axis.currentValue, axis.min, axis.max)) { + axis.currentValue = axis.newValue; + atLeastOneSignificantChange = true; + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + if (force || hasValueChangedSignificantly(axis.filter, + axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { + axis.highCurrentValue = axis.highNewValue; + atLeastOneSignificantChange = true; + } + } + } + return atLeastOneSignificantChange; +} + +bool JoystickInputMapper::hasValueChangedSignificantly( + float filter, float newValue, float currentValue, float min, float max) { + if (newValue != currentValue) { + // Filter out small changes in value unless the value is converging on the axis + // bounds or center point. This is intended to reduce the amount of information + // sent to applications by particularly noisy joysticks (such as PS3). + if (fabs(newValue - currentValue) > filter + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) + || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { + return true; + } + } + return false; +} + +bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( + float filter, float newValue, float currentValue, float thresholdValue) { + float newDistance = fabs(newValue - thresholdValue); + if (newDistance < filter) { + float oldDistance = fabs(currentValue - thresholdValue); + if (newDistance < oldDistance) { return true; } } |