diff options
author | Jeff Brown <jeffbrown@google.com> | 2011-05-24 14:39:53 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-05-24 14:39:53 -0700 |
commit | c1eb82373a89cff9ed04e581a8fb39eee1f739ab (patch) | |
tree | fb1c89338ae64b6946fe3f49d9b40fd6dba1ccca /services | |
parent | b5b1fb25853eb2e00f981d3b0bb52acd50684c4f (diff) | |
parent | 80fd47ce75253dcdc2cfa85d7a3f42634b923a47 (diff) | |
download | frameworks_base-c1eb82373a89cff9ed04e581a8fb39eee1f739ab.zip frameworks_base-c1eb82373a89cff9ed04e581a8fb39eee1f739ab.tar.gz frameworks_base-c1eb82373a89cff9ed04e581a8fb39eee1f739ab.tar.bz2 |
Merge "Input device protocol enhancements."
Diffstat (limited to 'services')
-rw-r--r-- | services/input/EventHub.cpp | 39 | ||||
-rw-r--r-- | services/input/EventHub.h | 52 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 358 | ||||
-rw-r--r-- | services/input/InputReader.h | 90 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 4 |
5 files changed, 405 insertions, 138 deletions
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index ff4b11a..af30887 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -101,7 +101,7 @@ EventHub::Device::Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier) : next(NULL), fd(fd), id(id), path(path), identifier(identifier), - classes(0), keyBitmask(NULL), relBitmask(NULL), + classes(0), keyBitmask(NULL), relBitmask(NULL), propBitmask(NULL), configuration(NULL), virtualKeyMap(NULL) { } @@ -109,6 +109,7 @@ EventHub::Device::~Device() { close(); delete[] keyBitmask; delete[] relBitmask; + delete[] propBitmask; delete configuration; delete virtualKeyMap; } @@ -205,6 +206,18 @@ bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { return false; } +bool EventHub::hasInputProperty(int32_t deviceId, int property) const { + if (property >= 0 && property <= INPUT_PROP_MAX) { + AutoMutex _l(mLock); + + Device* device = getDeviceLocked(deviceId); + if (device && device->propBitmask) { + return test_bit(property, device->propBitmask); + } + } + return false; +} + int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { if (scanCode >= 0 && scanCode <= KEY_MAX) { AutoMutex _l(mLock); @@ -834,24 +847,24 @@ int EventHub::openDevice(const char *devicePath) { memset(sw_bitmask, 0, sizeof(sw_bitmask)); ioctl(fd, EVIOCGBIT(EV_SW, sizeof(sw_bitmask)), sw_bitmask); - device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; - if (device->keyBitmask != NULL) { - memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); - } else { - delete device; - LOGE("out of memory allocating key bitmask"); - return -1; - } + uint8_t prop_bitmask[sizeof_bit_array(INPUT_PROP_MAX + 1)]; + memset(prop_bitmask, 0, sizeof(prop_bitmask)); + ioctl(fd, EVIOCGPROP(sizeof(prop_bitmask)), prop_bitmask); + device->keyBitmask = new uint8_t[sizeof(key_bitmask)]; device->relBitmask = new uint8_t[sizeof(rel_bitmask)]; - if (device->relBitmask != NULL) { - memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask)); - } else { + device->propBitmask = new uint8_t[sizeof(prop_bitmask)]; + + if (!device->keyBitmask || !device->relBitmask || !device->propBitmask) { delete device; - LOGE("out of memory allocating rel bitmask"); + LOGE("out of memory allocating bitmasks"); return -1; } + memcpy(device->keyBitmask, key_bitmask, sizeof(key_bitmask)); + memcpy(device->relBitmask, rel_bitmask, sizeof(rel_bitmask)); + memcpy(device->propBitmask, prop_bitmask, sizeof(prop_bitmask)); + // See if this is a keyboard. Ignore everything in the button range except for // joystick and gamepad buttons which are handled like keyboards for the most part. bool haveKeyboardKeys = containsNonZeroByte(key_bitmask, 0, sizeof_bit_array(BTN_MISC)) diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 4d26a95..ca33619 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -34,25 +34,38 @@ #include <linux/input.h> -/* These constants are not defined in linux/input.h but they are part of the multitouch - * input protocol. */ - -#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ -#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ -#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ -#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ -#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ -#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */ -#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */ -#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device (finger, pen, ...) */ -#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ -#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ -#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ - -#define MT_TOOL_FINGER 0 /* Identifies a finger */ -#define MT_TOOL_PEN 1 /* Identifies a pen */ +/* These constants are not defined in linux/input.h in the version of the kernel + * headers currently provided with Bionic. */ + +#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) + +#define INPUT_PROP_POINTER 0x00 +#define INPUT_PROP_DIRECT 0x01 +#define INPUT_PROP_BUTTONPAD 0x02 +#define INPUT_PROP_SEMI_MT 0x03 +#define INPUT_PROP_MAX 0x1f +#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) + +#define ABS_MT_SLOT 0x2f +#define ABS_MT_TOUCH_MAJOR 0x30 +#define ABS_MT_TOUCH_MINOR 0x31 +#define ABS_MT_WIDTH_MAJOR 0x32 +#define ABS_MT_WIDTH_MINOR 0x33 +#define ABS_MT_ORIENTATION 0x34 +#define ABS_MT_POSITION_X 0x35 +#define ABS_MT_POSITION_Y 0x36 +#define ABS_MT_TOOL_TYPE 0x37 +#define ABS_MT_BLOB_ID 0x38 +#define ABS_MT_TRACKING_ID 0x39 +#define ABS_MT_PRESSURE 0x3a +#define ABS_MT_DISTANCE 0x3b + +#define MT_TOOL_FINGER 0 +#define MT_TOOL_PEN 1 #define SYN_MT_REPORT 2 +#define SYN_DROPPED 3 + /* Convenience constants. */ @@ -172,6 +185,8 @@ public: virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; + virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const = 0; @@ -236,6 +251,8 @@ public: virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; + virtual bool hasInputProperty(int32_t deviceId, int property) const; + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const; @@ -286,6 +303,7 @@ private: uint32_t classes; uint8_t* keyBitmask; uint8_t* relBitmask; + uint8_t* propBitmask; String8 configurationFile; PropertyMap* configuration; VirtualKeyMap* virtualKeyMap; diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 6003207..f07b01d 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -28,7 +28,7 @@ #define DEBUG_VIRTUAL_KEYS 0 // Log debug messages about pointers. -#define DEBUG_POINTERS 0 +#define DEBUG_POINTERS 1 // Log debug messages about pointer assignment calculations. #define DEBUG_POINTER_ASSIGNMENT 0 @@ -58,6 +58,9 @@ namespace android { // --- Constants --- +// Maximum number of slots supported when using the slot-based Multitouch Protocol B. +static const size_t MAX_SLOTS = 32; + // Quiet time between certain gesture transitions. // Time to allow for all fingers or buttons to settle into a stable state before // starting a new gesture. @@ -809,7 +812,8 @@ bool InputReaderThread::threadLoop() { // --- InputDevice --- InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) : - mContext(context), mId(id), mName(name), mSources(0), mIsExternal(false) { + mContext(context), mId(id), mName(name), mSources(0), + mIsExternal(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { @@ -898,9 +902,26 @@ void InputDevice::process(const RawEvent* rawEvents, size_t count) { rawEvent->value, rawEvent->flags); #endif - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); + if (mDropUntilNextSync) { + if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_REPORT) { + mDropUntilNextSync = false; +#if DEBUG_RAW_EVENTS + LOGD("Recovered from input event buffer overrun."); +#endif + } else { +#if DEBUG_RAW_EVENTS + LOGD("Dropped input event while waiting for next input sync."); +#endif + } + } else if (rawEvent->type == EV_SYN && rawEvent->scanCode == SYN_DROPPED) { + LOGI("Detected input event buffer overrun for device %s.", mName.string()); + mDropUntilNextSync = true; + reset(); + } else { + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->process(rawEvent); + } } } } @@ -1812,6 +1833,10 @@ void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { info->addMotionRange(mLocked.orientedRanges.orientation); } + if (mLocked.orientedRanges.haveDistance) { + info->addMotionRange(mLocked.orientedRanges.distance); + } + if (mPointerController != NULL) { float minX, minY, maxX, maxY; if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { @@ -1849,6 +1874,7 @@ void TouchInputMapper::dump(String8& dump) { 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 "DistanceScale: %0.3f\n", mLocked.distanceScale); dump.appendFormat(INDENT3 "Last Touch:\n"); dump.appendFormat(INDENT4 "Pointer Count: %d\n", mLastTouch.pointerCount); @@ -1889,6 +1915,7 @@ void TouchInputMapper::initializeLocked() { mLocked.orientedRanges.haveTouchSize = false; mLocked.orientedRanges.haveToolSize = false; mLocked.orientedRanges.haveOrientation = false; + mLocked.orientedRanges.haveDistance = false; mPointerGesture.reset(); } @@ -1947,9 +1974,14 @@ void TouchInputMapper::configureParameters() { // The device is a cursor device with a touch pad attached. // By default don't use the touch pad to move the pointer. mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { + // The device is a pointing device like a track pad. + mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; + } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { + // The device is a touch screen. + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else { - // The device is just a touch pad. - // By default use the touch pad to move the pointer and to perform related gestures. + // The device is a touch pad of unknown purpose. mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } @@ -2016,6 +2048,9 @@ void TouchInputMapper::configureRawAxes() { mRawAxes.toolMajor.clear(); mRawAxes.toolMinor.clear(); mRawAxes.orientation.clear(); + mRawAxes.distance.clear(); + mRawAxes.trackingId.clear(); + mRawAxes.slot.clear(); } void TouchInputMapper::dumpRawAxes(String8& dump) { @@ -2028,6 +2063,9 @@ void TouchInputMapper::dumpRawAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawAxes.toolMajor, "ToolMajor"); dumpRawAbsoluteAxisInfo(dump, mRawAxes.toolMinor, "ToolMinor"); dumpRawAbsoluteAxisInfo(dump, mRawAxes.orientation, "Orientation"); + dumpRawAbsoluteAxisInfo(dump, mRawAxes.distance, "Distance"); + dumpRawAbsoluteAxisInfo(dump, mRawAxes.trackingId, "TrackingId"); + dumpRawAbsoluteAxisInfo(dump, mRawAxes.slot, "Slot"); } bool TouchInputMapper::configureSurfaceLocked() { @@ -2234,6 +2272,8 @@ bool TouchInputMapper::configureSurfaceLocked() { } } + mLocked.orientedRanges.haveOrientation = true; + mLocked.orientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; mLocked.orientedRanges.orientation.source = mTouchSource; mLocked.orientedRanges.orientation.min = - M_PI_2; @@ -2241,6 +2281,31 @@ bool TouchInputMapper::configureSurfaceLocked() { mLocked.orientedRanges.orientation.flat = 0; mLocked.orientedRanges.orientation.fuzz = 0; } + + // Distance + mLocked.distanceScale = 0; + if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { + if (mCalibration.distanceCalibration + == Calibration::DISTANCE_CALIBRATION_SCALED) { + if (mCalibration.haveDistanceScale) { + mLocked.distanceScale = mCalibration.distanceScale; + } else { + mLocked.distanceScale = 1.0f; + } + } + + mLocked.orientedRanges.haveDistance = true; + + mLocked.orientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; + mLocked.orientedRanges.distance.source = mTouchSource; + mLocked.orientedRanges.distance.min = + mRawAxes.distance.minValue * mLocked.distanceScale; + mLocked.orientedRanges.distance.max = + mRawAxes.distance.minValue * mLocked.distanceScale; + mLocked.orientedRanges.distance.flat = 0; + mLocked.orientedRanges.distance.fuzz = + mRawAxes.distance.fuzz * mLocked.distanceScale; + } } if (orientationChanged || sizeChanged) { @@ -2518,6 +2583,23 @@ void TouchInputMapper::parseCalibration() { orientationCalibrationString.string()); } } + + // Distance + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; + String8 distanceCalibrationString; + if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { + if (distanceCalibrationString == "none") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } else if (distanceCalibrationString == "scaled") { + out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } else if (distanceCalibrationString != "default") { + LOGW("Invalid value for touch.distance.calibration: '%s'", + distanceCalibrationString.string()); + } + } + + out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), + out.distanceScale); } void TouchInputMapper::resolveCalibration() { @@ -2618,6 +2700,20 @@ void TouchInputMapper::resolveCalibration() { default: break; } + + // Distance + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_DEFAULT: + if (mRawAxes.distance.valid) { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; + } else { + mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; + } + break; + + default: + break; + } } void TouchInputMapper::dumpCalibration(String8& dump) { @@ -2740,6 +2836,23 @@ void TouchInputMapper::dumpCalibration(String8& dump) { default: LOG_ASSERT(false); } + + // Distance + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_NONE: + dump.append(INDENT4 "touch.distance.calibration: none\n"); + break; + case Calibration::DISTANCE_CALIBRATION_SCALED: + dump.append(INDENT4 "touch.distance.calibration: scaled\n"); + break; + default: + LOG_ASSERT(false); + } + + if (mCalibration.haveDistanceScale) { + dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", + mCalibration.distanceScale); + } } void TouchInputMapper::reset() { @@ -3247,6 +3360,16 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, orientation = 0; } + // Distance + float distance; + switch (mCalibration.distanceCalibration) { + case Calibration::DISTANCE_CALIBRATION_SCALED: + distance = in.distance * mLocked.distanceScale; + break; + default: + distance = 0; + } + // X and Y // Adjust coords for surface orientation. float x, y; @@ -3289,6 +3412,9 @@ void TouchInputMapper::prepareTouches(int32_t* outEdgeFlags, out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); + if (distance != 0) { + out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); + } // Write output properties. PointerProperties& properties = mCurrentTouchProperties[i]; @@ -5020,13 +5146,13 @@ bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCode SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : TouchInputMapper(device) { - initialize(); + clearState(); } SingleTouchInputMapper::~SingleTouchInputMapper() { } -void SingleTouchInputMapper::initialize() { +void SingleTouchInputMapper::clearState() { mAccumulator.clear(); mDown = false; @@ -5040,7 +5166,7 @@ void SingleTouchInputMapper::initialize() { void SingleTouchInputMapper::reset() { TouchInputMapper::reset(); - initialize(); + clearState(); } void SingleTouchInputMapper::process(const RawEvent* rawEvent) { @@ -5144,6 +5270,7 @@ void SingleTouchInputMapper::sync(nsecs_t when) { mCurrentTouch.pointers[0].toolMajor = mToolWidth; mCurrentTouch.pointers[0].toolMinor = mToolWidth; mCurrentTouch.pointers[0].orientation = 0; + mCurrentTouch.pointers[0].distance = 0; mCurrentTouch.pointers[0].isStylus = false; // TODO: Set stylus mCurrentTouch.idToIndex[0] = 0; mCurrentTouch.idBits.markBit(0); @@ -5168,22 +5295,22 @@ void SingleTouchInputMapper::configureRawAxes() { // --- MultiTouchInputMapper --- MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { - initialize(); + TouchInputMapper(device), mSlotCount(0), mUsingSlotsProtocol(false) { + clearState(); } MultiTouchInputMapper::~MultiTouchInputMapper() { } -void MultiTouchInputMapper::initialize() { - mAccumulator.clear(); +void MultiTouchInputMapper::clearState() { + mAccumulator.clear(mSlotCount); mButtonState = 0; } void MultiTouchInputMapper::reset() { TouchInputMapper::reset(); - initialize(); + clearState(); } void MultiTouchInputMapper::process(const RawEvent* rawEvent) { @@ -5203,45 +5330,69 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { } case EV_ABS: { - uint32_t pointerIndex = mAccumulator.pointerCount; - Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex]; + bool newSlot = false; + if (mUsingSlotsProtocol && rawEvent->scanCode == ABS_MT_SLOT) { + mAccumulator.currentSlot = rawEvent->value; + newSlot = true; + } + + if (mAccumulator.currentSlot < 0 || size_t(mAccumulator.currentSlot) >= mSlotCount) { + if (newSlot) { +#if DEBUG_POINTERS + LOGW("MultiTouch device %s emitted invalid slot index %d but it " + "should be between 0 and %d; ignoring this slot.", + getDeviceName().string(), mAccumulator.currentSlot, mSlotCount); +#endif + } + break; + } + + Accumulator::Slot* slot = &mAccumulator.slots[mAccumulator.currentSlot]; switch (rawEvent->scanCode) { case ABS_MT_POSITION_X: - pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X; - pointer->absMTPositionX = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_X; + slot->absMTPositionX = rawEvent->value; break; case ABS_MT_POSITION_Y: - pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y; - pointer->absMTPositionY = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y; + slot->absMTPositionY = rawEvent->value; break; case ABS_MT_TOUCH_MAJOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR; - pointer->absMTTouchMajor = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR; + slot->absMTTouchMajor = rawEvent->value; break; case ABS_MT_TOUCH_MINOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR; - pointer->absMTTouchMinor = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR; + slot->absMTTouchMinor = rawEvent->value; break; case ABS_MT_WIDTH_MAJOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR; - pointer->absMTWidthMajor = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR; + slot->absMTWidthMajor = rawEvent->value; break; case ABS_MT_WIDTH_MINOR: - pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR; - pointer->absMTWidthMinor = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR; + slot->absMTWidthMinor = rawEvent->value; break; case ABS_MT_ORIENTATION: - pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION; - pointer->absMTOrientation = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION; + slot->absMTOrientation = rawEvent->value; break; case ABS_MT_TRACKING_ID: - pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; - pointer->absMTTrackingId = rawEvent->value; + if (mUsingSlotsProtocol && rawEvent->value < 0) { + slot->clear(); + } else { + slot->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID; + slot->absMTTrackingId = rawEvent->value; + } break; case ABS_MT_PRESSURE: - pointer->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; - pointer->absMTPressure = rawEvent->value; + slot->fields |= Accumulator::FIELD_ABS_MT_PRESSURE; + slot->absMTPressure = rawEvent->value; + break; + case ABS_MT_TOOL_TYPE: + slot->fields |= Accumulator::FIELD_ABS_MT_TOOL_TYPE; + slot->absMTToolType = rawEvent->value; break; } break; @@ -5251,19 +5402,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { switch (rawEvent->scanCode) { case SYN_MT_REPORT: { // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - uint32_t pointerIndex = mAccumulator.pointerCount; - - if (mAccumulator.pointers[pointerIndex].fields) { - if (pointerIndex == MAX_POINTERS) { - LOGW("MultiTouch device driver returned more than maximum of %d pointers.", - MAX_POINTERS); - } else { - pointerIndex += 1; - mAccumulator.pointerCount = pointerIndex; - } - } - - mAccumulator.pointers[pointerIndex].clear(); + mAccumulator.currentSlot += 1; break; } @@ -5279,99 +5418,120 @@ void MultiTouchInputMapper::sync(nsecs_t when) { static const uint32_t REQUIRED_FIELDS = Accumulator::FIELD_ABS_MT_POSITION_X | Accumulator::FIELD_ABS_MT_POSITION_Y; - uint32_t inCount = mAccumulator.pointerCount; - uint32_t outCount = 0; + size_t inCount = mSlotCount; + size_t outCount = 0; bool havePointerIds = true; mCurrentTouch.clear(); - for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) { - const Accumulator::Pointer& inPointer = mAccumulator.pointers[inIndex]; - uint32_t fields = inPointer.fields; + for (size_t inIndex = 0; inIndex < inCount; inIndex++) { + const Accumulator::Slot& inSlot = mAccumulator.slots[inIndex]; + uint32_t fields = inSlot.fields; if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) { // Some drivers send empty MT sync packets without X / Y to indicate a pointer up. + // This may also indicate an unused slot. // Drop this finger. continue; } + if (outCount >= MAX_POINTERS) { +#if DEBUG_POINTERS + LOGD("MultiTouch device %s emitted more than maximum of %d pointers; " + "ignoring the rest.", + getDeviceName().string(), MAX_POINTERS); +#endif + break; // too many fingers! + } + PointerData& outPointer = mCurrentTouch.pointers[outCount]; - outPointer.x = inPointer.absMTPositionX; - outPointer.y = inPointer.absMTPositionY; + outPointer.x = inSlot.absMTPositionX; + outPointer.y = inSlot.absMTPositionY; if (fields & Accumulator::FIELD_ABS_MT_PRESSURE) { - if (inPointer.absMTPressure <= 0) { - // Some devices send sync packets with X / Y but with a 0 pressure to indicate - // a pointer going up. Drop this finger. - continue; - } - outPointer.pressure = inPointer.absMTPressure; + outPointer.pressure = inSlot.absMTPressure; } else { // Default pressure to 0 if absent. outPointer.pressure = 0; } if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MAJOR) { - if (inPointer.absMTTouchMajor <= 0) { + if (inSlot.absMTTouchMajor <= 0) { // Some devices send sync packets with X / Y but with a 0 touch major to indicate // a pointer going up. Drop this finger. continue; } - outPointer.touchMajor = inPointer.absMTTouchMajor; + outPointer.touchMajor = inSlot.absMTTouchMajor; } else { // Default touch area to 0 if absent. outPointer.touchMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) { - outPointer.touchMinor = inPointer.absMTTouchMinor; + outPointer.touchMinor = inSlot.absMTTouchMinor; } else { // Assume touch area is circular. outPointer.touchMinor = outPointer.touchMajor; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MAJOR) { - outPointer.toolMajor = inPointer.absMTWidthMajor; + outPointer.toolMajor = inSlot.absMTWidthMajor; } else { // Default tool area to 0 if absent. outPointer.toolMajor = 0; } if (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) { - outPointer.toolMinor = inPointer.absMTWidthMinor; + outPointer.toolMinor = inSlot.absMTWidthMinor; } else { // Assume tool area is circular. outPointer.toolMinor = outPointer.toolMajor; } if (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) { - outPointer.orientation = inPointer.absMTOrientation; + outPointer.orientation = inSlot.absMTOrientation; } else { // Default orientation to vertical if absent. outPointer.orientation = 0; } - outPointer.isStylus = false; // TODO: Handle stylus + if (fields & Accumulator::FIELD_ABS_MT_DISTANCE) { + outPointer.distance = inSlot.absMTDistance; + } else { + // Default distance is 0 (direct contact). + outPointer.distance = 0; + } + + if (fields & Accumulator::FIELD_ABS_MT_TOOL_TYPE) { + outPointer.isStylus = (inSlot.absMTToolType == MT_TOOL_PEN); + } else { + // Assume this is not a stylus. + outPointer.isStylus = false; + } // Assign pointer id using tracking id if available. if (havePointerIds) { - if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { - uint32_t id = uint32_t(inPointer.absMTTrackingId); + int32_t id; + if (mUsingSlotsProtocol) { + id = inIndex; + } else if (fields & Accumulator::FIELD_ABS_MT_TRACKING_ID) { + id = inSlot.absMTTrackingId; + } else { + id = -1; + } - if (id > MAX_POINTER_ID) { + if (id >= 0 && id <= MAX_POINTER_ID) { + outPointer.id = id; + mCurrentTouch.idToIndex[id] = outCount; + mCurrentTouch.idBits.markBit(id); + } else { + if (id >= 0) { #if DEBUG_POINTERS - LOGD("Pointers: Ignoring driver provided pointer id %d because " - "it is larger than max supported id %d", + LOGD("Pointers: Ignoring driver provided slot index or tracking id %d because " + "it is larger than the maximum supported pointer id %d", id, MAX_POINTER_ID); #endif - havePointerIds = false; - } - else { - outPointer.id = id; - mCurrentTouch.idToIndex[id] = outCount; - mCurrentTouch.idBits.markBit(id); } - } else { havePointerIds = false; } } @@ -5386,20 +5546,40 @@ void MultiTouchInputMapper::sync(nsecs_t when) { syncTouch(when, havePointerIds); - mAccumulator.clear(); + mAccumulator.clear(mUsingSlotsProtocol ? 0 : mSlotCount); } void MultiTouchInputMapper::configureRawAxes() { TouchInputMapper::configureRawAxes(); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mRawAxes.x); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mRawAxes.y); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mRawAxes.touchMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mRawAxes.touchMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mRawAxes.toolMajor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mRawAxes.toolMinor); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mRawAxes.orientation); - getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, & mRawAxes.pressure); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, &mRawAxes.x); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, &mRawAxes.y); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, &mRawAxes.touchMajor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, &mRawAxes.touchMinor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, &mRawAxes.toolMajor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, &mRawAxes.toolMinor); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, &mRawAxes.orientation); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_PRESSURE, &mRawAxes.pressure); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_DISTANCE, &mRawAxes.distance); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TRACKING_ID, &mRawAxes.trackingId); + getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_SLOT, &mRawAxes.slot); + + if (mRawAxes.trackingId.valid + && mRawAxes.slot.valid && mRawAxes.slot.minValue == 0 && mRawAxes.slot.maxValue > 0) { + mSlotCount = mRawAxes.slot.maxValue + 1; + if (mSlotCount > MAX_SLOTS) { + LOGW("MultiTouch Device %s reported %d slots but the framework " + "only supports a maximum of %d slots at this time.", + getDeviceName().string(), mSlotCount, MAX_SLOTS); + mSlotCount = MAX_SLOTS; + } + mUsingSlotsProtocol = true; + } else { + mSlotCount = MAX_POINTERS; + mUsingSlotsProtocol = false; + } + + mAccumulator.allocateSlots(mSlotCount); } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 62ac4b2..85338b6 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -331,6 +331,7 @@ private: String8 mName; uint32_t mSources; bool mIsExternal; + bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); @@ -602,6 +603,7 @@ protected: int32_t toolMajor; int32_t toolMinor; int32_t orientation; + int32_t distance; bool isStylus; inline bool operator== (const PointerData& other) const { @@ -613,7 +615,8 @@ protected: && touchMinor == other.touchMinor && toolMajor == other.toolMajor && toolMinor == other.toolMinor - && orientation == other.orientation; + && orientation == other.orientation + && distance == other.distance; } inline bool operator!= (const PointerData& other) const { return !(*this == other); @@ -759,6 +762,17 @@ protected: }; OrientationCalibration orientationCalibration; + + // Distance + enum DistanceCalibration { + DISTANCE_CALIBRATION_DEFAULT, + DISTANCE_CALIBRATION_NONE, + DISTANCE_CALIBRATION_SCALED, + }; + + DistanceCalibration distanceCalibration; + bool haveDistanceScale; + float distanceScale; } mCalibration; // Raw axis information from the driver. @@ -771,6 +785,9 @@ protected: RawAbsoluteAxisInfo toolMajor; RawAbsoluteAxisInfo toolMinor; RawAbsoluteAxisInfo orientation; + RawAbsoluteAxisInfo distance; + RawAbsoluteAxisInfo trackingId; + RawAbsoluteAxisInfo slot; } mRawAxes; // Current and previous touch sample data. @@ -819,6 +836,8 @@ protected: float orientationScale; + float distanceScale; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; @@ -840,6 +859,9 @@ protected: bool haveOrientation; InputDeviceInfo::MotionRange orientation; + + bool haveDistance; + InputDeviceInfo::MotionRange distance; } orientedRanges; // Oriented dimensions and precision. @@ -1146,7 +1168,7 @@ private: int32_t mToolWidth; int32_t mButtonState; - void initialize(); + void clearState(); void sync(nsecs_t when); }; @@ -1166,20 +1188,21 @@ protected: private: struct Accumulator { enum { - FIELD_ABS_MT_POSITION_X = 1, - FIELD_ABS_MT_POSITION_Y = 2, - FIELD_ABS_MT_TOUCH_MAJOR = 4, - FIELD_ABS_MT_TOUCH_MINOR = 8, - FIELD_ABS_MT_WIDTH_MAJOR = 16, - FIELD_ABS_MT_WIDTH_MINOR = 32, - FIELD_ABS_MT_ORIENTATION = 64, - FIELD_ABS_MT_TRACKING_ID = 128, - FIELD_ABS_MT_PRESSURE = 256, + FIELD_ABS_MT_POSITION_X = 1 << 0, + FIELD_ABS_MT_POSITION_Y = 1 << 1, + FIELD_ABS_MT_TOUCH_MAJOR = 1 << 2, + FIELD_ABS_MT_TOUCH_MINOR = 1 << 3, + FIELD_ABS_MT_WIDTH_MAJOR = 1 << 4, + FIELD_ABS_MT_WIDTH_MINOR = 1 << 5, + FIELD_ABS_MT_ORIENTATION = 1 << 6, + FIELD_ABS_MT_TRACKING_ID = 1 << 7, + FIELD_ABS_MT_PRESSURE = 1 << 8, + FIELD_ABS_MT_TOOL_TYPE = 1 << 9, + FIELD_ABS_MT_DISTANCE = 1 << 10, }; - uint32_t pointerCount; - struct Pointer { - uint32_t fields; + struct Slot { + uint32_t fields; // 0 if slot is unused int32_t absMTPositionX; int32_t absMTPositionY; @@ -1190,27 +1213,56 @@ private: int32_t absMTOrientation; int32_t absMTTrackingId; int32_t absMTPressure; + int32_t absMTToolType; + int32_t absMTDistance; + + inline Slot() { + clear(); + } inline void clear() { fields = 0; } - } pointers[MAX_POINTERS + 1]; // + 1 to remove the need for extra range checks + }; + + // Current slot index. + int32_t currentSlot; + + // Array of slots. + Slot* slots; // Bitfield of buttons that went down or up. uint32_t buttonDown; uint32_t buttonUp; - inline void clear() { - pointerCount = 0; - pointers[0].clear(); + Accumulator() : slots(NULL) { + clear(false); + } + + ~Accumulator() { + delete[] slots; + } + + void allocateSlots(size_t slotCount) { + slots = new Slot[slotCount]; + } + + void clear(size_t slotCount) { + for (size_t i = 0; i < slotCount; i++) { + slots[i].clear(); + } + currentSlot = 0; buttonDown = 0; buttonUp = 0; } } mAccumulator; + size_t mSlotCount; + bool mUsingSlotsProtocol; + int32_t mButtonState; - void initialize(); + void clearState(); void sync(nsecs_t when); }; diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index f5d7ae8..1ab2a3e 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -613,6 +613,10 @@ private: return false; } + virtual bool hasInputProperty(int32_t deviceId, int property) const { + return false; + } + virtual status_t mapKey(int32_t deviceId, int scancode, int32_t* outKeycode, uint32_t* outFlags) const { Device* device = getDevice(deviceId); |