Merge "Joystick tweaks. (DO NOT MERGE)" into honeycomb-mr1

This commit is contained in:
Jeff Brown
2011-03-07 11:47:58 -08:00
committed by Android (Google) Code Review
16 changed files with 601 additions and 69 deletions

View File

@ -218115,6 +218115,28 @@
visibility="public" visibility="public"
> >
</field> </field>
<field name="AXIS_BRAKE"
type="int"
transient="false"
volatile="false"
value="23"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="AXIS_GAS"
type="int"
transient="false"
volatile="false"
value="22"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="AXIS_GENERIC_1" <field name="AXIS_GENERIC_1"
type="int" type="int"
transient="false" transient="false"
@ -218368,6 +218390,17 @@
visibility="public" visibility="public"
> >
</field> </field>
<field name="AXIS_RUDDER"
type="int"
transient="false"
volatile="false"
value="20"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="AXIS_RX" <field name="AXIS_RX"
type="int" type="int"
transient="false" transient="false"
@ -218412,6 +218445,17 @@
visibility="public" visibility="public"
> >
</field> </field>
<field name="AXIS_THROTTLE"
type="int"
transient="false"
volatile="false"
value="19"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="AXIS_TOOL_MAJOR" <field name="AXIS_TOOL_MAJOR"
type="int" type="int"
transient="false" transient="false"
@ -218467,6 +218511,17 @@
visibility="public" visibility="public"
> >
</field> </field>
<field name="AXIS_WHEEL"
type="int"
transient="false"
volatile="false"
value="21"
static="true"
final="true"
deprecated="not deprecated"
visibility="public"
>
</field>
<field name="AXIS_X" <field name="AXIS_X"
type="int" type="int"
transient="false" transient="false"

View File

@ -674,6 +674,87 @@ public final class MotionEvent extends InputEvent implements Parcelable {
*/ */
public static final int AXIS_RTRIGGER = 18; public static final int AXIS_RTRIGGER = 18;
/**
* Constant used to identify the Throttle axis of a motion event.
* <p>
* <ul>
* <li>For a joystick, reports the absolute position of the throttle control.
* The value is normalized to a range from 0.0 (fully open) to 1.0 (fully closed).
* </ul>
* </p>
*
* @see #getAxisValue(int, int)
* @see #getHistoricalAxisValue(int, int, int)
* @see MotionEvent.PointerCoords#getAxisValue(int)
* @see InputDevice#getMotionRange
*/
public static final int AXIS_THROTTLE = 19;
/**
* Constant used to identify the Rudder axis of a motion event.
* <p>
* <ul>
* <li>For a joystick, reports the absolute position of the rudder control.
* The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
* </ul>
* </p>
*
* @see #getAxisValue(int, int)
* @see #getHistoricalAxisValue(int, int, int)
* @see MotionEvent.PointerCoords#getAxisValue(int)
* @see InputDevice#getMotionRange
*/
public static final int AXIS_RUDDER = 20;
/**
* Constant used to identify the Wheel axis of a motion event.
* <p>
* <ul>
* <li>For a joystick, reports the absolute position of the steering wheel control.
* The value is normalized to a range from -1.0 (turn left) to 1.0 (turn right).
* </ul>
* </p>
*
* @see #getAxisValue(int, int)
* @see #getHistoricalAxisValue(int, int, int)
* @see MotionEvent.PointerCoords#getAxisValue(int)
* @see InputDevice#getMotionRange
*/
public static final int AXIS_WHEEL = 21;
/**
* Constant used to identify the Gas axis of a motion event.
* <p>
* <ul>
* <li>For a joystick, reports the absolute position of the gas (accelerator) control.
* The value is normalized to a range from 0.0 (no acceleration)
* to 1.0 (maximum acceleration).
* </ul>
* </p>
*
* @see #getAxisValue(int, int)
* @see #getHistoricalAxisValue(int, int, int)
* @see MotionEvent.PointerCoords#getAxisValue(int)
* @see InputDevice#getMotionRange
*/
public static final int AXIS_GAS = 22;
/**
* Constant used to identify the Brake axis of a motion event.
* <p>
* <ul>
* <li>For a joystick, reports the absolute position of the brake control.
* The value is normalized to a range from 0.0 (no braking) to 1.0 (maximum braking).
* </ul>
* </p>
*
* @see #getAxisValue(int, int)
* @see #getHistoricalAxisValue(int, int, int)
* @see MotionEvent.PointerCoords#getAxisValue(int)
* @see InputDevice#getMotionRange
*/
public static final int AXIS_BRAKE = 23;
/** /**
* Constant used to identify the Generic 1 axis of a motion event. * Constant used to identify the Generic 1 axis of a motion event.
* The interpretation of a generic axis is device-specific. * The interpretation of a generic axis is device-specific.
@ -877,6 +958,11 @@ public final class MotionEvent extends InputEvent implements Parcelable {
names.append(AXIS_HAT_Y, "AXIS_HAT_Y"); names.append(AXIS_HAT_Y, "AXIS_HAT_Y");
names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER"); names.append(AXIS_LTRIGGER, "AXIS_LTRIGGER");
names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER"); names.append(AXIS_RTRIGGER, "AXIS_RTRIGGER");
names.append(AXIS_THROTTLE, "AXIS_THROTTLE");
names.append(AXIS_RUDDER, "AXIS_RUDDER");
names.append(AXIS_WHEEL, "AXIS_WHEEL");
names.append(AXIS_GAS, "AXIS_GAS");
names.append(AXIS_BRAKE, "AXIS_BRAKE");
names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1"); names.append(AXIS_GENERIC_1, "AXIS_GENERIC_1");
names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2"); names.append(AXIS_GENERIC_2, "AXIS_GENERIC_2");
names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3");

View File

@ -409,6 +409,10 @@ axis 0x02 Z
axis 0x03 RX axis 0x03 RX
axis 0x04 RY axis 0x04 RY
axis 0x05 RZ axis 0x05 RZ
axis 0x06 THROTTLE
axis 0x07 RUDDER
axis 0x08 WHEEL
axis 0x09 GAS
axis 0x0a BRAKE
axis 0x10 HAT_X axis 0x10 HAT_X
axis 0x11 HAT_Y axis 0x11 HAT_Y

View File

@ -0,0 +1,46 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# XBox 360 USB Controller
#
key 304 BUTTON_A
key 305 BUTTON_B
key 307 BUTTON_X
key 308 BUTTON_Y
key 310 BUTTON_L1
key 311 BUTTON_R1
key 314 BUTTON_SELECT
key 315 BUTTON_START
key 316 BUTTON_MODE
key 317 BUTTON_THUMBL
key 318 BUTTON_THUMBR
# Left and right stick.
# The reported value for flat is 128 out of a range from -32767 to 32768, which is absurd.
# This confuses applications that rely on the flat value because the joystick actually
# settles in a flat range of +/- 4096 or so.
axis 0x00 X flat 4096
axis 0x01 Y flat 4096
axis 0x03 Z flat 4096
axis 0x04 RZ flat 4096
# Triggers.
axis 0x02 LTRIGGER
axis 0x05 RTRIGGER
# Hat.
axis 0x10 HAT_X
axis 0x11 HAT_Y

View File

@ -0,0 +1,53 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Logitech G25 Racing Wheel (in Compatibility Mode)
#
# 4 way buttons above hat
key 0x121 BUTTON_A
key 0x123 BUTTON_B
key 0x120 BUTTON_X
key 0x122 BUTTON_Y
# Row of buttons under hat
key 0x12b BUTTON_1
key 0x128 BUTTON_2
key 0x129 BUTTON_3
key 0x12a BUTTON_4
# Gear shift positions
# 0x12a top-left gear (aliased as BUTTON_4)
# 0x12b bottom-left gear (aliased as BUTTON_1)
# Buttons on wheel
key 0x127 BUTTON_L1
key 0x126 BUTTON_R1
# Toggles under wheel
key 0x125 BUTTON_L2
key 0x124 BUTTON_R2
# Hat
axis 0x10 HAT_X
axis 0x11 HAT_Y
# Steering Wheel
axis 0x00 WHEEL
# Accelerator / Brake
# 00..7e : accelerator
# 80..ff : brake
axis 0x01 split 0x7f GAS BRAKE

View File

@ -0,0 +1,62 @@
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Logitech G25 Racing Wheel (in Native Mode)
#
# 4 way buttons above hat
key 0x121 BUTTON_A
key 0x123 BUTTON_B
key 0x120 BUTTON_X
key 0x122 BUTTON_Y
# Row of buttons under hat
key 0x12b BUTTON_1
key 0x128 BUTTON_2
key 0x129 BUTTON_3
key 0x12a BUTTON_4
# Gear shift positions
key 0x12c BUTTON_5
key 0x12d BUTTON_6
key 0x12e BUTTON_7
key 0x12f BUTTON_8
key 0x2d0 BUTTON_9
key 0x2d1 BUTTON_10
key 0x2d2 BUTTON_11
# Buttons on wheel
key 0x127 BUTTON_L1
key 0x126 BUTTON_R1
# Toggles under wheel
key 0x125 BUTTON_L2
key 0x124 BUTTON_R2
# Hat
axis 0x10 HAT_X
axis 0x11 HAT_Y
# Steering Wheel
axis 0x00 WHEEL
# Clutch
axis 0x01 invert GENERIC_1
# Accelerator
axis 0x02 invert GAS
# Brake
axis 0x05 invert BRAKE

View File

@ -19,7 +19,10 @@ keylayouts := \
Generic.kl \ Generic.kl \
AVRCP.kl \ AVRCP.kl \
qwerty.kl \ qwerty.kl \
Vendor_045e_Product_028e.kl \
Vendor_046d_Product_c216.kl \ Vendor_046d_Product_c216.kl \
Vendor_046d_Product_c294.kl \
Vendor_046d_Product_c299.kl \
Vendor_046d_Product_c532.kl \ Vendor_046d_Product_c532.kl \
Vendor_054c_Product_0268.kl \ Vendor_054c_Product_0268.kl \
Vendor_05ac_Product_0239.kl \ Vendor_05ac_Product_0239.kl \

View File

@ -24,6 +24,36 @@
namespace android { namespace android {
struct AxisInfo {
enum Mode {
// Axis value is reported directly.
MODE_NORMAL = 0,
// Axis value should be inverted before reporting.
MODE_INVERT = 1,
// Axis value should be split into two axes
MODE_SPLIT = 2,
};
// Axis mode.
Mode mode;
// Axis id.
// When split, this is the axis used for values smaller than the split position.
int32_t axis;
// When split, this is the axis used for values after higher than the split position.
int32_t highAxis;
// The split value, or 0 if not split.
int32_t splitValue;
// The flat value, or -1 if none.
int32_t flatOverride;
AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) {
}
};
/** /**
* Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes.
*/ */
@ -36,7 +66,7 @@ public:
status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const; status_t mapKey(int32_t scanCode, int32_t* keyCode, uint32_t* flags) const;
status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const; status_t findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const;
status_t mapAxis(int32_t scanCode, int32_t* axis) const; status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const;
private: private:
struct Key { struct Key {
@ -45,7 +75,7 @@ private:
}; };
KeyedVector<int32_t, Key> mKeys; KeyedVector<int32_t, Key> mKeys;
KeyedVector<int32_t, int32_t> mAxes; KeyedVector<int32_t, AxisInfo> mAxes;
KeyLayoutMap(); KeyLayoutMap();

View File

@ -270,6 +270,11 @@ static const KeycodeLabel AXES[] = {
{ "HAT_Y", 16 }, { "HAT_Y", 16 },
{ "LTRIGGER", 17 }, { "LTRIGGER", 17 },
{ "RTRIGGER", 18 }, { "RTRIGGER", 18 },
{ "THROTTLE", 19 },
{ "RUDDER", 20 },
{ "WHEEL", 21 },
{ "GAS", 22 },
{ "BRAKE", 23 },
{ "GENERIC_1", 32 }, { "GENERIC_1", 32 },
{ "GENERIC_2", 33 }, { "GENERIC_2", 33 },
{ "GENERIC_3", 34 }, { "GENERIC_3", 34 },

View File

@ -113,20 +113,23 @@ status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* out
return NO_ERROR; return NO_ERROR;
} }
status_t KeyLayoutMap::mapAxis(int32_t scanCode, int32_t* axis) const { status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const {
ssize_t index = mAxes.indexOfKey(scanCode); ssize_t index = mAxes.indexOfKey(scanCode);
if (index < 0) { if (index < 0) {
#if DEBUG_MAPPING #if DEBUG_MAPPING
LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode);
#endif #endif
*axis = -1;
return NAME_NOT_FOUND; return NAME_NOT_FOUND;
} }
*axis = mAxes.valueAt(index); *outAxisInfo = mAxes.valueAt(index);
#if DEBUG_MAPPING #if DEBUG_MAPPING
LOGD("mapAxis: scanCode=%d ~ Result axis=%d.", scanCode, *axis); LOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, "
"splitValue=%d, flatOverride=%d.",
scanCode,
outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis,
outAxisInfo->splitValue, outAxisInfo->flatOverride);
#endif #endif
return NO_ERROR; return NO_ERROR;
} }
@ -249,19 +252,89 @@ status_t KeyLayoutMap::Parser::parseAxis() {
return BAD_VALUE; return BAD_VALUE;
} }
AxisInfo axisInfo;
mTokenizer->skipDelimiters(WHITESPACE);
String8 token = mTokenizer->nextToken(WHITESPACE);
if (token == "invert") {
axisInfo.mode = AxisInfo::MODE_INVERT;
mTokenizer->skipDelimiters(WHITESPACE); mTokenizer->skipDelimiters(WHITESPACE);
String8 axisToken = mTokenizer->nextToken(WHITESPACE); String8 axisToken = mTokenizer->nextToken(WHITESPACE);
int32_t axis = getAxisByLabel(axisToken.string()); axisInfo.axis = getAxisByLabel(axisToken.string());
if (axis < 0) { if (axisInfo.axis < 0) {
LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(), LOGE("%s: Expected inverted axis label, got '%s'.",
axisToken.string()); mTokenizer->getLocation().string(), axisToken.string());
return BAD_VALUE;
}
} else if (token == "split") {
axisInfo.mode = AxisInfo::MODE_SPLIT;
mTokenizer->skipDelimiters(WHITESPACE);
String8 splitToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0));
if (*end) {
LOGE("%s: Expected split value, got '%s'.",
mTokenizer->getLocation().string(), splitToken.string());
return BAD_VALUE; return BAD_VALUE;
} }
mTokenizer->skipDelimiters(WHITESPACE);
String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.axis = getAxisByLabel(lowAxisToken.string());
if (axisInfo.axis < 0) {
LOGE("%s: Expected low axis label, got '%s'.",
mTokenizer->getLocation().string(), lowAxisToken.string());
return BAD_VALUE;
}
mTokenizer->skipDelimiters(WHITESPACE);
String8 highAxisToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.highAxis = getAxisByLabel(highAxisToken.string());
if (axisInfo.highAxis < 0) {
LOGE("%s: Expected high axis label, got '%s'.",
mTokenizer->getLocation().string(), highAxisToken.string());
return BAD_VALUE;
}
} else {
axisInfo.axis = getAxisByLabel(token.string());
if (axisInfo.axis < 0) {
LOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.",
mTokenizer->getLocation().string(), token.string());
return BAD_VALUE;
}
}
for (;;) {
mTokenizer->skipDelimiters(WHITESPACE);
if (mTokenizer->isEol()) {
break;
}
String8 keywordToken = mTokenizer->nextToken(WHITESPACE);
if (keywordToken == "flat") {
mTokenizer->skipDelimiters(WHITESPACE);
String8 flatToken = mTokenizer->nextToken(WHITESPACE);
axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0));
if (*end) {
LOGE("%s: Expected flat value, got '%s'.",
mTokenizer->getLocation().string(), flatToken.string());
return BAD_VALUE;
}
} else {
LOGE("%s: Expected keyword 'flat', got '%s'.",
mTokenizer->getLocation().string(), keywordToken.string());
return BAD_VALUE;
}
}
#if DEBUG_PARSER #if DEBUG_PARSER
LOGD("Parsed axis: scanCode=%d, axis=%d.", scanCode, axis); LOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, "
"splitValue=%d, flatOverride=%d.",
scanCode,
axisInfo.mode, axisInfo.axis, axisInfo.highAxis,
axisInfo.splitValue, axisInfo.flatOverride);
#endif #endif
mMap->mAxes.add(scanCode, axis); mMap->mAxes.add(scanCode, axisInfo);
return NO_ERROR; return NO_ERROR;
} }

View File

@ -359,6 +359,11 @@ enum {
AMOTION_EVENT_AXIS_HAT_Y = 16, AMOTION_EVENT_AXIS_HAT_Y = 16,
AMOTION_EVENT_AXIS_LTRIGGER = 17, AMOTION_EVENT_AXIS_LTRIGGER = 17,
AMOTION_EVENT_AXIS_RTRIGGER = 18, AMOTION_EVENT_AXIS_RTRIGGER = 18,
AMOTION_EVENT_AXIS_THROTTLE = 19,
AMOTION_EVENT_AXIS_RUDDER = 20,
AMOTION_EVENT_AXIS_WHEEL = 21,
AMOTION_EVENT_AXIS_GAS = 22,
AMOTION_EVENT_AXIS_BRAKE = 23,
AMOTION_EVENT_AXIS_GENERIC_1 = 32, AMOTION_EVENT_AXIS_GENERIC_1 = 32,
AMOTION_EVENT_AXIS_GENERIC_2 = 33, AMOTION_EVENT_AXIS_GENERIC_2 = 33,
AMOTION_EVENT_AXIS_GENERIC_3 = 34, AMOTION_EVENT_AXIS_GENERIC_3 = 34,

View File

@ -352,14 +352,13 @@ status_t EventHub::mapKey(int32_t deviceId, int scancode,
return NAME_NOT_FOUND; return NAME_NOT_FOUND;
} }
status_t EventHub::mapAxis(int32_t deviceId, int scancode, status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const
int32_t* outAxis) const
{ {
AutoMutex _l(mLock); AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId); Device* device = getDeviceLocked(deviceId);
if (device && device->keyMap.haveKeyLayout()) { if (device && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis); status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
if (err == NO_ERROR) { if (err == NO_ERROR) {
return NO_ERROR; return NO_ERROR;
} }
@ -369,14 +368,13 @@ status_t EventHub::mapAxis(int32_t deviceId, int scancode,
device = getDeviceLocked(mBuiltInKeyboardId); device = getDeviceLocked(mBuiltInKeyboardId);
if (device && device->keyMap.haveKeyLayout()) { if (device && device->keyMap.haveKeyLayout()) {
status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxis); status_t err = device->keyMap.keyLayoutMap->mapAxis(scancode, outAxisInfo);
if (err == NO_ERROR) { if (err == NO_ERROR) {
return NO_ERROR; return NO_ERROR;
} }
} }
} }
*outAxis = -1;
return NAME_NOT_FOUND; return NAME_NOT_FOUND;
} }

View File

@ -176,7 +176,7 @@ public:
int32_t* outKeycode, uint32_t* outFlags) const = 0; int32_t* outKeycode, uint32_t* outFlags) const = 0;
virtual status_t mapAxis(int32_t deviceId, int scancode, virtual status_t mapAxis(int32_t deviceId, int scancode,
int32_t* outAxis) const = 0; AxisInfo* outAxisInfo) const = 0;
// exclude a particular device from opening // exclude a particular device from opening
// this can be used to ignore input devices for sensors // this can be used to ignore input devices for sensors
@ -235,7 +235,7 @@ public:
int32_t* outKeycode, uint32_t* outFlags) const; int32_t* outKeycode, uint32_t* outFlags) const;
virtual status_t mapAxis(int32_t deviceId, int scancode, virtual status_t mapAxis(int32_t deviceId, int scancode,
int32_t* outAxis) const; AxisInfo* outAxisInfo) const;
virtual void addExcludedDevice(const char* deviceName); virtual void addExcludedDevice(const char* deviceName);

View File

@ -3854,7 +3854,10 @@ void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
for (size_t i = 0; i < mAxes.size(); i++) { for (size_t i = 0; i < mAxes.size(); i++) {
const Axis& axis = mAxes.valueAt(i); const Axis& axis = mAxes.valueAt(i);
info->addMotionRange(axis.axis, axis.min, axis.max, axis.flat, axis.fuzz); info->addMotionRange(axis.axisInfo.axis, axis.min, axis.max, axis.flat, axis.fuzz);
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
info->addMotionRange(axis.axisInfo.highAxis, axis.min, axis.max, axis.flat, axis.fuzz);
}
} }
} }
@ -3865,18 +3868,29 @@ void JoystickInputMapper::dump(String8& dump) {
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
const Axis& axis = mAxes.valueAt(i); const Axis& axis = mAxes.valueAt(i);
const char* label = getAxisLabel(axis.axis); const char* label = getAxisLabel(axis.axisInfo.axis);
char name[32];
if (label) { if (label) {
strncpy(name, label, sizeof(name)); dump.appendFormat(INDENT4 "%s", label);
name[sizeof(name) - 1] = '\0';
} else { } else {
snprintf(name, sizeof(name), "%d", axis.axis); dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
} }
dump.appendFormat(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, " if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
"scale=%0.3f, offset=%0.3f\n", label = getAxisLabel(axis.axisInfo.highAxis);
name, axis.min, axis.max, axis.flat, axis.fuzz, if (label) {
axis.scale, axis.offset); dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
} else {
dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
axis.axisInfo.splitValue);
}
} else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
dump.append(" (invert)");
}
dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f\n",
axis.min, axis.max, axis.flat, axis.fuzz);
dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, "
"highScale=%0.5f, highOffset=%0.5f\n",
axis.scale, axis.offset, axis.highScale, axis.highOffset);
dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n", dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, rawFlat=%d, rawFuzz=%d\n",
mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz); axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz);
@ -3891,25 +3905,38 @@ void JoystickInputMapper::configure() {
RawAbsoluteAxisInfo rawAxisInfo; RawAbsoluteAxisInfo rawAxisInfo;
getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo); getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo);
if (rawAxisInfo.valid) { if (rawAxisInfo.valid) {
int32_t axisId; // Map axis.
bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId); AxisInfo axisInfo;
bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo);
if (!explicitlyMapped) { if (!explicitlyMapped) {
// Axis is not explicitly mapped, will choose a generic axis later. // Axis is not explicitly mapped, will choose a generic axis later.
axisId = -1; axisInfo.mode = AxisInfo::MODE_NORMAL;
axisInfo.axis = -1;
} }
// Apply flat override.
int32_t rawFlat = axisInfo.flatOverride < 0
? rawAxisInfo.flat : axisInfo.flatOverride;
// Calculate scaling factors and limits.
Axis axis; Axis axis;
if (isCenteredAxis(axisId)) { if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
scale, 0.0f, highScale, 0.0f,
0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
} else if (isCenteredAxis(axisInfo.axis)) {
float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
axis.initialize(rawAxisInfo, axisId, explicitlyMapped, axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
scale, offset, -1.0f, 1.0f, scale, offset, scale, offset,
rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
} else { } else {
float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
axis.initialize(rawAxisInfo, axisId, explicitlyMapped, axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped,
scale, 0.0f, 0.0f, 1.0f, scale, 0.0f, scale, 0.0f,
rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale);
} }
// To eliminate noise while the joystick is at rest, filter out small variations // To eliminate noise while the joystick is at rest, filter out small variations
@ -3934,14 +3961,14 @@ void JoystickInputMapper::configure() {
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
Axis& axis = mAxes.editValueAt(i); Axis& axis = mAxes.editValueAt(i);
if (axis.axis < 0) { if (axis.axisInfo.axis < 0) {
while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16
&& haveAxis(nextGenericAxisId)) { && haveAxis(nextGenericAxisId)) {
nextGenericAxisId += 1; nextGenericAxisId += 1;
} }
if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) {
axis.axis = nextGenericAxisId; axis.axisInfo.axis = nextGenericAxisId;
nextGenericAxisId += 1; nextGenericAxisId += 1;
} else { } else {
LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " LOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids "
@ -3954,10 +3981,13 @@ void JoystickInputMapper::configure() {
} }
} }
bool JoystickInputMapper::haveAxis(int32_t axis) { bool JoystickInputMapper::haveAxis(int32_t axisId) {
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
if (mAxes.valueAt(i).axis == axis) { const Axis& axis = mAxes.valueAt(i);
if (axis.axisInfo.axis == axisId
|| (axis.axisInfo.mode == AxisInfo::MODE_SPLIT
&& axis.axisInfo.highAxis == axisId)) {
return true; return true;
} }
} }
@ -3987,6 +4017,8 @@ bool JoystickInputMapper::isCenteredAxis(int32_t axis) {
case AMOTION_EVENT_AXIS_HAT_X: case AMOTION_EVENT_AXIS_HAT_X:
case AMOTION_EVENT_AXIS_HAT_Y: case AMOTION_EVENT_AXIS_HAT_Y:
case AMOTION_EVENT_AXIS_ORIENTATION: case AMOTION_EVENT_AXIS_ORIENTATION:
case AMOTION_EVENT_AXIS_RUDDER:
case AMOTION_EVENT_AXIS_WHEEL:
return true; return true;
default: default:
return false; return false;
@ -4000,7 +4032,7 @@ void JoystickInputMapper::reset() {
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
Axis& axis = mAxes.editValueAt(i); Axis& axis = mAxes.editValueAt(i);
axis.newValue = 0; axis.resetValue();
} }
sync(when, true /*force*/); sync(when, true /*force*/);
@ -4014,10 +4046,34 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) {
ssize_t index = mAxes.indexOfKey(rawEvent->scanCode); ssize_t index = mAxes.indexOfKey(rawEvent->scanCode);
if (index >= 0) { if (index >= 0) {
Axis& axis = mAxes.editValueAt(index); Axis& axis = mAxes.editValueAt(index);
float newValue = rawEvent->value * axis.scale + axis.offset; float newValue, highNewValue;
if (newValue != axis.newValue) { switch (axis.axisInfo.mode) {
axis.newValue = newValue; case AxisInfo::MODE_INVERT:
newValue = (axis.rawAxisInfo.maxValue - rawEvent->value)
* axis.scale + axis.offset;
highNewValue = 0.0f;
break;
case AxisInfo::MODE_SPLIT:
if (rawEvent->value < axis.axisInfo.splitValue) {
newValue = (axis.axisInfo.splitValue - rawEvent->value)
* axis.scale + axis.offset;
highNewValue = 0.0f;
} else if (rawEvent->value > axis.axisInfo.splitValue) {
newValue = 0.0f;
highNewValue = (rawEvent->value - axis.axisInfo.splitValue)
* axis.highScale + axis.highOffset;
} else {
newValue = 0.0f;
highNewValue = 0.0f;
} }
break;
default:
newValue = rawEvent->value * axis.scale + axis.offset;
highNewValue = 0.0f;
break;
}
axis.newValue = newValue;
axis.highNewValue = highNewValue;
} }
break; break;
} }
@ -4033,7 +4089,7 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) {
} }
void JoystickInputMapper::sync(nsecs_t when, bool force) { void JoystickInputMapper::sync(nsecs_t when, bool force) {
if (!force && !haveAxesChangedSignificantly()) { if (!filterAxes(force)) {
return; return;
} }
@ -4044,9 +4100,11 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) {
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
Axis& axis = mAxes.editValueAt(i); const Axis& axis = mAxes.valueAt(i);
pointerCoords.setAxisValue(axis.axis, axis.newValue); pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue);
axis.oldValue = axis.newValue; if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
pointerCoords.setAxisValue(axis.axisInfo.highAxis, axis.highCurrentValue);
}
} }
// Moving a joystick axis should not wake the devide because joysticks can // Moving a joystick axis should not wake the devide because joysticks can
@ -4061,12 +4119,49 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) {
1, &pointerId, &pointerCoords, 0, 0, 0); 1, &pointerId, &pointerCoords, 0, 0, 0);
} }
bool JoystickInputMapper::haveAxesChangedSignificantly() { bool JoystickInputMapper::filterAxes(bool force) {
bool atLeastOneSignificantChange = force;
size_t numAxes = mAxes.size(); size_t numAxes = mAxes.size();
for (size_t i = 0; i < numAxes; i++) { for (size_t i = 0; i < numAxes; i++) {
const Axis& axis = mAxes.valueAt(i); Axis& axis = mAxes.editValueAt(i);
if (axis.newValue != axis.oldValue if (force || hasValueChangedSignificantly(axis.filter,
&& fabs(axis.newValue - axis.oldValue) > axis.filter) { axis.newValue, axis.currentValue, axis.min, axis.max)) {
axis.currentValue = axis.newValue;
atLeastOneSignificantChange = true;
}
if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
if (force || hasValueChangedSignificantly(axis.filter,
axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) {
axis.highCurrentValue = axis.highNewValue;
atLeastOneSignificantChange = true;
}
}
}
return atLeastOneSignificantChange;
}
bool JoystickInputMapper::hasValueChangedSignificantly(
float filter, float newValue, float currentValue, float min, float max) {
if (newValue != currentValue) {
// Filter out small changes in value unless the value is converging on the axis
// bounds or center point. This is intended to reduce the amount of information
// sent to applications by particularly noisy joysticks (such as PS3).
if (fabs(newValue - currentValue) > filter
|| hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min)
|| hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max)
|| hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) {
return true;
}
}
return false;
}
bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(
float filter, float newValue, float currentValue, float thresholdValue) {
float newDistance = fabs(newValue - thresholdValue);
if (newDistance < filter) {
float oldDistance = fabs(currentValue - thresholdValue);
if (newDistance < oldDistance) {
return true; return true;
} }
} }

View File

@ -1011,38 +1011,50 @@ public:
private: private:
struct Axis { struct Axis {
RawAbsoluteAxisInfo rawAxisInfo; RawAbsoluteAxisInfo rawAxisInfo;
AxisInfo axisInfo;
int32_t axis; // axis id
bool explicitlyMapped; // true if the axis was explicitly assigned an axis id bool explicitlyMapped; // true if the axis was explicitly assigned an axis id
float scale; // scale factor from raw to normalized values float scale; // scale factor from raw to normalized values
float offset; // offset to add after scaling for normalization float offset; // offset to add after scaling for normalization
float highScale; // scale factor from raw to normalized values of high split
float highOffset; // offset to add after scaling for normalization of high split
float min; // normalized inclusive minimum float min; // normalized inclusive minimum
float max; // normalized inclusive maximum float max; // normalized inclusive maximum
float flat; // normalized flat region size float flat; // normalized flat region size
float fuzz; // normalized error tolerance float fuzz; // normalized error tolerance
float oldValue; // previous value
float newValue; // most recent value
float filter; // filter out small variations of this size float filter; // filter out small variations of this size
float currentValue; // current value
float newValue; // most recent value
float highCurrentValue; // current value of high split
float highNewValue; // most recent value of high split
void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo,
int32_t axis, bool explicitlyMapped, float scale, float offset, bool explicitlyMapped, float scale, float offset,
float highScale, float highOffset,
float min, float max, float flat, float fuzz) { float min, float max, float flat, float fuzz) {
this->rawAxisInfo = rawAxisInfo; this->rawAxisInfo = rawAxisInfo;
this->axis = axis; this->axisInfo = axisInfo;
this->explicitlyMapped = explicitlyMapped; this->explicitlyMapped = explicitlyMapped;
this->scale = scale; this->scale = scale;
this->offset = offset; this->offset = offset;
this->highScale = highScale;
this->highOffset = highOffset;
this->min = min; this->min = min;
this->max = max; this->max = max;
this->flat = flat; this->flat = flat;
this->fuzz = fuzz; this->fuzz = fuzz;
this->filter = 0; this->filter = 0;
this->oldValue = 0; resetValue();
}
void resetValue() {
this->currentValue = 0;
this->newValue = 0; this->newValue = 0;
this->highCurrentValue = 0;
this->highNewValue = 0;
} }
}; };
@ -1051,9 +1063,14 @@ private:
void sync(nsecs_t when, bool force); void sync(nsecs_t when, bool force);
bool haveAxis(int32_t axis); bool haveAxis(int32_t axisId);
void pruneAxes(bool ignoreExplicitlyMappedAxes); void pruneAxes(bool ignoreExplicitlyMappedAxes);
bool haveAxesChangedSignificantly(); bool filterAxes(bool force);
static bool hasValueChangedSignificantly(float filter,
float newValue, float currentValue, float min, float max);
static bool hasMovedNearerToValueWithinFilteredRange(float filter,
float newValue, float currentValue, float thresholdValue);
static bool isCenteredAxis(int32_t axis); static bool isCenteredAxis(int32_t axis);
}; };

View File

@ -592,7 +592,7 @@ private:
} }
virtual status_t mapAxis(int32_t deviceId, int scancode, virtual status_t mapAxis(int32_t deviceId, int scancode,
int32_t* outAxis) const { AxisInfo* outAxisInfo) const {
return NAME_NOT_FOUND; return NAME_NOT_FOUND;
} }