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:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 ---
|
||||
|
||||
Reference in New Issue
Block a user