summaryrefslogtreecommitdiffstats
path: root/libs/ui/InputReader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ui/InputReader.cpp')
-rw-r--r--libs/ui/InputReader.cpp2942
1 files changed, 2048 insertions, 894 deletions
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 30e391f..c5183e4 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -31,10 +31,6 @@
#include <limits.h>
#include <math.h>
-/** Amount that trackball needs to move in order to generate a key event. */
-#define TRACKBALL_MOVEMENT_THRESHOLD 6
-
-
namespace android {
// --- Static Functions ---
@@ -115,17 +111,21 @@ int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
return keyCode;
}
+static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) {
+ return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0;
+}
+
// --- InputReader ---
InputReader::InputReader(const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputDispatcherInterface>& dispatcher) :
- mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher) {
+ mEventHub(eventHub), mPolicy(policy), mDispatcher(dispatcher),
+ mGlobalMetaState(0) {
configureExcludedDevices();
- resetGlobalMetaState();
- resetDisplayProperties();
- updateExportedVirtualKeyState();
+ updateGlobalMetaState();
+ updateInputConfiguration();
}
InputReader::~InputReader() {
@@ -136,12 +136,7 @@ InputReader::~InputReader() {
void InputReader::loopOnce() {
RawEvent rawEvent;
- mEventHub->getEvent(& rawEvent.deviceId, & rawEvent.type, & rawEvent.scanCode,
- & rawEvent.keyCode, & rawEvent.flags, & rawEvent.value, & rawEvent.when);
-
- // Replace the event timestamp so it is in same timebase as java.lang.System.nanoTime()
- // and android.os.SystemClock.uptimeMillis() as expected by the rest of the system.
- rawEvent.when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mEventHub->getEvent(& rawEvent);
#if DEBUG_RAW_EVENTS
LOGD("Input event: device=0x%x type=0x%x scancode=%d keycode=%d value=%d",
@@ -155,621 +150,1371 @@ void InputReader::loopOnce() {
void InputReader::process(const RawEvent* rawEvent) {
switch (rawEvent->type) {
case EventHubInterface::DEVICE_ADDED:
- handleDeviceAdded(rawEvent);
+ addDevice(rawEvent->when, rawEvent->deviceId);
break;
case EventHubInterface::DEVICE_REMOVED:
- handleDeviceRemoved(rawEvent);
+ removeDevice(rawEvent->when, rawEvent->deviceId);
break;
- case EV_SYN:
- handleSync(rawEvent);
+ default:
+ consumeEvent(rawEvent);
break;
+ }
+}
- case EV_KEY:
- handleKey(rawEvent);
- break;
+void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
+ String8 name = mEventHub->getDeviceName(deviceId);
+ uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- case EV_REL:
- handleRelativeMotion(rawEvent);
- break;
+ InputDevice* device = createDevice(deviceId, name, classes);
+ device->configure();
- case EV_ABS:
- handleAbsoluteMotion(rawEvent);
- break;
+ bool added = false;
+ { // acquire device registry writer lock
+ RWLock::AutoWLock _wl(mDeviceRegistryLock);
- case EV_SW:
- handleSwitch(rawEvent);
- break;
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ mDevices.add(deviceId, device);
+ added = true;
+ }
+ } // release device registry writer lock
+
+ if (! added) {
+ LOGW("Ignoring spurious device added event for deviceId %d.", deviceId);
+ delete device;
+ return;
}
+
+ if (device->isIgnored()) {
+ LOGI("Device added: id=0x%x, name=%s (ignored non-input device)",
+ deviceId, name.string());
+ } else {
+ LOGI("Device added: id=0x%x, name=%s, sources=%08x",
+ deviceId, name.string(), device->getSources());
+ }
+
+ handleConfigurationChanged(when);
}
-void InputReader::handleDeviceAdded(const RawEvent* rawEvent) {
- InputDevice* device = getDevice(rawEvent->deviceId);
- if (device) {
- LOGW("Ignoring spurious device added event for deviceId %d.", rawEvent->deviceId);
+void InputReader::removeDevice(nsecs_t when, int32_t deviceId) {
+ bool removed = false;
+ InputDevice* device = NULL;
+ { // acquire device registry writer lock
+ RWLock::AutoWLock _wl(mDeviceRegistryLock);
+
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ device = mDevices.valueAt(deviceIndex);
+ mDevices.removeItemsAt(deviceIndex, 1);
+ removed = true;
+ }
+ } // release device registry writer lock
+
+ if (! removed) {
+ LOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
return;
}
- addDevice(rawEvent->when, rawEvent->deviceId);
+ device->reset();
+
+ if (device->isIgnored()) {
+ LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)",
+ device->getId(), device->getName().string());
+ } else {
+ LOGI("Device removed: id=0x%x, name=%s, sources=%08x",
+ device->getId(), device->getName().string(), device->getSources());
+ }
+
+ delete device;
+
+ handleConfigurationChanged(when);
}
-void InputReader::handleDeviceRemoved(const RawEvent* rawEvent) {
- InputDevice* device = getDevice(rawEvent->deviceId);
- if (! device) {
- LOGW("Ignoring spurious device removed event for deviceId %d.", rawEvent->deviceId);
- return;
+InputDevice* InputReader::createDevice(int32_t deviceId, const String8& name, uint32_t classes) {
+ InputDevice* device = new InputDevice(this, deviceId, name);
+
+ const int32_t associatedDisplayId = 0; // FIXME: hardcoded for current single-display devices
+
+ // Switch-like devices.
+ if (classes & INPUT_DEVICE_CLASS_SWITCH) {
+ device->addMapper(new SwitchInputMapper(device));
}
- removeDevice(rawEvent->when, device);
+ // Keyboard-like devices.
+ uint32_t keyboardSources = 0;
+ int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
+ if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
+ keyboardSources |= AINPUT_SOURCE_KEYBOARD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
+ keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
+ }
+ if (classes & INPUT_DEVICE_CLASS_DPAD) {
+ keyboardSources |= AINPUT_SOURCE_DPAD;
+ }
+ if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
+ keyboardSources |= AINPUT_SOURCE_GAMEPAD;
+ }
+
+ if (keyboardSources != 0) {
+ device->addMapper(new KeyboardInputMapper(device,
+ associatedDisplayId, keyboardSources, keyboardType));
+ }
+
+ // Trackball-like devices.
+ if (classes & INPUT_DEVICE_CLASS_TRACKBALL) {
+ device->addMapper(new TrackballInputMapper(device, associatedDisplayId));
+ }
+
+ // Touchscreen-like devices.
+ if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN_MT) {
+ device->addMapper(new MultiTouchInputMapper(device, associatedDisplayId));
+ } else if (classes & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
+ device->addMapper(new SingleTouchInputMapper(device, associatedDisplayId));
+ }
+
+ return device;
}
-void InputReader::handleSync(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+void InputReader::consumeEvent(const RawEvent* rawEvent) {
+ int32_t deviceId = rawEvent->deviceId;
- if (rawEvent->scanCode == SYN_MT_REPORT) {
- // MultiTouch Sync: The driver has returned all data for *one* of the pointers.
- // We drop pointers with pressure <= 0 since that indicates they are not down.
- if (device->isMultiTouchScreen()) {
- uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
- if (device->multiTouchScreen.accumulator.pointers[pointerIndex].fields) {
- if (pointerIndex == MAX_POINTERS) {
- LOGW("MultiTouch device driver returned more than maximum of %d pointers.",
- MAX_POINTERS);
- } else {
- pointerIndex += 1;
- device->multiTouchScreen.accumulator.pointerCount = pointerIndex;
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ LOGW("Discarding event for unknown deviceId %d.", deviceId);
+ return;
+ }
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (device->isIgnored()) {
+ //LOGD("Discarding event for ignored deviceId %d.", deviceId);
+ return;
+ }
+
+ device->process(rawEvent);
+ } // release device registry reader lock
+}
+
+void InputReader::handleConfigurationChanged(nsecs_t when) {
+ // Reset global meta state because it depends on the list of all configured devices.
+ updateGlobalMetaState();
+
+ // Update input configuration.
+ updateInputConfiguration();
+
+ // Enqueue configuration changed.
+ mDispatcher->notifyConfigurationChanged(when);
+}
+
+void InputReader::configureExcludedDevices() {
+ Vector<String8> excludedDeviceNames;
+ mPolicy->getExcludedDeviceNames(excludedDeviceNames);
+
+ for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
+ mEventHub->addExcludedDevice(excludedDeviceNames[i]);
+ }
+}
+
+void InputReader::updateGlobalMetaState() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ mGlobalMetaState = 0;
+
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ mGlobalMetaState |= device->getMetaState();
+ }
+ } // release device registry reader lock
+ } // release state lock
+}
+
+int32_t InputReader::getGlobalMetaState() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ return mGlobalMetaState;
+ } // release state lock
+}
+
+void InputReader::updateInputConfiguration() {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
+ int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
+ int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ InputDeviceInfo deviceInfo;
+ for (size_t i = 0; i < mDevices.size(); i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ device->getDeviceInfo(& deviceInfo);
+ uint32_t sources = deviceInfo.getSources();
+
+ if ((sources & AINPUT_SOURCE_TOUCHSCREEN) == AINPUT_SOURCE_TOUCHSCREEN) {
+ touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ }
+ if ((sources & AINPUT_SOURCE_TRACKBALL) == AINPUT_SOURCE_TRACKBALL) {
+ navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
+ } else if ((sources & AINPUT_SOURCE_DPAD) == AINPUT_SOURCE_DPAD) {
+ navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+ }
+ if (deviceInfo.getKeyboardType() == AINPUT_KEYBOARD_TYPE_ALPHABETIC) {
+ keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
}
}
+ } // release device registry reader lock
+
+ mInputConfiguration.touchScreen = touchScreenConfig;
+ mInputConfiguration.keyboard = keyboardConfig;
+ mInputConfiguration.navigation = navigationConfig;
+ } // release state lock
+}
+
+void InputReader::getInputConfiguration(InputConfiguration* outConfiguration) {
+ { // acquire state lock
+ AutoMutex _l(mStateLock);
+
+ *outConfiguration = mInputConfiguration;
+ } // release state lock
+}
+
+status_t InputReader::getInputDeviceInfo(int32_t deviceId, InputDeviceInfo* outDeviceInfo) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
- device->multiTouchScreen.accumulator.pointers[pointerIndex].clear();
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex < 0) {
+ return NAME_NOT_FOUND;
}
- } else if (rawEvent->scanCode == SYN_REPORT) {
- // General Sync: The driver has returned all data for the current event update.
- if (device->isMultiTouchScreen()) {
- if (device->multiTouchScreen.accumulator.isDirty()) {
- onMultiTouchScreenStateChanged(rawEvent->when, device);
- device->multiTouchScreen.accumulator.clear();
+
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (device->isIgnored()) {
+ return NAME_NOT_FOUND;
+ }
+
+ device->getDeviceInfo(outDeviceInfo);
+ return OK;
+ } // release device registy reader lock
+}
+
+void InputReader::getInputDeviceIds(Vector<int32_t>& outDeviceIds) {
+ outDeviceIds.clear();
+
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored()) {
+ outDeviceIds.add(device->getId());
}
- } else if (device->isSingleTouchScreen()) {
- if (device->singleTouchScreen.accumulator.isDirty()) {
- onSingleTouchScreenStateChanged(rawEvent->when, device);
- device->singleTouchScreen.accumulator.clear();
+ }
+ } // release device registy reader lock
+}
+
+int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) {
+ return getState(deviceId, sourceMask, keyCode, & InputDevice::getKeyCodeState);
+}
+
+int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) {
+ return getState(deviceId, sourceMask, scanCode, & InputDevice::getScanCodeState);
+}
+
+int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
+ return getState(deviceId, sourceMask, switchCode, & InputDevice::getSwitchState);
+}
+
+int32_t InputReader::getState(int32_t deviceId, uint32_t sourceMask, int32_t code,
+ GetStateFunc getStateFunc) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+
+ int32_t result = AKEY_STATE_UNKNOWN;
+ if (deviceId >= 0) {
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = (device->*getStateFunc)(sourceMask, code);
+ }
+ }
+ } else {
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = (device->*getStateFunc)(sourceMask, code);
+ if (result >= AKEY_STATE_DOWN) {
+ return result;
+ }
+ }
}
}
+ return result;
+ } // release device registy reader lock
+}
+
+bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask,
+ size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) {
+ memset(outFlags, 0, numCodes);
+ return markSupportedKeyCodes(deviceId, sourceMask, numCodes, keyCodes, outFlags);
+}
- if (device->trackball.accumulator.isDirty()) {
- onTrackballStateChanged(rawEvent->when, device);
- device->trackball.accumulator.clear();
+bool InputReader::markSupportedKeyCodes(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ { // acquire device registry reader lock
+ RWLock::AutoRLock _rl(mDeviceRegistryLock);
+ bool result = false;
+ if (deviceId >= 0) {
+ ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
+ if (deviceIndex >= 0) {
+ InputDevice* device = mDevices.valueAt(deviceIndex);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result = device->markSupportedKeyCodes(sourceMask,
+ numCodes, keyCodes, outFlags);
+ }
+ }
+ } else {
+ size_t numDevices = mDevices.size();
+ for (size_t i = 0; i < numDevices; i++) {
+ InputDevice* device = mDevices.valueAt(i);
+ if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
+ result |= device->markSupportedKeyCodes(sourceMask,
+ numCodes, keyCodes, outFlags);
+ }
+ }
}
- }
+ return result;
+ } // release device registy reader lock
}
-void InputReader::handleKey(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
- bool down = rawEvent->value != 0;
- int32_t scanCode = rawEvent->scanCode;
+// --- InputReaderThread ---
- if (device->isSingleTouchScreen()) {
- switch (rawEvent->scanCode) {
- case BTN_TOUCH:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH;
- device->singleTouchScreen.accumulator.btnTouch = down;
- return;
- }
+InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
+ Thread(/*canCallJava*/ true), mReader(reader) {
+}
+
+InputReaderThread::~InputReaderThread() {
+}
+
+bool InputReaderThread::threadLoop() {
+ mReader->loopOnce();
+ return true;
+}
+
+
+// --- InputDevice ---
+
+InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) :
+ mContext(context), mId(id), mName(name), mSources(0) {
+}
+
+InputDevice::~InputDevice() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ delete mMappers[i];
}
+ mMappers.clear();
+}
- if (device->isTrackball()) {
- switch (rawEvent->scanCode) {
- case BTN_MOUSE:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
- device->trackball.accumulator.btnMouse = down;
+void InputDevice::addMapper(InputMapper* mapper) {
+ mMappers.add(mapper);
+}
- // Process the trackball change now since we may not receive a sync immediately.
- onTrackballStateChanged(rawEvent->when, device);
- device->trackball.accumulator.clear();
- return;
- }
+void InputDevice::configure() {
+ mSources = 0;
+
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->configure();
+ mSources |= mapper->getSources();
+ }
+}
+
+void InputDevice::reset() {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->reset();
}
+}
- if (device->isKeyboard()) {
- int32_t keyCode = rawEvent->keyCode;
- onKey(rawEvent->when, device, down, keyCode, scanCode, rawEvent->flags);
+void InputDevice::process(const RawEvent* rawEvent) {
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->process(rawEvent);
}
}
-void InputReader::handleRelativeMotion(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
+ outDeviceInfo->initialize(mId, mName);
- if (device->isTrackball()) {
- switch (rawEvent->scanCode) {
- case REL_X:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_REL_X;
- device->trackball.accumulator.relX = rawEvent->value;
- break;
- case REL_Y:
- device->trackball.accumulator.fields |=
- InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
- device->trackball.accumulator.relY = rawEvent->value;
- break;
- }
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ mapper->populateDeviceInfo(outDeviceInfo);
}
}
-void InputReader::handleAbsoluteMotion(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
+int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState);
+}
- if (device->isMultiTouchScreen()) {
- uint32_t pointerIndex = device->multiTouchScreen.accumulator.pointerCount;
- InputDevice::MultiTouchScreenState::Accumulator::Pointer* pointer =
- & device->multiTouchScreen.accumulator.pointers[pointerIndex];
+int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return getState(sourceMask, scanCode, & InputMapper::getScanCodeState);
+}
- switch (rawEvent->scanCode) {
- case ABS_MT_POSITION_X:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X;
- pointer->absMTPositionX = rawEvent->value;
- break;
- case ABS_MT_POSITION_Y:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y;
- pointer->absMTPositionY = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MAJOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
- pointer->absMTTouchMajor = rawEvent->value;
- break;
- case ABS_MT_TOUCH_MINOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
- pointer->absMTTouchMinor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MAJOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- pointer->absMTWidthMajor = rawEvent->value;
- break;
- case ABS_MT_WIDTH_MINOR:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
- pointer->absMTWidthMinor = rawEvent->value;
- break;
- case ABS_MT_ORIENTATION:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION;
- pointer->absMTOrientation = rawEvent->value;
- break;
- case ABS_MT_TRACKING_ID:
- pointer->fields |=
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TRACKING_ID;
- pointer->absMTTrackingId = rawEvent->value;
- break;
+int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return getState(sourceMask, switchCode, & InputMapper::getSwitchState);
+}
+
+int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
+ int32_t result = AKEY_STATE_UNKNOWN;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
+ result = (mapper->*getStateFunc)(sourceMask, code);
+ if (result >= AKEY_STATE_DOWN) {
+ return result;
+ }
}
- } else if (device->isSingleTouchScreen()) {
- switch (rawEvent->scanCode) {
- case ABS_X:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X;
- device->singleTouchScreen.accumulator.absX = rawEvent->value;
- break;
- case ABS_Y:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y;
- device->singleTouchScreen.accumulator.absY = rawEvent->value;
- break;
- case ABS_PRESSURE:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE;
- device->singleTouchScreen.accumulator.absPressure = rawEvent->value;
- break;
- case ABS_TOOL_WIDTH:
- device->singleTouchScreen.accumulator.fields |=
- InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH;
- device->singleTouchScreen.accumulator.absToolWidth = rawEvent->value;
- break;
+ }
+ return result;
+}
+
+bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ bool result = false;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
+ result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
}
}
+ return result;
+}
+
+int32_t InputDevice::getMetaState() {
+ int32_t result = 0;
+ size_t numMappers = mMappers.size();
+ for (size_t i = 0; i < numMappers; i++) {
+ InputMapper* mapper = mMappers[i];
+ result |= mapper->getMetaState();
+ }
+ return result;
+}
+
+
+// --- InputMapper ---
+
+InputMapper::InputMapper(InputDevice* device) :
+ mDevice(device), mContext(device->getContext()) {
+}
+
+InputMapper::~InputMapper() {
+}
+
+void InputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ info->addSource(getSources());
+}
+
+void InputMapper::configure() {
+}
+
+void InputMapper::reset() {
+}
+
+int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return AKEY_STATE_UNKNOWN;
+}
+
+bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ return false;
+}
+
+int32_t InputMapper::getMetaState() {
+ return 0;
+}
+
+bool InputMapper::applyStandardPolicyActions(nsecs_t when, int32_t policyActions) {
+ if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
+ getDispatcher()->notifyAppSwitchComing(when);
+ }
+
+ return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
}
-void InputReader::handleSwitch(const RawEvent* rawEvent) {
- InputDevice* device = getNonIgnoredDevice(rawEvent->deviceId);
- if (! device) return;
- onSwitch(rawEvent->when, device, rawEvent->scanCode, rawEvent->value);
+// --- SwitchInputMapper ---
+
+SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
+ InputMapper(device) {
}
-void InputReader::onKey(nsecs_t when, InputDevice* device,
- bool down, int32_t keyCode, int32_t scanCode, uint32_t policyFlags) {
- /* Refresh display properties so we can rotate key codes according to display orientation */
+SwitchInputMapper::~SwitchInputMapper() {
+}
- if (! refreshDisplayProperties()) {
- return;
+uint32_t SwitchInputMapper::getSources() {
+ return 0;
+}
+
+void SwitchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_SW:
+ processSwitch(rawEvent->when, rawEvent->scanCode, rawEvent->value);
+ break;
}
+}
- /* Update device state */
+void SwitchInputMapper::processSwitch(nsecs_t when, int32_t switchCode, int32_t switchValue) {
+ uint32_t policyFlags = 0;
+ int32_t policyActions = getPolicy()->interceptSwitch(
+ when, switchCode, switchValue, policyFlags);
- int32_t oldMetaState = device->keyboard.current.metaState;
- int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
- if (oldMetaState != newMetaState) {
- device->keyboard.current.metaState = newMetaState;
- resetGlobalMetaState();
+ applyStandardPolicyActions(when, policyActions);
+}
+
+int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
+ return getEventHub()->getSwitchState(getDeviceId(), switchCode);
+}
+
+
+// --- KeyboardInputMapper ---
+
+KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, int32_t associatedDisplayId,
+ uint32_t sources, int32_t keyboardType) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
+ mKeyboardType(keyboardType) {
+ initialize();
+}
+
+KeyboardInputMapper::~KeyboardInputMapper() {
+}
+
+void KeyboardInputMapper::initialize() {
+ mMetaState = AMETA_NONE;
+ mDownTime = 0;
+}
+
+uint32_t KeyboardInputMapper::getSources() {
+ return mSources;
+}
+
+void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ info->setKeyboardType(mKeyboardType);
+}
+
+void KeyboardInputMapper::reset() {
+ // Synthesize key up event on reset if keys are currently down.
+ while (! mKeyDowns.isEmpty()) {
+ const KeyDown& keyDown = mKeyDowns.top();
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0);
+ }
+
+ InputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+ getContext()->updateGlobalMetaState();
+}
+
+void KeyboardInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY: {
+ int32_t scanCode = rawEvent->scanCode;
+ if (isKeyboardOrGamepadKey(scanCode)) {
+ processKey(rawEvent->when, rawEvent->value != 0, rawEvent->keyCode, scanCode,
+ rawEvent->flags);
+ }
+ break;
+ }
}
+}
- // FIXME if we send a down event about a rotated key press we should ensure that we send
- // a corresponding up event about the rotated key press even if the orientation
- // has changed in the meantime
- keyCode = rotateKeyCode(keyCode, mDisplayOrientation);
+bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
+ return scanCode < BTN_MOUSE
+ || scanCode >= KEY_OK
+ || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI);
+}
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
+ uint32_t policyFlags) {
if (down) {
- device->keyboard.current.downTime = when;
+ // Rotate key codes according to orientation.
+ if (mAssociatedDisplayId >= 0) {
+ int32_t orientation;
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ return;
+ }
+
+ keyCode = rotateKeyCode(keyCode, orientation);
+ }
+
+ // Add key down.
+ ssize_t keyDownIndex = findKeyDown(scanCode);
+ if (keyDownIndex >= 0) {
+ // key repeat, be sure to use same keycode as before in case of rotation
+ keyCode = mKeyDowns.top().keyCode;
+ } else {
+ // key down
+ mKeyDowns.push();
+ KeyDown& keyDown = mKeyDowns.editTop();
+ keyDown.keyCode = keyCode;
+ keyDown.scanCode = scanCode;
+ }
+ } else {
+ // Remove key down.
+ ssize_t keyDownIndex = findKeyDown(scanCode);
+ if (keyDownIndex >= 0) {
+ // key up, be sure to use same keycode as before in case of rotation
+ keyCode = mKeyDowns.top().keyCode;
+ mKeyDowns.removeAt(size_t(keyDownIndex));
+ } else {
+ // key was not actually down
+ LOGI("Dropping key up from device %s because the key was not down. "
+ "keyCode=%d, scanCode=%d",
+ getDeviceName().string(), keyCode, scanCode);
+ return;
+ }
}
- /* Apply policy */
+ int32_t oldMetaState = mMetaState;
+ int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
+ if (oldMetaState != newMetaState) {
+ mMetaState = newMetaState;
+ getContext()->updateGlobalMetaState();
+ }
- int32_t policyActions = mPolicy->interceptKey(when, device->id,
- down, keyCode, scanCode, policyFlags);
+ /* Apply policy. */
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
+ int32_t policyActions = getPolicy()->interceptKey(when,
+ getDeviceId(), down, keyCode, scanCode, policyFlags);
+
+ if (! applyStandardPolicyActions(when, policyActions)) {
return; // event dropped
}
- /* Enqueue key event for dispatch */
+ /* Enqueue key event for dispatch. */
int32_t keyEventAction;
if (down) {
- device->keyboard.current.downTime = when;
+ mDownTime = when;
keyEventAction = AKEY_EVENT_ACTION_DOWN;
} else {
keyEventAction = AKEY_EVENT_ACTION_UP;
}
int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
- if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
+ if (policyFlags & POLICY_FLAG_WOKE_HERE) {
keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
}
- mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode,
- device->keyboard.current.metaState,
- device->keyboard.current.downTime);
+ mMetaState, mDownTime);
}
-void InputReader::onSwitch(nsecs_t when, InputDevice* device, int32_t switchCode,
- int32_t switchValue) {
- int32_t policyActions = mPolicy->interceptSwitch(when, switchCode, switchValue);
+ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
+ size_t n = mKeyDowns.size();
+ for (size_t i = 0; i < n; i++) {
+ if (mKeyDowns[i].scanCode == scanCode) {
+ return i;
+ }
+ }
+ return -1;
+}
- uint32_t policyFlags = 0;
- applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags);
+int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
}
-void InputReader::onMultiTouchScreenStateChanged(nsecs_t when,
- InputDevice* device) {
- static const uint32_t REQUIRED_FIELDS =
- InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_X
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_POSITION_Y
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
- | InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
+int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
+}
- /* Refresh display properties so we can map touch screen coords into display coords */
+bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
+}
- if (! refreshDisplayProperties()) {
- return;
+int32_t KeyboardInputMapper::getMetaState() {
+ return mMetaState;
+}
+
+
+// --- TrackballInputMapper ---
+
+TrackballInputMapper::TrackballInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+ mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
+ mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
+ mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+ mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+
+ initialize();
+}
+
+TrackballInputMapper::~TrackballInputMapper() {
+}
+
+uint32_t TrackballInputMapper::getSources() {
+ return AINPUT_SOURCE_TRACKBALL;
+}
+
+void TrackballInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ info->addMotionRange(AINPUT_MOTION_RANGE_X, -1.0f, 1.0f, 0.0f, mXScale);
+ info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
+}
+
+void TrackballInputMapper::initialize() {
+ mAccumulator.clear();
+
+ mDown = false;
+ mDownTime = 0;
+}
+
+void TrackballInputMapper::reset() {
+ // Synthesize trackball button up event on reset if trackball button is currently down.
+ if (mDown) {
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+ mAccumulator.btnMouse = false;
+ sync(when);
}
- /* Update device state */
+ InputMapper::reset();
- InputDevice::MultiTouchScreenState* in = & device->multiTouchScreen;
- InputDevice::TouchData* out = & device->touchScreen.currentTouch;
+ // Reinitialize.
+ initialize();
+}
- uint32_t inCount = in->accumulator.pointerCount;
- uint32_t outCount = 0;
- bool havePointerIds = true;
+void TrackballInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY:
+ switch (rawEvent->scanCode) {
+ case BTN_MOUSE:
+ mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+ mAccumulator.btnMouse = rawEvent->value != 0;
- out->clear();
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ break;
+ }
+ break;
- for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
- uint32_t fields = in->accumulator.pointers[inIndex].fields;
+ case EV_REL:
+ switch (rawEvent->scanCode) {
+ case REL_X:
+ mAccumulator.fields |= Accumulator::FIELD_REL_X;
+ mAccumulator.relX = rawEvent->value;
+ break;
+ case REL_Y:
+ mAccumulator.fields |= Accumulator::FIELD_REL_Y;
+ mAccumulator.relY = rawEvent->value;
+ break;
+ }
+ break;
- if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
-#if DEBUG_POINTERS
- LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
- inIndex, fields);
- continue;
-#endif
+ case EV_SYN:
+ switch (rawEvent->scanCode) {
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ }
+ break;
}
+ break;
+ }
+}
- if (in->accumulator.pointers[inIndex].absMTTouchMajor <= 0) {
- // Pointer is not down. Drop it.
- continue;
+void TrackballInputMapper::sync(nsecs_t when) {
+ /* Get display properties so for rotation based on display orientation. */
+
+ int32_t orientation;
+ if (mAssociatedDisplayId >= 0) {
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+ return;
}
+ } else {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
+ }
- out->pointers[outCount].x = in->accumulator.pointers[inIndex].absMTPositionX;
- out->pointers[outCount].y = in->accumulator.pointers[inIndex].absMTPositionY;
+ /* Update saved trackball state */
- out->pointers[outCount].touchMajor = in->accumulator.pointers[inIndex].absMTTouchMajor;
- out->pointers[outCount].touchMinor = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
- ? in->accumulator.pointers[inIndex].absMTTouchMinor
- : in->accumulator.pointers[inIndex].absMTTouchMajor;
+ uint32_t fields = mAccumulator.fields;
+ bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
- out->pointers[outCount].toolMajor = in->accumulator.pointers[inIndex].absMTWidthMajor;
- out->pointers[outCount].toolMinor = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
- ? in->accumulator.pointers[inIndex].absMTWidthMinor
- : in->accumulator.pointers[inIndex].absMTWidthMajor;
+ if (downChanged) {
+ if (mAccumulator.btnMouse) {
+ mDown = true;
+ mDownTime = when;
+ } else {
+ mDown = false;
+ }
+ }
- out->pointers[outCount].orientation = (fields
- & InputDevice::MultiTouchScreenState::Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
- ? in->accumulator.pointers[inIndex].absMTOrientation : 0;
+ /* Apply policy */
- // Derive an approximation of pressure and size.
- // FIXME assignment of pressure may be incorrect, probably better to let
- // pressure = touch / width. Later on we pass width to MotionEvent as a size, which
- // isn't quite right either. Should be using touch for that.
- out->pointers[outCount].pressure = in->accumulator.pointers[inIndex].absMTTouchMajor;
- out->pointers[outCount].size = in->accumulator.pointers[inIndex].absMTWidthMajor;
+ uint32_t policyFlags = 0;
+ int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
- if (havePointerIds) {
- if (fields & InputDevice::MultiTouchScreenState::Accumulator::
- FIELD_ABS_MT_TRACKING_ID) {
- uint32_t id = uint32_t(in->accumulator.pointers[inIndex].absMTTrackingId);
+ if (! applyStandardPolicyActions(when, policyActions)) {
+ return; // event dropped
+ }
- if (id > MAX_POINTER_ID) {
-#if DEBUG_POINTERS
- LOGD("Pointers: Ignoring driver provided pointer id %d because "
- "it is larger than max supported id %d for optimizations",
- id, MAX_POINTER_ID);
-#endif
- havePointerIds = false;
- }
- else {
- out->pointers[outCount].id = id;
- out->idToIndex[id] = outCount;
- out->idBits.markBit(id);
- }
- } else {
- havePointerIds = false;
- }
- }
+ /* Enqueue motion event for dispatch. */
- outCount += 1;
+ int32_t motionEventAction;
+ if (downChanged) {
+ motionEventAction = mDown ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
+ } else {
+ motionEventAction = AMOTION_EVENT_ACTION_MOVE;
+ }
+
+ int32_t pointerId = 0;
+ PointerCoords pointerCoords;
+ pointerCoords.x = fields & Accumulator::FIELD_REL_X
+ ? mAccumulator.relX * mXScale : 0;
+ pointerCoords.y = fields & Accumulator::FIELD_REL_Y
+ ? mAccumulator.relY * mYScale : 0;
+ pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
+ pointerCoords.size = 0;
+ pointerCoords.touchMajor = 0;
+ pointerCoords.touchMinor = 0;
+ pointerCoords.toolMajor = 0;
+ pointerCoords.toolMinor = 0;
+ pointerCoords.orientation = 0;
+
+ float temp;
+ switch (orientation) {
+ case InputReaderPolicyInterface::ROTATION_90:
+ temp = pointerCoords.x;
+ pointerCoords.x = pointerCoords.y;
+ pointerCoords.y = - temp;
+ break;
+
+ case InputReaderPolicyInterface::ROTATION_180:
+ pointerCoords.x = - pointerCoords.x;
+ pointerCoords.y = - pointerCoords.y;
+ break;
+
+ case InputReaderPolicyInterface::ROTATION_270:
+ temp = pointerCoords.x;
+ pointerCoords.x = - pointerCoords.y;
+ pointerCoords.y = temp;
+ break;
}
- out->pointerCount = outCount;
+ int32_t metaState = mContext->getGlobalMetaState();
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
+ motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
+ 1, & pointerId, & pointerCoords, mXPrecision, mYPrecision, mDownTime);
+}
+
- onTouchScreenChanged(when, device, havePointerIds);
+// --- TouchInputMapper ---
+
+TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ InputMapper(device), mAssociatedDisplayId(associatedDisplayId),
+ mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) {
+ initialize();
}
-void InputReader::onSingleTouchScreenStateChanged(nsecs_t when,
- InputDevice* device) {
- /* Refresh display properties so we can map touch screen coords into display coords */
+TouchInputMapper::~TouchInputMapper() {
+}
- if (! refreshDisplayProperties()) {
- return;
+uint32_t TouchInputMapper::getSources() {
+ return mAssociatedDisplayId >= 0 ? AINPUT_SOURCE_TOUCHSCREEN : AINPUT_SOURCE_TOUCHPAD;
+}
+
+void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
+ InputMapper::populateDeviceInfo(info);
+
+ // FIXME: Should ensure the surface information is up to date so that orientation changes
+ // are noticed immediately. Unfortunately we will need to add some extra locks here
+ // to prevent race conditions.
+ // configureSurface();
+
+ info->addMotionRange(AINPUT_MOTION_RANGE_X, mOrientedRanges.x);
+ info->addMotionRange(AINPUT_MOTION_RANGE_Y, mOrientedRanges.y);
+ info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mOrientedRanges.pressure);
+ info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mOrientedRanges.size);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mOrientedRanges.touchMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mOrientedRanges.touchMinor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mOrientedRanges.toolMajor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mOrientedRanges.toolMinor);
+ info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mOrientedRanges.orientation);
+}
+
+void TouchInputMapper::initialize() {
+ mLastTouch.clear();
+ mDownTime = 0;
+ mCurrentVirtualKey.down = false;
+
+ for (uint32_t i = 0; i < MAX_POINTERS; i++) {
+ mAveragingTouchFilter.historyStart[i] = 0;
+ mAveragingTouchFilter.historyEnd[i] = 0;
}
- /* Update device state */
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
+}
- InputDevice::SingleTouchScreenState* in = & device->singleTouchScreen;
- InputDevice::TouchData* out = & device->touchScreen.currentTouch;
+void TouchInputMapper::configure() {
+ InputMapper::configure();
- uint32_t fields = in->accumulator.fields;
+ // Configure basic parameters.
+ mParameters.useBadTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useAveragingTouchFilter = getPolicy()->filterTouchEvents();
+ mParameters.useJumpyTouchFilter = getPolicy()->filterJumpyTouchEvents();
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_BTN_TOUCH) {
- in->current.down = in->accumulator.btnTouch;
+ // Configure absolute axis information.
+ configureAxes();
+
+ // Configure pressure factors.
+ if (mAxes.pressure.valid) {
+ mPressureOrigin = mAxes.pressure.minValue;
+ mPressureScale = 1.0f / mAxes.pressure.getRange();
+ } else {
+ mPressureOrigin = 0;
+ mPressureScale = 1.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_X) {
- in->current.x = in->accumulator.absX;
+ mOrientedRanges.pressure.min = 0.0f;
+ mOrientedRanges.pressure.max = 1.0f;
+ mOrientedRanges.pressure.flat = 0.0f;
+ mOrientedRanges.pressure.fuzz = mPressureScale;
+
+ // Configure size factors.
+ if (mAxes.size.valid) {
+ mSizeOrigin = mAxes.size.minValue;
+ mSizeScale = 1.0f / mAxes.size.getRange();
+ } else {
+ mSizeOrigin = 0;
+ mSizeScale = 1.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_Y) {
- in->current.y = in->accumulator.absY;
+ mOrientedRanges.size.min = 0.0f;
+ mOrientedRanges.size.max = 1.0f;
+ mOrientedRanges.size.flat = 0.0f;
+ mOrientedRanges.size.fuzz = mSizeScale;
+
+ // Configure orientation factors.
+ if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
+ mOrientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
+ } else {
+ mOrientationScale = 0.0f;
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_PRESSURE) {
- in->current.pressure = in->accumulator.absPressure;
+ mOrientedRanges.orientation.min = - M_PI_2;
+ mOrientedRanges.orientation.max = M_PI_2;
+ mOrientedRanges.orientation.flat = 0;
+ mOrientedRanges.orientation.fuzz = mOrientationScale;
+
+ // Configure surface dimensions and orientation.
+ configureSurface();
+}
+
+void TouchInputMapper::configureAxes() {
+ mAxes.x.valid = false;
+ mAxes.y.valid = false;
+ mAxes.pressure.valid = false;
+ mAxes.size.valid = false;
+ mAxes.touchMajor.valid = false;
+ mAxes.touchMinor.valid = false;
+ mAxes.toolMajor.valid = false;
+ mAxes.toolMinor.valid = false;
+ mAxes.orientation.valid = false;
+}
+
+bool TouchInputMapper::configureSurface() {
+ // Update orientation and dimensions if needed.
+ int32_t orientation;
+ int32_t width, height;
+ if (mAssociatedDisplayId >= 0) {
+ if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
+ return false;
+ }
+ } else {
+ orientation = InputReaderPolicyInterface::ROTATION_0;
+ width = mAxes.x.getRange();
+ height = mAxes.y.getRange();
}
- if (fields & InputDevice::SingleTouchScreenState::Accumulator::FIELD_ABS_TOOL_WIDTH) {
- in->current.size = in->accumulator.absToolWidth;
+ bool orientationChanged = mSurfaceOrientation != orientation;
+ if (orientationChanged) {
+ mSurfaceOrientation = orientation;
}
- out->clear();
+ bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
+ if (sizeChanged) {
+ mSurfaceWidth = width;
+ mSurfaceHeight = height;
+
+ // Compute size-dependent translation and scaling factors and place virtual keys.
+ if (mAxes.x.valid && mAxes.y.valid) {
+ mXOrigin = mAxes.x.minValue;
+ mYOrigin = mAxes.y.minValue;
+
+ LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
+ getDeviceId(), getDeviceName().string());
+
+ mXScale = float(width) / mAxes.x.getRange();
+ mYScale = float(height) / mAxes.y.getRange();
+ mXPrecision = 1.0f / mXScale;
+ mYPrecision = 1.0f / mYScale;
+
+ configureVirtualKeys();
+ } else {
+ mXOrigin = 0;
+ mYOrigin = 0;
+ mXScale = 1.0f;
+ mYScale = 1.0f;
+ mXPrecision = 1.0f;
+ mYPrecision = 1.0f;
+ }
+
+ // Configure touch and tool area ranges.
+ float diagonal = sqrt(float(width * width + height * height));
+ float diagonalFuzz = sqrt(mXScale * mXScale + mYScale * mYScale);
+
+ mOrientedRanges.touchMajor.min = 0.0f;
+ mOrientedRanges.touchMajor.max = diagonal;
+ mOrientedRanges.touchMajor.flat = 0.0f;
+ mOrientedRanges.touchMajor.fuzz = diagonalFuzz;
+ mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
+
+ mOrientedRanges.toolMinor = mOrientedRanges.toolMajor = mOrientedRanges.touchMajor;
+ }
+
+ if (orientationChanged || sizeChanged) {
+ // Compute oriented surface dimensions, precision, and scales.
+ float orientedXScale, orientedYScale;
+ switch (mSurfaceOrientation) {
+ case InputReaderPolicyInterface::ROTATION_90:
+ case InputReaderPolicyInterface::ROTATION_270:
+ mOrientedSurfaceWidth = mSurfaceHeight;
+ mOrientedSurfaceHeight = mSurfaceWidth;
+ mOrientedXPrecision = mYPrecision;
+ mOrientedYPrecision = mXPrecision;
+ orientedXScale = mYScale;
+ orientedYScale = mXScale;
+ break;
+ default:
+ mOrientedSurfaceWidth = mSurfaceWidth;
+ mOrientedSurfaceHeight = mSurfaceHeight;
+ mOrientedXPrecision = mXPrecision;
+ mOrientedYPrecision = mYPrecision;
+ orientedXScale = mXScale;
+ orientedYScale = mYScale;
+ break;
+ }
+
+ // Configure position ranges.
+ mOrientedRanges.x.min = 0;
+ mOrientedRanges.x.max = mOrientedSurfaceWidth;
+ mOrientedRanges.x.flat = 0;
+ mOrientedRanges.x.fuzz = orientedXScale;
- if (in->current.down) {
- out->pointerCount = 1;
- out->pointers[0].id = 0;
- out->pointers[0].x = in->current.x;
- out->pointers[0].y = in->current.y;
- out->pointers[0].pressure = in->current.pressure;
- out->pointers[0].size = in->current.size;
- out->pointers[0].touchMajor = in->current.pressure;
- out->pointers[0].touchMinor = in->current.pressure;
- out->pointers[0].toolMajor = in->current.size;
- out->pointers[0].toolMinor = in->current.size;
- out->pointers[0].orientation = 0;
- out->idToIndex[0] = 0;
- out->idBits.markBit(0);
+ mOrientedRanges.y.min = 0;
+ mOrientedRanges.y.max = mOrientedSurfaceHeight;
+ mOrientedRanges.y.flat = 0;
+ mOrientedRanges.y.fuzz = orientedYScale;
}
- onTouchScreenChanged(when, device, true);
+ return true;
}
-void InputReader::onTouchScreenChanged(nsecs_t when,
- InputDevice* device, bool havePointerIds) {
- /* Apply policy */
+void TouchInputMapper::configureVirtualKeys() {
+ assert(mAxes.x.valid && mAxes.y.valid);
+
+ Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
+ getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
+
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
+
+ mVirtualKeys.clear();
+
+ if (virtualKeyDefinitions.size() == 0) {
+ return;
+ }
+
+ mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
+
+ int32_t touchScreenLeft = mAxes.x.minValue;
+ int32_t touchScreenTop = mAxes.y.minValue;
+ int32_t touchScreenWidth = mAxes.x.getRange();
+ int32_t touchScreenHeight = mAxes.y.getRange();
- int32_t policyActions = mPolicy->interceptTouch(when);
+ for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
+ const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+ virtualKeyDefinitions[i];
+
+ mVirtualKeys.add();
+ VirtualKey& virtualKey = mVirtualKeys.editTop();
+
+ virtualKey.scanCode = virtualKeyDefinition.scanCode;
+ int32_t keyCode;
+ uint32_t flags;
+ if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
+ & keyCode, & flags)) {
+ LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+ mVirtualKeys.pop(); // drop the key
+ continue;
+ }
+
+ virtualKey.keyCode = keyCode;
+ virtualKey.flags = flags;
+
+ // convert the key definition's display coordinates into touch coordinates for a hit box
+ int32_t halfWidth = virtualKeyDefinition.width / 2;
+ int32_t halfHeight = virtualKeyDefinition.height / 2;
+
+ virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
+ * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
+ virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
+ * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
+ virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
+ * touchScreenHeight / mSurfaceHeight + touchScreenTop;
+ virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
+ * touchScreenHeight / mSurfaceHeight + touchScreenTop;
+
+ LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
+ virtualKey.scanCode, virtualKey.keyCode,
+ virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+ }
+ } // release virtual key lock
+}
+
+void TouchInputMapper::reset() {
+ // Synthesize touch up event if touch is currently down.
+ // This will also take care of finishing virtual key processing if needed.
+ if (mLastTouch.pointerCount != 0) {
+ nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
+ mCurrentTouch.clear();
+ syncTouch(when, true);
+ }
+
+ InputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+}
+
+void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
+ /* Refresh associated display information and update our size configuration if needed. */
+
+ if (! configureSurface()) {
+ return;
+ }
+
+ /* Apply policy */
uint32_t policyFlags = 0;
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- device->touchScreen.lastTouch.clear();
+ int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
+
+ if (! applyStandardPolicyActions(when, policyActions)) {
+ mLastTouch.clear();
return; // event dropped
}
/* Preprocess pointer data */
- if (device->touchScreen.parameters.useBadTouchFilter) {
- if (device->touchScreen.applyBadTouchFilter()) {
+ if (mParameters.useBadTouchFilter) {
+ if (applyBadTouchFilter()) {
havePointerIds = false;
}
}
- if (device->touchScreen.parameters.useJumpyTouchFilter) {
- if (device->touchScreen.applyJumpyTouchFilter()) {
+ if (mParameters.useJumpyTouchFilter) {
+ if (applyJumpyTouchFilter()) {
havePointerIds = false;
}
}
if (! havePointerIds) {
- device->touchScreen.calculatePointerIds();
+ calculatePointerIds();
}
- InputDevice::TouchData temp;
- InputDevice::TouchData* savedTouch;
- if (device->touchScreen.parameters.useAveragingTouchFilter) {
- temp.copyFrom(device->touchScreen.currentTouch);
+ TouchData temp;
+ TouchData* savedTouch;
+ if (mParameters.useAveragingTouchFilter) {
+ temp.copyFrom(mCurrentTouch);
savedTouch = & temp;
- device->touchScreen.applyAveragingTouchFilter();
+ applyAveragingTouchFilter();
} else {
- savedTouch = & device->touchScreen.currentTouch;
+ savedTouch = & mCurrentTouch;
}
- /* Process virtual keys or touches */
+ /* Process touches and virtual keys */
- if (! consumeVirtualKeyTouches(when, device, policyFlags)) {
- dispatchTouches(when, device, policyFlags);
+ TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
+ if (touchResult == DISPATCH_TOUCH) {
+ dispatchTouches(when, policyFlags);
}
- // Copy current touch to last touch in preparation for the next cycle.
- device->touchScreen.lastTouch.copyFrom(*savedTouch);
+ /* Copy current touch to last touch in preparation for the next cycle. */
+
+ if (touchResult == DROP_STROKE) {
+ mLastTouch.clear();
+ } else {
+ mLastTouch.copyFrom(*savedTouch);
+ }
}
-bool InputReader::consumeVirtualKeyTouches(nsecs_t when,
- InputDevice* device, uint32_t policyFlags) {
- switch (device->touchScreen.currentVirtualKey.status) {
- case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED:
- if (device->touchScreen.currentTouch.pointerCount == 0) {
- // Pointer went up after virtual key canceled.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
- }
- return true; // consumed
+TouchInputMapper::TouchResult TouchInputMapper::consumeOffScreenTouches(
+ nsecs_t when, uint32_t policyFlags) {
+ int32_t keyEventAction, keyEventFlags;
+ int32_t keyCode, scanCode, downTime;
+ TouchResult touchResult;
+
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- case InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN:
- if (device->touchScreen.currentTouch.pointerCount == 0) {
- // Pointer went up while virtual key was down.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_UP;
+ if (mCurrentVirtualKey.down) {
+ if (mCurrentTouch.pointerCount == 0) {
+ // Pointer went up while virtual key was down.
+ mCurrentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
- return true; // consumed
- }
+ keyEventAction = AKEY_EVENT_ACTION_UP;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ touchResult = SKIP_TOUCH;
+ goto DispatchVirtualKey;
+ }
- if (device->touchScreen.currentTouch.pointerCount == 1) {
- const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
- if (virtualKey
- && virtualKey->keyCode == device->touchScreen.currentVirtualKey.keyCode) {
- // Pointer is still within the space of the virtual key.
- return true; // consumed
+ if (mCurrentTouch.pointerCount == 1) {
+ int32_t x = mCurrentTouch.pointers[0].x;
+ int32_t y = mCurrentTouch.pointers[0].y;
+ const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+ if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
+ // Pointer is still within the space of the virtual key.
+ return SKIP_TOUCH;
+ }
}
- }
- // Pointer left virtual key area or another pointer also went down.
- // Send key cancellation.
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_CANCELED;
+ // Pointer left virtual key area or another pointer also went down.
+ // Send key cancellation and drop the stroke so subsequent motions will be
+ // considered fresh downs. This is useful when the user swipes away from the
+ // virtual key area into the main display surface.
+ mCurrentVirtualKey.down = false;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
- | AKEY_EVENT_FLAG_CANCELED);
- return true; // consumed
-
- default:
- if (device->touchScreen.currentTouch.pointerCount == 1
- && device->touchScreen.lastTouch.pointerCount == 0) {
- // Pointer just went down. Check for virtual key hit.
- const InputDevice::VirtualKey* virtualKey = device->touchScreen.findVirtualKeyHit();
- if (virtualKey) {
- device->touchScreen.currentVirtualKey.status =
- InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN;
- device->touchScreen.currentVirtualKey.downTime = when;
- device->touchScreen.currentVirtualKey.keyCode = virtualKey->keyCode;
- device->touchScreen.currentVirtualKey.scanCode = virtualKey->scanCode;
+ keyEventAction = AKEY_EVENT_ACTION_UP;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY
+ | AKEY_EVENT_FLAG_CANCELED;
+ touchResult = DROP_STROKE;
+ goto DispatchVirtualKey;
+ } else {
+ if (mCurrentTouch.pointerCount >= 1 && mLastTouch.pointerCount == 0) {
+ // Pointer just went down. Handle off-screen touches, if needed.
+ int32_t x = mCurrentTouch.pointers[0].x;
+ int32_t y = mCurrentTouch.pointers[0].y;
+ if (! isPointInsideSurface(x, y)) {
+ // If exactly one pointer went down, check for virtual key hit.
+ // Otherwise we will drop the entire stroke.
+ if (mCurrentTouch.pointerCount == 1) {
+ const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+ if (virtualKey) {
+ mCurrentVirtualKey.down = true;
+ mCurrentVirtualKey.downTime = when;
+ mCurrentVirtualKey.keyCode = virtualKey->keyCode;
+ mCurrentVirtualKey.scanCode = virtualKey->scanCode;
#if DEBUG_VIRTUAL_KEYS
- LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
- device->touchScreen.currentVirtualKey.keyCode,
- device->touchScreen.currentVirtualKey.scanCode);
+ LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
+ mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
#endif
- dispatchVirtualKey(when, device, policyFlags, AKEY_EVENT_ACTION_DOWN,
- AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY);
- return true; // consumed
+ keyEventAction = AKEY_EVENT_ACTION_DOWN;
+ keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM
+ | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
+ touchResult = SKIP_TOUCH;
+ goto DispatchVirtualKey;
+ }
+ }
+ return DROP_STROKE;
+ }
}
+ return DISPATCH_TOUCH;
}
- return false; // not consumed
- }
-}
-void InputReader::dispatchVirtualKey(nsecs_t when,
- InputDevice* device, uint32_t policyFlags,
- int32_t keyEventAction, int32_t keyEventFlags) {
- updateExportedVirtualKeyState();
+ DispatchVirtualKey:
+ // Collect remaining state needed to dispatch virtual key.
+ keyCode = mCurrentVirtualKey.keyCode;
+ scanCode = mCurrentVirtualKey.scanCode;
+ downTime = mCurrentVirtualKey.downTime;
+ } // release virtual key lock
- int32_t keyCode = device->touchScreen.currentVirtualKey.keyCode;
- int32_t scanCode = device->touchScreen.currentVirtualKey.scanCode;
- nsecs_t downTime = device->touchScreen.currentVirtualKey.downTime;
- int32_t metaState = globalMetaState();
+ // Dispatch virtual key.
+ int32_t metaState = mContext->getGlobalMetaState();
if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
- mPolicy->virtualKeyDownFeedback();
+ getPolicy()->virtualKeyDownFeedback();
}
- int32_t policyActions = mPolicy->interceptKey(when, device->id,
+ int32_t policyActions = getPolicy()->interceptKey(when, getDeviceId(),
keyEventAction == AKEY_EVENT_ACTION_DOWN, keyCode, scanCode, policyFlags);
- if (applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- mDispatcher->notifyKey(when, device->id, AINPUT_SOURCE_KEYBOARD, policyFlags,
+ if (applyStandardPolicyActions(when, policyActions)) {
+ getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
}
+ return touchResult;
}
-void InputReader::dispatchTouches(nsecs_t when,
- InputDevice* device, uint32_t policyFlags) {
- uint32_t currentPointerCount = device->touchScreen.currentTouch.pointerCount;
- uint32_t lastPointerCount = device->touchScreen.lastTouch.pointerCount;
+void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
+ uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+ uint32_t lastPointerCount = mLastTouch.pointerCount;
if (currentPointerCount == 0 && lastPointerCount == 0) {
return; // nothing to do!
}
- BitSet32 currentIdBits = device->touchScreen.currentTouch.idBits;
- BitSet32 lastIdBits = device->touchScreen.lastTouch.idBits;
+ BitSet32 currentIdBits = mCurrentTouch.idBits;
+ BitSet32 lastIdBits = mLastTouch.idBits;
if (currentIdBits == lastIdBits) {
// No pointer id changes so this is a move event.
// The dispatcher takes care of batching moves so we don't have to deal with that here.
int32_t motionEventAction = AMOTION_EVENT_ACTION_MOVE;
- dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
+ dispatchTouch(when, policyFlags, & mCurrentTouch,
currentIdBits, -1, motionEventAction);
} else {
// There may be pointers going up and pointers going down at the same time when pointer
@@ -791,7 +1536,7 @@ void InputReader::dispatchTouches(nsecs_t when,
motionEventAction = AMOTION_EVENT_ACTION_POINTER_UP;
}
- dispatchTouch(when, device, policyFlags, & device->touchScreen.lastTouch,
+ dispatchTouch(when, policyFlags, & mLastTouch,
oldActiveIdBits, upId, motionEventAction);
}
@@ -804,40 +1549,24 @@ void InputReader::dispatchTouches(nsecs_t when,
int32_t motionEventAction;
if (oldActiveIdBits.isEmpty()) {
motionEventAction = AMOTION_EVENT_ACTION_DOWN;
- device->touchScreen.downTime = when;
+ mDownTime = when;
} else {
motionEventAction = AMOTION_EVENT_ACTION_POINTER_DOWN;
}
- dispatchTouch(when, device, policyFlags, & device->touchScreen.currentTouch,
+ dispatchTouch(when, policyFlags, & mCurrentTouch,
activeIdBits, downId, motionEventAction);
}
}
}
-void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t policyFlags,
- InputDevice::TouchData* touch, BitSet32 idBits, uint32_t changedId,
+void TouchInputMapper::dispatchTouch(nsecs_t when, uint32_t policyFlags,
+ TouchData* touch, BitSet32 idBits, uint32_t changedId,
int32_t motionEventAction) {
- int32_t orientedWidth, orientedHeight;
- switch (mDisplayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- case InputReaderPolicyInterface::ROTATION_270:
- orientedWidth = mDisplayHeight;
- orientedHeight = mDisplayWidth;
- break;
- default:
- orientedWidth = mDisplayWidth;
- orientedHeight = mDisplayHeight;
- break;
- }
-
uint32_t pointerCount = 0;
int32_t pointerIds[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
- const InputDevice::TouchScreenState::Precalculated& precalculated =
- device->touchScreen.precalculated;
-
// Walk through the the active pointers and map touch screen coordinates (TouchData) into
// display coordinates (PointerCoords) and adjust for display orientation.
while (! idBits.isEmpty()) {
@@ -845,55 +1574,57 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
idBits.clearBit(id);
uint32_t index = touch->idToIndex[id];
- float x = float(touch->pointers[index].x
- - precalculated.xOrigin) * precalculated.xScale;
- float y = float(touch->pointers[index].y
- - precalculated.yOrigin) * precalculated.yScale;
- float pressure = float(touch->pointers[index].pressure
- - precalculated.pressureOrigin) * precalculated.pressureScale;
- float size = float(touch->pointers[index].size
- - precalculated.sizeOrigin) * precalculated.sizeScale;
+ float x = float(touch->pointers[index].x - mXOrigin) * mXScale;
+ float y = float(touch->pointers[index].y - mYOrigin) * mYScale;
+ float pressure = float(touch->pointers[index].pressure - mPressureOrigin) * mPressureScale;
+ float size = float(touch->pointers[index].size - mSizeOrigin) * mSizeScale;
- float orientation = float(touch->pointers[index].orientation)
- * precalculated.orientationScale;
+ float orientation = float(touch->pointers[index].orientation) * mOrientationScale;
- bool vertical = abs(orientation) <= M_PI / 8;
+ float touchMajor, touchMinor, toolMajor, toolMinor;
+ if (abs(orientation) <= M_PI_4) {
+ // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
+ touchMajor = float(touch->pointers[index].touchMajor) * mYScale;
+ touchMinor = float(touch->pointers[index].touchMinor) * mXScale;
+ toolMajor = float(touch->pointers[index].toolMajor) * mYScale;
+ toolMinor = float(touch->pointers[index].toolMinor) * mXScale;
+ } else {
+ // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
+ touchMajor = float(touch->pointers[index].touchMajor) * mXScale;
+ touchMinor = float(touch->pointers[index].touchMinor) * mYScale;
+ toolMajor = float(touch->pointers[index].toolMajor) * mXScale;
+ toolMinor = float(touch->pointers[index].toolMinor) * mYScale;
+ }
- switch (mDisplayOrientation) {
+ switch (mSurfaceOrientation) {
case InputReaderPolicyInterface::ROTATION_90: {
float xTemp = x;
x = y;
- y = mDisplayWidth - xTemp;
- vertical = ! vertical;
+ y = mOrientedSurfaceWidth - xTemp;
+ orientation -= M_PI_2;
+ if (orientation < - M_PI_2) {
+ orientation += M_PI;
+ }
break;
}
case InputReaderPolicyInterface::ROTATION_180: {
- x = mDisplayWidth - x;
- y = mDisplayHeight - y;
+ x = mOrientedSurfaceWidth - x;
+ y = mOrientedSurfaceHeight - y;
+ orientation = - orientation;
break;
}
case InputReaderPolicyInterface::ROTATION_270: {
float xTemp = x;
- x = mDisplayHeight - y;
+ x = mOrientedSurfaceHeight - y;
y = xTemp;
- vertical = ! vertical;
+ orientation += M_PI_2;
+ if (orientation > M_PI_2) {
+ orientation -= M_PI;
+ }
break;
}
}
- float touchMajor, touchMinor, toolMajor, toolMinor;
- if (vertical) {
- touchMajor = float(touch->pointers[index].touchMajor) * precalculated.yScale;
- touchMinor = float(touch->pointers[index].touchMinor) * precalculated.xScale;
- toolMajor = float(touch->pointers[index].toolMajor) * precalculated.yScale;
- toolMinor = float(touch->pointers[index].toolMinor) * precalculated.xScale;
- } else {
- touchMajor = float(touch->pointers[index].touchMajor) * precalculated.xScale;
- touchMinor = float(touch->pointers[index].touchMinor) * precalculated.yScale;
- toolMajor = float(touch->pointers[index].toolMajor) * precalculated.xScale;
- toolMinor = float(touch->pointers[index].toolMinor) * precalculated.yScale;
- }
-
pointerIds[pointerCount] = int32_t(id);
pointerCoords[pointerCount].x = x;
@@ -919,561 +1650,984 @@ void InputReader::dispatchTouch(nsecs_t when, InputDevice* device, uint32_t poli
if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
if (pointerCoords[0].x <= 0) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
- } else if (pointerCoords[0].x >= orientedWidth) {
+ } else if (pointerCoords[0].x >= mOrientedSurfaceWidth) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
}
if (pointerCoords[0].y <= 0) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
- } else if (pointerCoords[0].y >= orientedHeight) {
+ } else if (pointerCoords[0].y >= mOrientedSurfaceHeight) {
motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
}
}
- nsecs_t downTime = device->touchScreen.downTime;
- mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
- motionEventAction, globalMetaState(), motionEventEdgeFlags,
+ getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
+ motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
pointerCount, pointerIds, pointerCoords,
- 0, 0, downTime);
+ mOrientedXPrecision, mOrientedYPrecision, mDownTime);
}
-void InputReader::onTrackballStateChanged(nsecs_t when,
- InputDevice* device) {
- static const uint32_t DELTA_FIELDS =
- InputDevice::TrackballState::Accumulator::FIELD_REL_X
- | InputDevice::TrackballState::Accumulator::FIELD_REL_Y;
+bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+ if (mAxes.x.valid && mAxes.y.valid) {
+ return x >= mAxes.x.minValue && x <= mAxes.x.maxValue
+ && y >= mAxes.y.minValue && y <= mAxes.y.maxValue;
+ }
+ return true;
+}
- /* Refresh display properties so we can trackball moves according to display orientation */
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLvk(int32_t x, int32_t y) {
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
- if (! refreshDisplayProperties()) {
- return;
- }
+#if DEBUG_VIRTUAL_KEYS
+ LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
+ "left=%d, top=%d, right=%d, bottom=%d",
+ x, y,
+ virtualKey.keyCode, virtualKey.scanCode,
+ virtualKey.hitLeft, virtualKey.hitTop,
+ virtualKey.hitRight, virtualKey.hitBottom);
+#endif
- /* Update device state */
+ if (virtualKey.isHit(x, y)) {
+ return & virtualKey;
+ }
+ }
- uint32_t fields = device->trackball.accumulator.fields;
- bool downChanged = fields & InputDevice::TrackballState::Accumulator::FIELD_BTN_MOUSE;
- bool deltaChanged = fields & DELTA_FIELDS;
+ return NULL;
+}
- bool down;
- if (downChanged) {
- if (device->trackball.accumulator.btnMouse) {
- device->trackball.current.down = true;
- device->trackball.current.downTime = when;
- down = true;
- } else {
- device->trackball.current.down = false;
- down = false;
+void TouchInputMapper::calculatePointerIds() {
+ uint32_t currentPointerCount = mCurrentTouch.pointerCount;
+ uint32_t lastPointerCount = mLastTouch.pointerCount;
+
+ if (currentPointerCount == 0) {
+ // No pointers to assign.
+ mCurrentTouch.idBits.clear();
+ } else if (lastPointerCount == 0) {
+ // All pointers are new.
+ mCurrentTouch.idBits.clear();
+ for (uint32_t i = 0; i < currentPointerCount; i++) {
+ mCurrentTouch.pointers[i].id = i;
+ mCurrentTouch.idToIndex[i] = i;
+ mCurrentTouch.idBits.markBit(i);
}
+ } else if (currentPointerCount == 1 && lastPointerCount == 1) {
+ // Only one pointer and no change in count so it must have the same id as before.
+ uint32_t id = mLastTouch.pointers[0].id;
+ mCurrentTouch.pointers[0].id = id;
+ mCurrentTouch.idToIndex[id] = 0;
+ mCurrentTouch.idBits.value = BitSet32::valueForBit(id);
} else {
- down = device->trackball.current.down;
- }
+ // General case.
+ // We build a heap of squared euclidean distances between current and last pointers
+ // associated with the current and last pointer indices. Then, we find the best
+ // match (by distance) for each current pointer.
+ PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS];
+
+ uint32_t heapSize = 0;
+ for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount;
+ currentPointerIndex++) {
+ for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount;
+ lastPointerIndex++) {
+ int64_t deltaX = mCurrentTouch.pointers[currentPointerIndex].x
+ - mLastTouch.pointers[lastPointerIndex].x;
+ int64_t deltaY = mCurrentTouch.pointers[currentPointerIndex].y
+ - mLastTouch.pointers[lastPointerIndex].y;
+
+ uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+ // Insert new element into the heap (sift up).
+ heap[heapSize].currentPointerIndex = currentPointerIndex;
+ heap[heapSize].lastPointerIndex = lastPointerIndex;
+ heap[heapSize].distance = distance;
+ heapSize += 1;
+ }
+ }
- /* Apply policy */
+ // Heapify
+ for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) {
+ startIndex -= 1;
+ for (uint32_t parentIndex = startIndex; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
+ if (childIndex >= heapSize) {
+ break;
+ }
- int32_t policyActions = mPolicy->interceptTrackball(when, downChanged, down, deltaChanged);
+ if (childIndex + 1 < heapSize
+ && heap[childIndex + 1].distance < heap[childIndex].distance) {
+ childIndex += 1;
+ }
- uint32_t policyFlags = 0;
- if (! applyStandardInputDispatchPolicyActions(when, policyActions, & policyFlags)) {
- return; // event dropped
- }
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
+ break;
+ }
- /* Enqueue motion event for dispatch */
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
+ }
+ }
- int32_t motionEventAction;
- if (downChanged) {
- motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
- } else {
- motionEventAction = AMOTION_EVENT_ACTION_MOVE;
- }
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - initial distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
- int32_t pointerId = 0;
- PointerCoords pointerCoords;
- pointerCoords.x = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_X
- ? device->trackball.accumulator.relX * device->trackball.precalculated.xScale : 0;
- pointerCoords.y = fields & InputDevice::TrackballState::Accumulator::FIELD_REL_Y
- ? device->trackball.accumulator.relY * device->trackball.precalculated.yScale : 0;
- pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
- pointerCoords.size = 0;
- pointerCoords.touchMajor = 0;
- pointerCoords.touchMinor = 0;
- pointerCoords.toolMajor = 0;
- pointerCoords.toolMinor = 0;
- pointerCoords.orientation = 0;
+ // Pull matches out by increasing order of distance.
+ // To avoid reassigning pointers that have already been matched, the loop keeps track
+ // of which last and current pointers have been matched using the matchedXXXBits variables.
+ // It also tracks the used pointer id bits.
+ BitSet32 matchedLastBits(0);
+ BitSet32 matchedCurrentBits(0);
+ BitSet32 usedIdBits(0);
+ bool first = true;
+ for (uint32_t i = min(currentPointerCount, lastPointerCount); i > 0; i--) {
+ for (;;) {
+ if (first) {
+ // The first time through the loop, we just consume the root element of
+ // the heap (the one with smallest distance).
+ first = false;
+ } else {
+ // Previous iterations consumed the root element of the heap.
+ // Pop root element off of the heap (sift down).
+ heapSize -= 1;
+ assert(heapSize > 0);
+
+ // Sift down.
+ heap[0] = heap[heapSize];
+ for (uint32_t parentIndex = 0; ;) {
+ uint32_t childIndex = parentIndex * 2 + 1;
+ if (childIndex >= heapSize) {
+ break;
+ }
+
+ if (childIndex + 1 < heapSize
+ && heap[childIndex + 1].distance < heap[childIndex].distance) {
+ childIndex += 1;
+ }
+
+ if (heap[parentIndex].distance <= heap[childIndex].distance) {
+ break;
+ }
+
+ swap(heap[parentIndex], heap[childIndex]);
+ parentIndex = childIndex;
+ }
+
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - reduced distance min-heap: size=%d", heapSize);
+ for (size_t i = 0; i < heapSize; i++) {
+ LOGD(" heap[%d]: cur=%d, last=%d, distance=%lld",
+ i, heap[i].currentPointerIndex, heap[i].lastPointerIndex,
+ heap[i].distance);
+ }
+#endif
+ }
- float temp;
- switch (mDisplayOrientation) {
- case InputReaderPolicyInterface::ROTATION_90:
- temp = pointerCoords.x;
- pointerCoords.x = pointerCoords.y;
- pointerCoords.y = - temp;
- break;
+ uint32_t currentPointerIndex = heap[0].currentPointerIndex;
+ if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched
- case InputReaderPolicyInterface::ROTATION_180:
- pointerCoords.x = - pointerCoords.x;
- pointerCoords.y = - pointerCoords.y;
- break;
+ uint32_t lastPointerIndex = heap[0].lastPointerIndex;
+ if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched
- case InputReaderPolicyInterface::ROTATION_270:
- temp = pointerCoords.x;
- pointerCoords.x = - pointerCoords.y;
- pointerCoords.y = temp;
- break;
- }
+ matchedCurrentBits.markBit(currentPointerIndex);
+ matchedLastBits.markBit(lastPointerIndex);
- mDispatcher->notifyMotion(when, device->id, AINPUT_SOURCE_TRACKBALL, policyFlags,
- motionEventAction, globalMetaState(), AMOTION_EVENT_EDGE_FLAG_NONE,
- 1, & pointerId, & pointerCoords,
- device->trackball.precalculated.xPrecision,
- device->trackball.precalculated.yPrecision,
- device->trackball.current.downTime);
-}
+ uint32_t id = mLastTouch.pointers[lastPointerIndex].id;
+ mCurrentTouch.pointers[currentPointerIndex].id = id;
+ mCurrentTouch.idToIndex[id] = currentPointerIndex;
+ usedIdBits.markBit(id);
-void InputReader::onConfigurationChanged(nsecs_t when) {
- // Reset global meta state because it depends on the list of all configured devices.
- resetGlobalMetaState();
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld",
+ lastPointerIndex, currentPointerIndex, id, heap[0].distance);
+#endif
+ break;
+ }
+ }
- // Reset virtual keys, just in case.
- updateExportedVirtualKeyState();
+ // Assign fresh ids to new pointers.
+ if (currentPointerCount > lastPointerCount) {
+ for (uint32_t i = currentPointerCount - lastPointerCount; ;) {
+ uint32_t currentPointerIndex = matchedCurrentBits.firstUnmarkedBit();
+ uint32_t id = usedIdBits.firstUnmarkedBit();
- // Update input configuration.
- updateExportedInputConfiguration();
+ mCurrentTouch.pointers[currentPointerIndex].id = id;
+ mCurrentTouch.idToIndex[id] = currentPointerIndex;
+ usedIdBits.markBit(id);
- // Enqueue configuration changed.
- mDispatcher->notifyConfigurationChanged(when);
-}
+#if DEBUG_POINTER_ASSIGNMENT
+ LOGD("calculatePointerIds - assigned: cur=%d, id=%d",
+ currentPointerIndex, id);
+#endif
-bool InputReader::applyStandardInputDispatchPolicyActions(nsecs_t when,
- int32_t policyActions, uint32_t* policyFlags) {
- if (policyActions & InputReaderPolicyInterface::ACTION_APP_SWITCH_COMING) {
- mDispatcher->notifyAppSwitchComing(when);
+ if (--i == 0) break; // done
+ matchedCurrentBits.markBit(currentPointerIndex);
+ }
+ }
+
+ // Fix id bits.
+ mCurrentTouch.idBits = usedIdBits;
}
+}
- if (policyActions & InputReaderPolicyInterface::ACTION_WOKE_HERE) {
- *policyFlags |= POLICY_FLAG_WOKE_HERE;
+/* Special hack for devices that have bad screen data: if one of the
+ * 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 (! mAxes.y.valid) {
+ return false;
}
- if (policyActions & InputReaderPolicyInterface::ACTION_BRIGHT_HERE) {
- *policyFlags |= POLICY_FLAG_BRIGHT_HERE;
+ uint32_t pointerCount = mCurrentTouch.pointerCount;
+
+ // Nothing to do if there are no points.
+ if (pointerCount == 0) {
+ return false;
}
- return policyActions & InputReaderPolicyInterface::ACTION_DISPATCH;
-}
+ // Don't do anything if a finger is going down or up. We run
+ // here before assigning pointer IDs, so there isn't a good
+ // way to do per-finger matching.
+ if (pointerCount != mLastTouch.pointerCount) {
+ return false;
+ }
-void InputReader::resetDisplayProperties() {
- mDisplayWidth = mDisplayHeight = -1;
- mDisplayOrientation = -1;
-}
+ // We consider a single movement across more than a 7/16 of
+ // 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 = mAxes.y.getRange() * 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
+ // we don't actually restore the old X either. Strange.
+ // The old code also tries to track when bad points were previously
+ // detected but it turns out that due to the placement of a "break"
+ // at the end of the loop, we never set mDroppedBadPoint to true
+ // so it is effectively dead code.
+ // Need to figure out if the old code is busted or just overcomplicated
+ // but working as intended.
+
+ // Look through all new points and see if any are farther than
+ // acceptable from all previous points.
+ for (uint32_t i = pointerCount; i-- > 0; ) {
+ int32_t y = mCurrentTouch.pointers[i].y;
+ int32_t closestY = INT_MAX;
+ int32_t closestDeltaY = 0;
+
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Looking at next point #%d: y=%d", i, y);
+#endif
-bool InputReader::refreshDisplayProperties() {
- int32_t newWidth, newHeight, newOrientation;
- if (mPolicy->getDisplayInfo(0, & newWidth, & newHeight, & newOrientation)) {
- if (newWidth != mDisplayWidth || newHeight != mDisplayHeight) {
- LOGD("Display size changed from %dx%d to %dx%d, updating device configuration",
- mDisplayWidth, mDisplayHeight, newWidth, newHeight);
+ for (uint32_t j = pointerCount; j-- > 0; ) {
+ int32_t lastY = mLastTouch.pointers[j].y;
+ int32_t deltaY = abs(y - lastY);
- mDisplayWidth = newWidth;
- mDisplayHeight = newHeight;
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Comparing with last point #%d: y=%d deltaY=%d",
+ j, lastY, deltaY);
+#endif
- for (size_t i = 0; i < mDevices.size(); i++) {
- configureDeviceForCurrentDisplaySize(mDevices.valueAt(i));
+ if (deltaY < maxDeltaY) {
+ goto SkipSufficientlyClosePoint;
+ }
+ if (deltaY < closestDeltaY) {
+ closestDeltaY = deltaY;
+ closestY = lastY;
}
}
- if (newOrientation != mDisplayOrientation) {
- LOGD("Display orientation changed to %d", mDisplayOrientation);
+ // Must not have found a close enough match.
+#if DEBUG_HACKS
+ LOGD("BadTouchFilter: Dropping bad point #%d: newY=%d oldY=%d deltaY=%d maxDeltaY=%d",
+ i, y, closestY, closestDeltaY, maxDeltaY);
+#endif
- mDisplayOrientation = newOrientation;
- }
- return true;
- } else {
- resetDisplayProperties();
- return false;
+ mCurrentTouch.pointers[i].y = closestY;
+ return true; // XXX original code only corrects one point
+
+ SkipSufficientlyClosePoint: ;
}
-}
-InputDevice* InputReader::getDevice(int32_t deviceId) {
- ssize_t index = mDevices.indexOfKey(deviceId);
- return index >= 0 ? mDevices.valueAt((size_t) index) : NULL;
+ // No change.
+ return false;
}
-InputDevice* InputReader::getNonIgnoredDevice(int32_t deviceId) {
- InputDevice* device = getDevice(deviceId);
- return device && ! device->ignored ? device : NULL;
-}
+/* Special hack for devices that have bad screen data: drop points where
+ * the coordinate value for one axis has jumped to the other pointer's location.
+ */
+bool TouchInputMapper::applyJumpyTouchFilter() {
+ // This hack requires valid axis parameters.
+ if (! mAxes.y.valid) {
+ return false;
+ }
-void InputReader::addDevice(nsecs_t when, int32_t deviceId) {
- uint32_t classes = mEventHub->getDeviceClasses(deviceId);
- String8 name = mEventHub->getDeviceName(deviceId);
- InputDevice* device = new InputDevice(deviceId, classes, name);
+ uint32_t pointerCount = mCurrentTouch.pointerCount;
+ if (mLastTouch.pointerCount != pointerCount) {
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Different pointer count %d -> %d",
+ mLastTouch.pointerCount, pointerCount);
+ for (uint32_t i = 0; i < pointerCount; i++) {
+ LOGD(" Pointer %d (%d, %d)", i,
+ mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y);
+ }
+#endif
- if (classes != 0) {
- LOGI("Device added: id=0x%x, name=%s, classes=%02x", device->id,
- device->name.string(), device->classes);
+ if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_TRANSITION_DROPS) {
+ if (mLastTouch.pointerCount == 1 && pointerCount == 2) {
+ // Just drop the first few events going from 1 to 2 pointers.
+ // They're bad often enough that they're not worth considering.
+ mCurrentTouch.pointerCount = 1;
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
- configureDevice(device);
- } else {
- LOGI("Device added: id=0x%x, name=%s (ignored non-input device)", device->id,
- device->name.string());
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Pointer 2 dropped");
+#endif
+ return true;
+ } else if (mLastTouch.pointerCount == 2 && pointerCount == 1) {
+ // The event when we go from 2 -> 1 tends to be messed up too
+ mCurrentTouch.pointerCount = 2;
+ mCurrentTouch.pointers[0] = mLastTouch.pointers[0];
+ mCurrentTouch.pointers[1] = mLastTouch.pointers[1];
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
+
+#if DEBUG_HACKS
+ for (int32_t i = 0; i < 2; i++) {
+ LOGD("JumpyTouchFilter: Pointer %d replaced (%d, %d)", i,
+ mCurrentTouch.pointers[i].x, mCurrentTouch.pointers[i].y);
+ }
+#endif
+ return true;
+ }
+ }
+ // Reset jumpy points dropped on other transitions or if limit exceeded.
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
- device->ignored = true;
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Transition - drop limit reset");
+#endif
+ return false;
}
- device->reset();
+ // We have the same number of pointers as last time.
+ // A 'jumpy' point is one where the coordinate value for one axis
+ // has jumped to the other pointer's location. No need to do anything
+ // else if we only have one pointer.
+ if (pointerCount < 2) {
+ return false;
+ }
- mDevices.add(deviceId, device);
+ if (mJumpyTouchFilter.jumpyPointsDropped < JUMPY_DROP_LIMIT) {
+ int jumpyEpsilon = mAxes.y.getRange() / JUMPY_EPSILON_DIVISOR;
- if (! device->ignored) {
- onConfigurationChanged(when);
- }
-}
+ // We only replace the single worst jumpy point as characterized by pointer distance
+ // in a single axis.
+ int32_t badPointerIndex = -1;
+ int32_t badPointerReplacementIndex = -1;
+ int32_t badPointerDistance = INT_MIN; // distance to be corrected
-void InputReader::removeDevice(nsecs_t when, InputDevice* device) {
- mDevices.removeItem(device->id);
+ for (uint32_t i = pointerCount; i-- > 0; ) {
+ int32_t x = mCurrentTouch.pointers[i].x;
+ int32_t y = mCurrentTouch.pointers[i].y;
- if (! device->ignored) {
- LOGI("Device removed: id=0x%x, name=%s, classes=%02x", device->id,
- device->name.string(), device->classes);
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Point %d (%d, %d)", i, x, y);
+#endif
- onConfigurationChanged(when);
- } else {
- LOGI("Device removed: id=0x%x, name=%s (ignored non-input device)", device->id,
- device->name.string());
- }
+ // Check if a touch point is too close to another's coordinates
+ bool dropX = false, dropY = false;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ if (i == j) {
+ continue;
+ }
- delete device;
-}
+ if (abs(x - mCurrentTouch.pointers[j].x) <= jumpyEpsilon) {
+ dropX = true;
+ break;
+ }
-void InputReader::configureDevice(InputDevice* device) {
- if (device->isMultiTouchScreen()) {
- configureAbsoluteAxisInfo(device, ABS_MT_POSITION_X, "X",
- & device->touchScreen.parameters.xAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_POSITION_Y, "Y",
- & device->touchScreen.parameters.yAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_TOUCH_MAJOR, "Pressure",
- & device->touchScreen.parameters.pressureAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_WIDTH_MAJOR, "Size",
- & device->touchScreen.parameters.sizeAxis);
- configureAbsoluteAxisInfo(device, ABS_MT_ORIENTATION, "Orientation",
- & device->touchScreen.parameters.orientationAxis);
- } else if (device->isSingleTouchScreen()) {
- configureAbsoluteAxisInfo(device, ABS_X, "X",
- & device->touchScreen.parameters.xAxis);
- configureAbsoluteAxisInfo(device, ABS_Y, "Y",
- & device->touchScreen.parameters.yAxis);
- configureAbsoluteAxisInfo(device, ABS_PRESSURE, "Pressure",
- & device->touchScreen.parameters.pressureAxis);
- configureAbsoluteAxisInfo(device, ABS_TOOL_WIDTH, "Size",
- & device->touchScreen.parameters.sizeAxis);
- device->touchScreen.parameters.orientationAxis.valid = false;
- }
-
- if (device->isTouchScreen()) {
- device->touchScreen.parameters.useBadTouchFilter =
- mPolicy->filterTouchEvents();
- device->touchScreen.parameters.useAveragingTouchFilter =
- mPolicy->filterTouchEvents();
- device->touchScreen.parameters.useJumpyTouchFilter =
- mPolicy->filterJumpyTouchEvents();
-
- if (device->touchScreen.parameters.pressureAxis.valid) {
- device->touchScreen.precalculated.pressureOrigin =
- device->touchScreen.parameters.pressureAxis.minValue;
- device->touchScreen.precalculated.pressureScale =
- 1.0f / device->touchScreen.parameters.pressureAxis.range;
- } else {
- device->touchScreen.precalculated.pressureOrigin = 0;
- device->touchScreen.precalculated.pressureScale = 1.0f;
- }
+ if (abs(y - mCurrentTouch.pointers[j].y) <= jumpyEpsilon) {
+ dropY = true;
+ break;
+ }
+ }
+ if (! dropX && ! dropY) {
+ continue; // not jumpy
+ }
- if (device->touchScreen.parameters.sizeAxis.valid) {
- device->touchScreen.precalculated.sizeOrigin =
- device->touchScreen.parameters.sizeAxis.minValue;
- device->touchScreen.precalculated.sizeScale =
- 1.0f / device->touchScreen.parameters.sizeAxis.range;
- } else {
- device->touchScreen.precalculated.sizeOrigin = 0;
- device->touchScreen.precalculated.sizeScale = 1.0f;
- }
+ // Find a replacement candidate by comparing with older points on the
+ // complementary (non-jumpy) axis.
+ int32_t distance = INT_MIN; // distance to be corrected
+ int32_t replacementIndex = -1;
+
+ if (dropX) {
+ // X looks too close. Find an older replacement point with a close Y.
+ int32_t smallestDeltaY = INT_MAX;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ int32_t deltaY = abs(y - mLastTouch.pointers[j].y);
+ if (deltaY < smallestDeltaY) {
+ smallestDeltaY = deltaY;
+ replacementIndex = j;
+ }
+ }
+ distance = abs(x - mLastTouch.pointers[replacementIndex].x);
+ } else {
+ // Y looks too close. Find an older replacement point with a close X.
+ int32_t smallestDeltaX = INT_MAX;
+ for (uint32_t j = 0; j < pointerCount; j++) {
+ int32_t deltaX = abs(x - mLastTouch.pointers[j].x);
+ if (deltaX < smallestDeltaX) {
+ smallestDeltaX = deltaX;
+ replacementIndex = j;
+ }
+ }
+ distance = abs(y - mLastTouch.pointers[replacementIndex].y);
+ }
- if (device->touchScreen.parameters.orientationAxis.valid
- && device->touchScreen.parameters.orientationAxis.maxValue > 0) {
- device->touchScreen.precalculated.orientationScale =
- M_PI_4 / device->touchScreen.parameters.orientationAxis.maxValue;
- } else {
- device->touchScreen.precalculated.orientationScale = 0.0f;
+ // If replacing this pointer would correct a worse error than the previous ones
+ // considered, then use this replacement instead.
+ if (distance > badPointerDistance) {
+ badPointerIndex = i;
+ badPointerReplacementIndex = replacementIndex;
+ badPointerDistance = distance;
+ }
}
- }
- if (device->isTrackball()) {
- device->trackball.precalculated.xPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.yPrecision = TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.xScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
- device->trackball.precalculated.yScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
+ // Correct the jumpy pointer if one was found.
+ if (badPointerIndex >= 0) {
+#if DEBUG_HACKS
+ LOGD("JumpyTouchFilter: Replacing bad pointer %d with (%d, %d)",
+ badPointerIndex,
+ mLastTouch.pointers[badPointerReplacementIndex].x,
+ mLastTouch.pointers[badPointerReplacementIndex].y);
+#endif
+
+ mCurrentTouch.pointers[badPointerIndex].x =
+ mLastTouch.pointers[badPointerReplacementIndex].x;
+ mCurrentTouch.pointers[badPointerIndex].y =
+ mLastTouch.pointers[badPointerReplacementIndex].y;
+ mJumpyTouchFilter.jumpyPointsDropped += 1;
+ return true;
+ }
}
- configureDeviceForCurrentDisplaySize(device);
+ mJumpyTouchFilter.jumpyPointsDropped = 0;
+ return false;
}
-void InputReader::configureDeviceForCurrentDisplaySize(InputDevice* device) {
- if (device->isTouchScreen()) {
- if (device->touchScreen.parameters.xAxis.valid
- && device->touchScreen.parameters.yAxis.valid) {
- device->touchScreen.precalculated.xOrigin =
- device->touchScreen.parameters.xAxis.minValue;
- device->touchScreen.precalculated.yOrigin =
- device->touchScreen.parameters.yAxis.minValue;
+/* Special hack for devices that have bad screen data: aggregate and
+ * compute averages of the coordinate data, to reduce the amount of
+ * jitter seen by applications. */
+void TouchInputMapper::applyAveragingTouchFilter() {
+ for (uint32_t currentIndex = 0; currentIndex < mCurrentTouch.pointerCount; currentIndex++) {
+ uint32_t id = mCurrentTouch.pointers[currentIndex].id;
+ int32_t x = mCurrentTouch.pointers[currentIndex].x;
+ int32_t y = mCurrentTouch.pointers[currentIndex].y;
+ int32_t pressure = mCurrentTouch.pointers[currentIndex].pressure;
+
+ if (mLastTouch.idBits.hasBit(id)) {
+ // Pointer was down before and is still down now.
+ // Compute average over history trace.
+ uint32_t start = mAveragingTouchFilter.historyStart[id];
+ uint32_t end = mAveragingTouchFilter.historyEnd[id];
+
+ int64_t deltaX = x - mAveragingTouchFilter.historyData[end].pointers[id].x;
+ int64_t deltaY = y - mAveragingTouchFilter.historyData[end].pointers[id].y;
+ uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY);
+
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Distance from last sample: %lld",
+ id, distance);
+#endif
- if (mDisplayWidth < 0) {
- LOGD("Skipping part of touch screen configuration since display size is unknown.");
+ if (distance < AVERAGING_DISTANCE_LIMIT) {
+ // Increment end index in preparation for recording new historical data.
+ end += 1;
+ if (end > AVERAGING_HISTORY_SIZE) {
+ end = 0;
+ }
- device->touchScreen.precalculated.xScale = 1.0f;
- device->touchScreen.precalculated.yScale = 1.0f;
- } else {
- LOGI("Device configured: id=0x%x, name=%s (display size was changed)", device->id,
- device->name.string());
+ // If the end index has looped back to the start index then we have filled
+ // the historical trace up to the desired size so we drop the historical
+ // data at the start of the trace.
+ if (end == start) {
+ start += 1;
+ if (start > AVERAGING_HISTORY_SIZE) {
+ start = 0;
+ }
+ }
- device->touchScreen.precalculated.xScale =
- float(mDisplayWidth) / device->touchScreen.parameters.xAxis.range;
- device->touchScreen.precalculated.yScale =
- float(mDisplayHeight) / device->touchScreen.parameters.yAxis.range;
+ // Add the raw data to the historical trace.
+ mAveragingTouchFilter.historyStart[id] = start;
+ mAveragingTouchFilter.historyEnd[id] = end;
+ mAveragingTouchFilter.historyData[end].pointers[id].x = x;
+ mAveragingTouchFilter.historyData[end].pointers[id].y = y;
+ mAveragingTouchFilter.historyData[end].pointers[id].pressure = pressure;
+
+ // Average over all historical positions in the trace by total pressure.
+ int32_t averagedX = 0;
+ int32_t averagedY = 0;
+ int32_t totalPressure = 0;
+ for (;;) {
+ int32_t historicalX = mAveragingTouchFilter.historyData[start].pointers[id].x;
+ int32_t historicalY = mAveragingTouchFilter.historyData[start].pointers[id].y;
+ int32_t historicalPressure = mAveragingTouchFilter.historyData[start]
+ .pointers[id].pressure;
+
+ averagedX += historicalX * historicalPressure;
+ averagedY += historicalY * historicalPressure;
+ totalPressure += historicalPressure;
+
+ if (start == end) {
+ break;
+ }
+
+ start += 1;
+ if (start > AVERAGING_HISTORY_SIZE) {
+ start = 0;
+ }
+ }
+
+ averagedX /= totalPressure;
+ averagedY /= totalPressure;
+
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - "
+ "totalPressure=%d, averagedX=%d, averagedY=%d", id, totalPressure,
+ averagedX, averagedY);
+#endif
- configureVirtualKeys(device);
+ mCurrentTouch.pointers[currentIndex].x = averagedX;
+ mCurrentTouch.pointers[currentIndex].y = averagedY;
+ } else {
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Exceeded max distance", id);
+#endif
}
} else {
- device->touchScreen.precalculated.xOrigin = 0;
- device->touchScreen.precalculated.xScale = 1.0f;
- device->touchScreen.precalculated.yOrigin = 0;
- device->touchScreen.precalculated.yScale = 1.0f;
+#if DEBUG_HACKS
+ LOGD("AveragingTouchFilter: Pointer id %d - Pointer went up", id);
+#endif
}
+
+ // Reset pointer history.
+ mAveragingTouchFilter.historyStart[id] = 0;
+ mAveragingTouchFilter.historyEnd[id] = 0;
+ mAveragingTouchFilter.historyData[0].pointers[id].x = x;
+ mAveragingTouchFilter.historyData[0].pointers[id].y = y;
+ mAveragingTouchFilter.historyData[0].pointers[id].pressure = pressure;
}
}
-void InputReader::configureVirtualKeys(InputDevice* device) {
- assert(device->touchScreen.parameters.xAxis.valid
- && device->touchScreen.parameters.yAxis.valid);
-
- device->touchScreen.virtualKeys.clear();
-
- Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
- mPolicy->getVirtualKeyDefinitions(device->name, virtualKeyDefinitions);
- if (virtualKeyDefinitions.size() == 0) {
- return;
- }
+int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- device->touchScreen.virtualKeys.setCapacity(virtualKeyDefinitions.size());
+ if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
+ return AKEY_STATE_VIRTUAL;
+ }
- int32_t touchScreenLeft = device->touchScreen.parameters.xAxis.minValue;
- int32_t touchScreenTop = device->touchScreen.parameters.yAxis.minValue;
- int32_t touchScreenWidth = device->touchScreen.parameters.xAxis.range;
- int32_t touchScreenHeight = device->touchScreen.parameters.yAxis.range;
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
+ if (virtualKey.keyCode == keyCode) {
+ return AKEY_STATE_UP;
+ }
+ }
+ } // release virtual key lock
- for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
- const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
- virtualKeyDefinitions[i];
+ return AKEY_STATE_UNKNOWN;
+}
- device->touchScreen.virtualKeys.add();
- InputDevice::VirtualKey& virtualKey =
- device->touchScreen.virtualKeys.editTop();
+int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- virtualKey.scanCode = virtualKeyDefinition.scanCode;
- int32_t keyCode;
- uint32_t flags;
- if (mEventHub->scancodeToKeycode(device->id, virtualKey.scanCode,
- & keyCode, & flags)) {
- LOGW(" VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
- device->touchScreen.virtualKeys.pop(); // drop the key
- continue;
+ if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
+ return AKEY_STATE_VIRTUAL;
}
- virtualKey.keyCode = keyCode;
- virtualKey.flags = flags;
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
+ if (virtualKey.scanCode == scanCode) {
+ return AKEY_STATE_UP;
+ }
+ }
+ } // release virtual key lock
- // convert the key definition's display coordinates into touch coordinates for a hit box
- int32_t halfWidth = virtualKeyDefinition.width / 2;
- int32_t halfHeight = virtualKeyDefinition.height / 2;
+ return AKEY_STATE_UNKNOWN;
+}
- virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
- * touchScreenWidth / mDisplayWidth + touchScreenLeft;
- virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
- * touchScreenWidth / mDisplayWidth + touchScreenLeft;
- virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
- * touchScreenHeight / mDisplayHeight + touchScreenTop;
- virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
- * touchScreenHeight / mDisplayHeight + touchScreenTop;
+bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
+ const int32_t* keyCodes, uint8_t* outFlags) {
+ { // acquire virtual key lock
+ AutoMutex _l(mVirtualKeyLock);
- LOGI(" VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
- virtualKey.scanCode, virtualKey.keyCode,
- virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
- }
-}
+ for (size_t i = 0; i < mVirtualKeys.size(); i++) {
+ const VirtualKey& virtualKey = mVirtualKeys[i];
-void InputReader::configureAbsoluteAxisInfo(InputDevice* device,
- int axis, const char* name, InputDevice::AbsoluteAxisInfo* out) {
- if (! mEventHub->getAbsoluteInfo(device->id, axis,
- & out->minValue, & out->maxValue, & out->flat, &out->fuzz)) {
- out->range = out->maxValue - out->minValue;
- if (out->range != 0) {
- LOGI(" %s: min=%d max=%d flat=%d fuzz=%d",
- name, out->minValue, out->maxValue, out->flat, out->fuzz);
- out->valid = true;
- return;
+ for (size_t i = 0; i < numCodes; i++) {
+ if (virtualKey.keyCode == keyCodes[i]) {
+ outFlags[i] = 1;
+ }
+ }
}
- }
+ } // release virtual key lock
- out->valid = false;
- out->minValue = 0;
- out->maxValue = 0;
- out->flat = 0;
- out->fuzz = 0;
- out->range = 0;
- LOGI(" %s: unknown axis values, marking as invalid", name);
+ return true;
}
-void InputReader::configureExcludedDevices() {
- Vector<String8> excludedDeviceNames;
- mPolicy->getExcludedDeviceNames(excludedDeviceNames);
- for (size_t i = 0; i < excludedDeviceNames.size(); i++) {
- mEventHub->addExcludedDevice(excludedDeviceNames[i]);
- }
+// --- SingleTouchInputMapper ---
+
+SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ TouchInputMapper(device, associatedDisplayId) {
+ initialize();
}
-void InputReader::resetGlobalMetaState() {
- mGlobalMetaState = -1;
+SingleTouchInputMapper::~SingleTouchInputMapper() {
}
-int32_t InputReader::globalMetaState() {
- if (mGlobalMetaState == -1) {
- mGlobalMetaState = 0;
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- if (device->isKeyboard()) {
- mGlobalMetaState |= device->keyboard.current.metaState;
+void SingleTouchInputMapper::initialize() {
+ mAccumulator.clear();
+
+ mDown = false;
+ mX = 0;
+ mY = 0;
+ mPressure = 0;
+ mSize = 0;
+}
+
+void SingleTouchInputMapper::reset() {
+ TouchInputMapper::reset();
+
+ // Reinitialize.
+ initialize();
+ }
+
+void SingleTouchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_KEY:
+ switch (rawEvent->scanCode) {
+ case BTN_TOUCH:
+ mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;
+ mAccumulator.btnTouch = rawEvent->value != 0;
+
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ break;
+ }
+ break;
+
+ case EV_ABS:
+ switch (rawEvent->scanCode) {
+ case ABS_X:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_X;
+ mAccumulator.absX = rawEvent->value;
+ break;
+ case ABS_Y:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_Y;
+ mAccumulator.absY = rawEvent->value;
+ break;
+ case ABS_PRESSURE:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_PRESSURE;
+ mAccumulator.absPressure = rawEvent->value;
+ break;
+ case ABS_TOOL_WIDTH:
+ mAccumulator.fields |= Accumulator::FIELD_ABS_TOOL_WIDTH;
+ mAccumulator.absToolWidth = rawEvent->value;
+ break;
+ }
+ break;
+
+ case EV_SYN:
+ switch (rawEvent->scanCode) {
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
}
+ break;
}
+ break;
}
- return mGlobalMetaState;
}
-void InputReader::updateExportedVirtualKeyState() {
- int32_t keyCode = -1, scanCode = -1;
+void SingleTouchInputMapper::sync(nsecs_t when) {
+ /* Update device state */
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- if (device->isTouchScreen()) {
- if (device->touchScreen.currentVirtualKey.status
- == InputDevice::TouchScreenState::CurrentVirtualKeyState::STATUS_DOWN) {
- keyCode = device->touchScreen.currentVirtualKey.keyCode;
- scanCode = device->touchScreen.currentVirtualKey.scanCode;
- }
- }
+ uint32_t fields = mAccumulator.fields;
+
+ if (fields & Accumulator::FIELD_BTN_TOUCH) {
+ mDown = mAccumulator.btnTouch;
+ }
+
+ if (fields & Accumulator::FIELD_ABS_X) {
+ mX = mAccumulator.absX;
}
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ if (fields & Accumulator::FIELD_ABS_Y) {
+ mY = mAccumulator.absY;
+ }
- mExportedVirtualKeyCode = keyCode;
- mExportedVirtualScanCode = scanCode;
- } // release exported state lock
+ if (fields & Accumulator::FIELD_ABS_PRESSURE) {
+ mPressure = mAccumulator.absPressure;
+ }
+
+ if (fields & Accumulator::FIELD_ABS_TOOL_WIDTH) {
+ mSize = mAccumulator.absToolWidth;
+ }
+
+ mCurrentTouch.clear();
+
+ if (mDown) {
+ mCurrentTouch.pointerCount = 1;
+ mCurrentTouch.pointers[0].id = 0;
+ mCurrentTouch.pointers[0].x = mX;
+ mCurrentTouch.pointers[0].y = mY;
+ mCurrentTouch.pointers[0].pressure = mPressure;
+ mCurrentTouch.pointers[0].size = mSize;
+ mCurrentTouch.pointers[0].touchMajor = mPressure;
+ mCurrentTouch.pointers[0].touchMinor = mPressure;
+ mCurrentTouch.pointers[0].toolMajor = mSize;
+ mCurrentTouch.pointers[0].toolMinor = mSize;
+ mCurrentTouch.pointers[0].orientation = 0;
+ mCurrentTouch.idToIndex[0] = 0;
+ mCurrentTouch.idBits.markBit(0);
+ }
+
+ syncTouch(when, true);
}
-bool InputReader::getCurrentVirtualKey(int32_t* outKeyCode, int32_t* outScanCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+void SingleTouchInputMapper::configureAxes() {
+ TouchInputMapper::configureAxes();
- *outKeyCode = mExportedVirtualKeyCode;
- *outScanCode = mExportedVirtualScanCode;
- return mExportedVirtualKeyCode != -1;
- } // release exported state lock
+ // The axes are aliased to take into account the manner in which they are presented
+ // as part of the TouchData during the sync.
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_X, & mAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_Y, & mAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_PRESSURE, & mAxes.pressure);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_TOOL_WIDTH, & mAxes.size);
+
+ mAxes.touchMajor = mAxes.pressure;
+ mAxes.touchMinor = mAxes.pressure;
+ mAxes.toolMajor = mAxes.size;
+ mAxes.toolMinor = mAxes.size;
}
-void InputReader::updateExportedInputConfiguration() {
- int32_t touchScreenConfig = InputConfiguration::TOUCHSCREEN_NOTOUCH;
- int32_t keyboardConfig = InputConfiguration::KEYBOARD_NOKEYS;
- int32_t navigationConfig = InputConfiguration::NAVIGATION_NONAV;
- for (size_t i = 0; i < mDevices.size(); i++) {
- InputDevice* device = mDevices.valueAt(i);
- int32_t deviceClasses = device->classes;
+// --- MultiTouchInputMapper ---
+
+MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
+ TouchInputMapper(device, associatedDisplayId) {
+ initialize();
+}
+
+MultiTouchInputMapper::~MultiTouchInputMapper() {
+}
+
+void MultiTouchInputMapper::initialize() {
+ mAccumulator.clear();
+}
+
+void MultiTouchInputMapper::reset() {
+ TouchInputMapper::reset();
- if (deviceClasses & INPUT_DEVICE_CLASS_TOUCHSCREEN) {
- touchScreenConfig = InputConfiguration::TOUCHSCREEN_FINGER;
+ // Reinitialize.
+ initialize();
+}
+
+void MultiTouchInputMapper::process(const RawEvent* rawEvent) {
+ switch (rawEvent->type) {
+ case EV_ABS: {
+ uint32_t pointerIndex = mAccumulator.pointerCount;
+ Accumulator::Pointer* pointer = & mAccumulator.pointers[pointerIndex];
+
+ switch (rawEvent->scanCode) {
+ case ABS_MT_POSITION_X:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_X;
+ pointer->absMTPositionX = rawEvent->value;
+ break;
+ case ABS_MT_POSITION_Y:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_POSITION_Y;
+ pointer->absMTPositionY = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MAJOR;
+ pointer->absMTTouchMajor = rawEvent->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TOUCH_MINOR;
+ pointer->absMTTouchMinor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
+ pointer->absMTWidthMajor = rawEvent->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_WIDTH_MINOR;
+ pointer->absMTWidthMinor = rawEvent->value;
+ break;
+ case ABS_MT_ORIENTATION:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_ORIENTATION;
+ pointer->absMTOrientation = rawEvent->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ pointer->fields |= Accumulator::FIELD_ABS_MT_TRACKING_ID;
+ pointer->absMTTrackingId = rawEvent->value;
+ break;
}
- if (deviceClasses & INPUT_DEVICE_CLASS_ALPHAKEY) {
- keyboardConfig = InputConfiguration::KEYBOARD_QWERTY;
+ break;
+ }
+
+ case EV_SYN:
+ 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();
+ break;
}
- if (deviceClasses & INPUT_DEVICE_CLASS_TRACKBALL) {
- navigationConfig = InputConfiguration::NAVIGATION_TRACKBALL;
- } else if (deviceClasses & INPUT_DEVICE_CLASS_DPAD) {
- navigationConfig = InputConfiguration::NAVIGATION_DPAD;
+
+ case SYN_REPORT:
+ if (mAccumulator.isDirty()) {
+ sync(rawEvent->when);
+ mAccumulator.clear();
+ }
+ break;
}
+ break;
}
+}
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+void MultiTouchInputMapper::sync(nsecs_t when) {
+ static const uint32_t REQUIRED_FIELDS =
+ Accumulator::FIELD_ABS_MT_POSITION_X
+ | Accumulator::FIELD_ABS_MT_POSITION_Y
+ | Accumulator::FIELD_ABS_MT_TOUCH_MAJOR
+ | Accumulator::FIELD_ABS_MT_WIDTH_MAJOR;
- mExportedInputConfiguration.touchScreen = touchScreenConfig;
- mExportedInputConfiguration.keyboard = keyboardConfig;
- mExportedInputConfiguration.navigation = navigationConfig;
- } // release exported state lock
-}
+ /* Update device state */
+
+ uint32_t inCount = mAccumulator.pointerCount;
+ uint32_t outCount = 0;
+ bool havePointerIds = true;
-void InputReader::getCurrentInputConfiguration(InputConfiguration* outConfiguration) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ mCurrentTouch.clear();
- *outConfiguration = mExportedInputConfiguration;
- } // release exported state lock
-}
+ for (uint32_t inIndex = 0; inIndex < inCount; inIndex++) {
+ uint32_t fields = mAccumulator.pointers[inIndex].fields;
-int32_t InputReader::getCurrentScanCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t scanCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ if ((fields & REQUIRED_FIELDS) != REQUIRED_FIELDS) {
+#if DEBUG_POINTERS
+ LOGD("Pointers: Missing required multitouch pointer fields: index=%d, fields=%d",
+ inIndex, fields);
+ continue;
+#endif
+ }
- if (mExportedVirtualScanCode == scanCode) {
- return AKEY_STATE_VIRTUAL;
+ if (mAccumulator.pointers[inIndex].absMTTouchMajor <= 0) {
+ // Pointer is not down. Drop it.
+ continue;
}
- } // release exported state lock
- return mEventHub->getScanCodeState(deviceId, deviceClasses, scanCode);
-}
+ mCurrentTouch.pointers[outCount].x = mAccumulator.pointers[inIndex].absMTPositionX;
+ mCurrentTouch.pointers[outCount].y = mAccumulator.pointers[inIndex].absMTPositionY;
-int32_t InputReader::getCurrentKeyCodeState(int32_t deviceId, int32_t deviceClasses,
- int32_t keyCode) const {
- { // acquire exported state lock
- AutoMutex _l(mExportedStateLock);
+ mCurrentTouch.pointers[outCount].touchMajor =
+ mAccumulator.pointers[inIndex].absMTTouchMajor;
+ mCurrentTouch.pointers[outCount].touchMinor =
+ (fields & Accumulator::FIELD_ABS_MT_TOUCH_MINOR) != 0
+ ? mAccumulator.pointers[inIndex].absMTTouchMinor
+ : mAccumulator.pointers[inIndex].absMTTouchMajor;
- if (mExportedVirtualKeyCode == keyCode) {
- return AKEY_STATE_VIRTUAL;
+ mCurrentTouch.pointers[outCount].toolMajor =
+ mAccumulator.pointers[inIndex].absMTWidthMajor;
+ mCurrentTouch.pointers[outCount].toolMinor =
+ (fields & Accumulator::FIELD_ABS_MT_WIDTH_MINOR) != 0
+ ? mAccumulator.pointers[inIndex].absMTWidthMinor
+ : mAccumulator.pointers[inIndex].absMTWidthMajor;
+
+ mCurrentTouch.pointers[outCount].orientation =
+ (fields & Accumulator::FIELD_ABS_MT_ORIENTATION) != 0
+ ? mAccumulator.pointers[inIndex].absMTOrientation : 0;
+
+ // Derive an approximation of pressure and size.
+ // FIXME assignment of pressure may be incorrect, probably better to let
+ // pressure = touch / width. Later on we pass width to MotionEvent as a size, which
+ // isn't quite right either. Should be using touch for that.
+ mCurrentTouch.pointers[outCount].pressure = mAccumulator.pointers[inIndex].absMTTouchMajor;
+ mCurrentTouch.pointers[outCount].size = mAccumulator.pointers[inIndex].absMTWidthMajor;
+
+ if (havePointerIds) {
+ if (fields & Accumulator::
+ FIELD_ABS_MT_TRACKING_ID) {
+ uint32_t id = uint32_t(mAccumulator.pointers[inIndex].absMTTrackingId);
+
+ if (id > MAX_POINTER_ID) {
+#if DEBUG_POINTERS
+ LOGD("Pointers: Ignoring driver provided pointer id %d because "
+ "it is larger than max supported id %d for optimizations",
+ id, MAX_POINTER_ID);
+#endif
+ havePointerIds = false;
+ }
+ else {
+ mCurrentTouch.pointers[outCount].id = id;
+ mCurrentTouch.idToIndex[id] = outCount;
+ mCurrentTouch.idBits.markBit(id);
+ }
+ } else {
+ havePointerIds = false;
+ }
}
- } // release exported state lock
- return mEventHub->getKeyCodeState(deviceId, deviceClasses, keyCode);
-}
+ outCount += 1;
+ }
-int32_t InputReader::getCurrentSwitchState(int32_t deviceId, int32_t deviceClasses,
- int32_t sw) const {
- return mEventHub->getSwitchState(deviceId, deviceClasses, sw);
-}
+ mCurrentTouch.pointerCount = outCount;
-bool InputReader::hasKeys(size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) const {
- return mEventHub->hasKeys(numCodes, keyCodes, outFlags);
+ syncTouch(when, havePointerIds);
}
+void MultiTouchInputMapper::configureAxes() {
+ TouchInputMapper::configureAxes();
-// --- InputReaderThread ---
+ // The axes are aliased to take into account the manner in which they are presented
+ // as part of the TouchData during the sync.
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_X, & mAxes.x);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_POSITION_Y, & mAxes.y);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MAJOR, & mAxes.touchMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_TOUCH_MINOR, & mAxes.touchMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MAJOR, & mAxes.toolMajor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_WIDTH_MINOR, & mAxes.toolMinor);
+ getEventHub()->getAbsoluteAxisInfo(getDeviceId(), ABS_MT_ORIENTATION, & mAxes.orientation);
-InputReaderThread::InputReaderThread(const sp<InputReaderInterface>& reader) :
- Thread(/*canCallJava*/ true), mReader(reader) {
-}
+ if (! mAxes.touchMinor.valid) {
+ mAxes.touchMinor = mAxes.touchMajor;
+ }
-InputReaderThread::~InputReaderThread() {
-}
+ if (! mAxes.toolMinor.valid) {
+ mAxes.toolMinor = mAxes.toolMajor;
+ }
-bool InputReaderThread::threadLoop() {
- mReader->loopOnce();
- return true;
+ mAxes.pressure = mAxes.touchMajor;
+ mAxes.size = mAxes.toolMajor;
}
+
} // namespace android