Support composite touch / joystick devices better.

This change enables the joystick input mapper to handle any axes
that are not claimed by the touch input mapper, which makes
auxiliary controls such as wheels / knobs accessible.

Change-Id: I01ee7f342ac91acfcb4ccb6676fd52b3d5bf31a0
This commit is contained in:
Jeff Brown
2011-08-31 12:56:34 -07:00
parent cc4f7db698
commit 9ee285afe7
5 changed files with 74 additions and 16 deletions

View File

@@ -78,6 +78,40 @@ static inline const char* toString(bool value) {
return value ? "true" : "false";
}
// --- Global Functions ---
uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) {
// Touch devices get dibs on touch-related axes.
if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) {
switch (axis) {
case ABS_X:
case ABS_Y:
case ABS_PRESSURE:
case ABS_TOOL_WIDTH:
case ABS_DISTANCE:
case ABS_TILT_X:
case ABS_TILT_Y:
case ABS_MT_SLOT:
case ABS_MT_TOUCH_MAJOR:
case ABS_MT_TOUCH_MINOR:
case ABS_MT_WIDTH_MAJOR:
case ABS_MT_WIDTH_MINOR:
case ABS_MT_ORIENTATION:
case ABS_MT_POSITION_X:
case ABS_MT_POSITION_Y:
case ABS_MT_TOOL_TYPE:
case ABS_MT_BLOB_ID:
case ABS_MT_TRACKING_ID:
case ABS_MT_PRESSURE:
case ABS_MT_DISTANCE:
return INPUT_DEVICE_CLASS_TOUCH;
}
}
// Joystick devices get the rest.
return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK;
}
// --- EventHub::Device ---
EventHub::Device::Device(int fd, int32_t id, const String8& path,
@@ -936,13 +970,17 @@ status_t EventHub::openDeviceLocked(const char *devicePath) {
}
// See if this device is a joystick.
// Ignore touchscreens because they use the same absolute axes for other purposes.
// Assumes that joysticks always have gamepad buttons in order to distinguish them
// from other devices such as accelerometers that also have absolute axes.
if (haveGamepadButtons
&& !(device->classes & INPUT_DEVICE_CLASS_TOUCH)
&& containsNonZeroByte(device->absBitmask, 0, sizeof_bit_array(ABS_MAX + 1))) {
device->classes |= INPUT_DEVICE_CLASS_JOYSTICK;
if (haveGamepadButtons) {
uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK;
for (int i = 0; i <= ABS_MAX; i++) {
if (test_bit(i, device->absBitmask)
&& (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) {
device->classes = assumedClasses;
break;
}
}
}
// Check whether this device has switches.

View File

@@ -111,6 +111,12 @@ enum {
INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000,
};
/*
* Gets the class that owns an axis, in cases where multiple classes might claim
* the same axis for different purposes.
*/
extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses);
/*
* Grand Central Station for events.
*

View File

@@ -390,7 +390,7 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
InputDevice* InputReader::createDeviceLocked(int32_t deviceId,
const String8& name, uint32_t classes) {
InputDevice* device = new InputDevice(&mContext, deviceId, name);
InputDevice* device = new InputDevice(&mContext, deviceId, name, classes);
// External devices.
if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
@@ -842,9 +842,10 @@ bool InputReaderThread::threadLoop() {
// --- InputDevice ---
InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name) :
mContext(context), mId(id), mName(name), mSources(0),
mIsExternal(false), mDropUntilNextSync(false) {
InputDevice::InputDevice(InputReaderContext* context, int32_t id, const String8& name,
uint32_t classes) :
mContext(context), mId(id), mName(name), mClasses(classes),
mSources(0), mIsExternal(false), mDropUntilNextSync(false) {
}
InputDevice::~InputDevice() {
@@ -5759,6 +5760,11 @@ void JoystickInputMapper::configure(nsecs_t when,
if (!changes) { // first time only
// Collect all axes.
for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
if (!(getAbsAxisUsage(abs, getDevice()->getClasses())
& INPUT_DEVICE_CLASS_JOYSTICK)) {
continue; // axis must be claimed by a different device
}
RawAbsoluteAxisInfo rawAxisInfo;
getAbsoluteAxisInfo(abs, &rawAxisInfo);
if (rawAxisInfo.valid) {

View File

@@ -430,12 +430,13 @@ private:
/* Represents the state of a single input device. */
class InputDevice {
public:
InputDevice(InputReaderContext* context, int32_t id, const String8& name);
InputDevice(InputReaderContext* context, int32_t id, const String8& name, uint32_t classes);
~InputDevice();
inline InputReaderContext* getContext() { return mContext; }
inline int32_t getId() { return mId; }
inline const String8& getName() { return mName; }
inline uint32_t getClasses() { return mClasses; }
inline uint32_t getSources() { return mSources; }
inline bool isExternal() { return mIsExternal; }
@@ -483,10 +484,11 @@ public:
private:
InputReaderContext* mContext;
int32_t mId;
String8 mName;
uint32_t mClasses;
Vector<InputMapper*> mMappers;
String8 mName;
uint32_t mSources;
bool mIsExternal;
bool mDropUntilNextSync;

View File

@@ -852,8 +852,8 @@ public:
mNextDevice = device;
}
InputDevice* newDevice(int32_t deviceId, const String8& name) {
return new InputDevice(&mContext, deviceId, name);
InputDevice* newDevice(int32_t deviceId, const String8& name, uint32_t classes) {
return new InputDevice(&mContext, deviceId, name, classes);
}
protected:
@@ -912,7 +912,7 @@ protected:
FakeInputMapper* addDeviceWithFakeInputMapper(int32_t deviceId,
const String8& name, uint32_t classes, uint32_t sources,
const PropertyMap* configuration) {
InputDevice* device = mReader->newDevice(deviceId, name);
InputDevice* device = mReader->newDevice(deviceId, name, classes);
FakeInputMapper* mapper = new FakeInputMapper(device, sources);
device->addMapper(mapper);
mReader->setNextDevice(device);
@@ -1211,6 +1211,7 @@ class InputDeviceTest : public testing::Test {
protected:
static const char* DEVICE_NAME;
static const int32_t DEVICE_ID;
static const uint32_t DEVICE_CLASSES;
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -1226,7 +1227,7 @@ protected:
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
}
virtual void TearDown() {
@@ -1241,10 +1242,13 @@ protected:
const char* InputDeviceTest::DEVICE_NAME = "device";
const int32_t InputDeviceTest::DEVICE_ID = 1;
const uint32_t InputDeviceTest::DEVICE_CLASSES = INPUT_DEVICE_CLASS_KEYBOARD
| INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_JOYSTICK;
TEST_F(InputDeviceTest, ImmutableProperties) {
ASSERT_EQ(DEVICE_ID, mDevice->getId());
ASSERT_STREQ(DEVICE_NAME, mDevice->getName());
ASSERT_EQ(DEVICE_CLASSES, mDevice->getClasses());
}
TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
@@ -1390,6 +1394,7 @@ class InputMapperTest : public testing::Test {
protected:
static const char* DEVICE_NAME;
static const int32_t DEVICE_ID;
static const uint32_t DEVICE_CLASSES;
sp<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
@@ -1402,7 +1407,7 @@ protected:
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new FakeInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME));
mDevice = new InputDevice(mFakeContext, DEVICE_ID, String8(DEVICE_NAME), DEVICE_CLASSES);
mFakeEventHub->addDevice(DEVICE_ID, String8(DEVICE_NAME), 0);
}
@@ -1483,6 +1488,7 @@ protected:
const char* InputMapperTest::DEVICE_NAME = "device";
const int32_t InputMapperTest::DEVICE_ID = 1;
const uint32_t InputMapperTest::DEVICE_CLASSES = 0; // not needed for current tests
// --- SwitchInputMapperTest ---