diff options
-rw-r--r-- | api/current.xml | 55 | ||||
-rw-r--r-- | core/java/android/view/MotionEvent.java | 86 | ||||
-rw-r--r-- | data/keyboards/Generic.kl | 6 | ||||
-rw-r--r-- | data/keyboards/Vendor_045e_Product_028e.kl | 46 | ||||
-rw-r--r-- | data/keyboards/Vendor_046d_Product_c294.kl | 53 | ||||
-rw-r--r-- | data/keyboards/Vendor_046d_Product_c299.kl | 62 | ||||
-rw-r--r-- | data/keyboards/common.mk | 3 | ||||
-rw-r--r-- | include/ui/KeyLayoutMap.h | 34 | ||||
-rwxr-xr-x | include/ui/KeycodeLabels.h | 5 | ||||
-rw-r--r-- | libs/ui/KeyLayoutMap.cpp | 97 | ||||
-rw-r--r-- | native/include/android/input.h | 5 | ||||
-rw-r--r-- | services/input/EventHub.cpp | 8 | ||||
-rw-r--r-- | services/input/EventHub.h | 4 | ||||
-rw-r--r-- | services/input/InputReader.cpp | 167 | ||||
-rw-r--r-- | services/input/InputReader.h | 37 | ||||
-rw-r--r-- | services/input/tests/InputReader_test.cpp | 2 |
16 files changed, 601 insertions, 69 deletions
diff --git a/api/current.xml b/api/current.xml index 422522e..142ff2b 100644 --- a/api/current.xml +++ b/api/current.xml @@ -218115,6 +218115,28 @@ visibility="public" > </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" type="int" transient="false" @@ -218368,6 +218390,17 @@ visibility="public" > </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" type="int" transient="false" @@ -218412,6 +218445,17 @@ visibility="public" > </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" type="int" transient="false" @@ -218467,6 +218511,17 @@ visibility="public" > </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" type="int" transient="false" diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 076f712..3c39149 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -675,6 +675,87 @@ public final class MotionEvent extends InputEvent implements Parcelable { 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. * 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_LTRIGGER, "AXIS_LTRIGGER"); 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_2, "AXIS_GENERIC_2"); names.append(AXIS_GENERIC_3, "AXIS_GENERIC_3"); diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl index 6d925d6..1428b63 100644 --- a/data/keyboards/Generic.kl +++ b/data/keyboards/Generic.kl @@ -409,6 +409,10 @@ axis 0x02 Z axis 0x03 RX axis 0x04 RY axis 0x05 RZ +axis 0x06 THROTTLE +axis 0x07 RUDDER +axis 0x08 WHEEL +axis 0x09 GAS +axis 0x0a BRAKE axis 0x10 HAT_X axis 0x11 HAT_Y -
\ No newline at end of file diff --git a/data/keyboards/Vendor_045e_Product_028e.kl b/data/keyboards/Vendor_045e_Product_028e.kl new file mode 100644 index 0000000..99f046a --- /dev/null +++ b/data/keyboards/Vendor_045e_Product_028e.kl @@ -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 diff --git a/data/keyboards/Vendor_046d_Product_c294.kl b/data/keyboards/Vendor_046d_Product_c294.kl new file mode 100644 index 0000000..5492f49 --- /dev/null +++ b/data/keyboards/Vendor_046d_Product_c294.kl @@ -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 diff --git a/data/keyboards/Vendor_046d_Product_c299.kl b/data/keyboards/Vendor_046d_Product_c299.kl new file mode 100644 index 0000000..d42963d --- /dev/null +++ b/data/keyboards/Vendor_046d_Product_c299.kl @@ -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 diff --git a/data/keyboards/common.mk b/data/keyboards/common.mk index 5b367b9..335298c 100644 --- a/data/keyboards/common.mk +++ b/data/keyboards/common.mk @@ -19,7 +19,10 @@ keylayouts := \ Generic.kl \ AVRCP.kl \ qwerty.kl \ + Vendor_045e_Product_028e.kl \ Vendor_046d_Product_c216.kl \ + Vendor_046d_Product_c294.kl \ + Vendor_046d_Product_c299.kl \ Vendor_046d_Product_c532.kl \ Vendor_054c_Product_0268.kl \ Vendor_05ac_Product_0239.kl \ diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h index 904c8f3..d82d0c8 100644 --- a/include/ui/KeyLayoutMap.h +++ b/include/ui/KeyLayoutMap.h @@ -24,6 +24,36 @@ 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. */ @@ -36,7 +66,7 @@ public: 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 mapAxis(int32_t scanCode, int32_t* axis) const; + status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const; private: struct Key { @@ -45,7 +75,7 @@ private: }; KeyedVector<int32_t, Key> mKeys; - KeyedVector<int32_t, int32_t> mAxes; + KeyedVector<int32_t, AxisInfo> mAxes; KeyLayoutMap(); diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index bdfbf7c..b912e9b 100755 --- a/include/ui/KeycodeLabels.h +++ b/include/ui/KeycodeLabels.h @@ -270,6 +270,11 @@ static const KeycodeLabel AXES[] = { { "HAT_Y", 16 }, { "LTRIGGER", 17 }, { "RTRIGGER", 18 }, + { "THROTTLE", 19 }, + { "RUDDER", 20 }, + { "WHEEL", 21 }, + { "GAS", 22 }, + { "BRAKE", 23 }, { "GENERIC_1", 32 }, { "GENERIC_2", 33 }, { "GENERIC_3", 34 }, diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/ui/KeyLayoutMap.cpp index 2ed0e66..8626a03 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -113,20 +113,23 @@ status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* out 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); if (index < 0) { #if DEBUG_MAPPING LOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); #endif - *axis = -1; return NAME_NOT_FOUND; } - *axis = mAxes.valueAt(index); + *outAxisInfo = mAxes.valueAt(index); #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 return NO_ERROR; } @@ -249,19 +252,89 @@ status_t KeyLayoutMap::Parser::parseAxis() { return BAD_VALUE; } + AxisInfo axisInfo; + mTokenizer->skipDelimiters(WHITESPACE); - String8 axisToken = mTokenizer->nextToken(WHITESPACE); - int32_t axis = getAxisByLabel(axisToken.string()); - if (axis < 0) { - LOGE("%s: Expected axis label, got '%s'.", mTokenizer->getLocation().string(), - axisToken.string()); - return BAD_VALUE; + String8 token = mTokenizer->nextToken(WHITESPACE); + if (token == "invert") { + axisInfo.mode = AxisInfo::MODE_INVERT; + + mTokenizer->skipDelimiters(WHITESPACE); + String8 axisToken = mTokenizer->nextToken(WHITESPACE); + axisInfo.axis = getAxisByLabel(axisToken.string()); + if (axisInfo.axis < 0) { + LOGE("%s: Expected inverted axis label, got '%s'.", + 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; + } + + 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 - 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 - mMap->mAxes.add(scanCode, axis); + mMap->mAxes.add(scanCode, axisInfo); return NO_ERROR; } diff --git a/native/include/android/input.h b/native/include/android/input.h index f19e8be..86be54a 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -359,6 +359,11 @@ enum { AMOTION_EVENT_AXIS_HAT_Y = 16, AMOTION_EVENT_AXIS_LTRIGGER = 17, 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_2 = 33, AMOTION_EVENT_AXIS_GENERIC_3 = 34, diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp index 2fe5980..e37a6b1 100644 --- a/services/input/EventHub.cpp +++ b/services/input/EventHub.cpp @@ -352,14 +352,13 @@ status_t EventHub::mapKey(int32_t deviceId, int scancode, return NAME_NOT_FOUND; } -status_t EventHub::mapAxis(int32_t deviceId, int scancode, - int32_t* outAxis) const +status_t EventHub::mapAxis(int32_t deviceId, int scancode, AxisInfo* outAxisInfo) const { AutoMutex _l(mLock); Device* device = getDeviceLocked(deviceId); 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) { return NO_ERROR; } @@ -369,14 +368,13 @@ status_t EventHub::mapAxis(int32_t deviceId, int scancode, device = getDeviceLocked(mBuiltInKeyboardId); 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) { return NO_ERROR; } } } - *outAxis = -1; return NAME_NOT_FOUND; } diff --git a/services/input/EventHub.h b/services/input/EventHub.h index 445c04b..ab42a1f 100644 --- a/services/input/EventHub.h +++ b/services/input/EventHub.h @@ -176,7 +176,7 @@ public: int32_t* outKeycode, uint32_t* outFlags) const = 0; virtual status_t mapAxis(int32_t deviceId, int scancode, - int32_t* outAxis) const = 0; + AxisInfo* outAxisInfo) const = 0; // exclude a particular device from opening // this can be used to ignore input devices for sensors @@ -235,7 +235,7 @@ public: int32_t* outKeycode, uint32_t* outFlags) const; virtual status_t mapAxis(int32_t deviceId, int scancode, - int32_t* outAxis) const; + AxisInfo* outAxisInfo) const; virtual void addExcludedDevice(const char* deviceName); diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index b92c3b5..00c3eb7 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -3854,7 +3854,10 @@ void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { for (size_t i = 0; i < mAxes.size(); 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(); for (size_t i = 0; i < numAxes; i++) { const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axis); - char name[32]; + const char* label = getAxisLabel(axis.axisInfo.axis); if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; + dump.appendFormat(INDENT4 "%s", label); } else { - snprintf(name, sizeof(name), "%d", axis.axis); + dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); + } + if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { + label = getAxisLabel(axis.axisInfo.highAxis); + if (label) { + 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(INDENT4 "%s: min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, " - "scale=%0.3f, offset=%0.3f\n", - name, axis.min, axis.max, axis.flat, axis.fuzz, - axis.scale, axis.offset); + + 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", mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz); @@ -3891,25 +3905,38 @@ void JoystickInputMapper::configure() { RawAbsoluteAxisInfo rawAxisInfo; getEventHub()->getAbsoluteAxisInfo(getDeviceId(), abs, &rawAxisInfo); if (rawAxisInfo.valid) { - int32_t axisId; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisId); + // Map axis. + AxisInfo axisInfo; + bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); if (!explicitlyMapped) { // 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; - 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 offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisId, explicitlyMapped, - scale, offset, -1.0f, 1.0f, - rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, offset, scale, offset, + -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } else { float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisId, explicitlyMapped, - scale, 0.0f, 0.0f, 1.0f, - rawAxisInfo.flat * scale, rawAxisInfo.fuzz * scale); + axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, + scale, 0.0f, scale, 0.0f, + 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale); } // 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(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); - if (axis.axis < 0) { + if (axis.axisInfo.axis < 0) { while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && haveAxis(nextGenericAxisId)) { nextGenericAxisId += 1; } if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axis = nextGenericAxisId; + axis.axisInfo.axis = nextGenericAxisId; nextGenericAxisId += 1; } else { 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(); 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; } } @@ -3987,6 +4017,8 @@ bool JoystickInputMapper::isCenteredAxis(int32_t axis) { case AMOTION_EVENT_AXIS_HAT_X: case AMOTION_EVENT_AXIS_HAT_Y: case AMOTION_EVENT_AXIS_ORIENTATION: + case AMOTION_EVENT_AXIS_RUDDER: + case AMOTION_EVENT_AXIS_WHEEL: return true; default: return false; @@ -4000,7 +4032,7 @@ void JoystickInputMapper::reset() { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { Axis& axis = mAxes.editValueAt(i); - axis.newValue = 0; + axis.resetValue(); } sync(when, true /*force*/); @@ -4014,10 +4046,34 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) { ssize_t index = mAxes.indexOfKey(rawEvent->scanCode); if (index >= 0) { Axis& axis = mAxes.editValueAt(index); - float newValue = rawEvent->value * axis.scale + axis.offset; - if (newValue != axis.newValue) { - axis.newValue = newValue; + float newValue, highNewValue; + switch (axis.axisInfo.mode) { + 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; } @@ -4033,7 +4089,7 @@ void JoystickInputMapper::process(const RawEvent* rawEvent) { } void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!force && !haveAxesChangedSignificantly()) { + if (!filterAxes(force)) { return; } @@ -4044,9 +4100,11 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - pointerCoords.setAxisValue(axis.axis, axis.newValue); - axis.oldValue = axis.newValue; + const Axis& axis = mAxes.valueAt(i); + pointerCoords.setAxisValue(axis.axisInfo.axis, axis.currentValue); + 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 @@ -4061,12 +4119,49 @@ void JoystickInputMapper::sync(nsecs_t when, bool force) { 1, &pointerId, &pointerCoords, 0, 0, 0); } -bool JoystickInputMapper::haveAxesChangedSignificantly() { +bool JoystickInputMapper::filterAxes(bool force) { + bool atLeastOneSignificantChange = force; size_t numAxes = mAxes.size(); for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.newValue != axis.oldValue - && fabs(axis.newValue - axis.oldValue) > axis.filter) { + Axis& axis = mAxes.editValueAt(i); + if (force || hasValueChangedSignificantly(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; } } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 655f0f0..e2cf08e 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -1011,38 +1011,50 @@ public: private: struct Axis { RawAbsoluteAxisInfo rawAxisInfo; + AxisInfo axisInfo; - int32_t axis; // axis id bool explicitlyMapped; // true if the axis was explicitly assigned an axis id float scale; // scale factor from raw to normalized values 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 max; // normalized inclusive maximum float flat; // normalized flat region size float fuzz; // normalized error tolerance - float oldValue; // previous value - float newValue; // most recent value - 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, - int32_t axis, bool explicitlyMapped, float scale, float offset, + void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, + bool explicitlyMapped, float scale, float offset, + float highScale, float highOffset, float min, float max, float flat, float fuzz) { this->rawAxisInfo = rawAxisInfo; - this->axis = axis; + this->axisInfo = axisInfo; this->explicitlyMapped = explicitlyMapped; this->scale = scale; this->offset = offset; + this->highScale = highScale; + this->highOffset = highOffset; this->min = min; this->max = max; this->flat = flat; this->fuzz = fuzz; this->filter = 0; - this->oldValue = 0; + resetValue(); + } + + void resetValue() { + this->currentValue = 0; this->newValue = 0; + this->highCurrentValue = 0; + this->highNewValue = 0; } }; @@ -1051,9 +1063,14 @@ private: void sync(nsecs_t when, bool force); - bool haveAxis(int32_t axis); + bool haveAxis(int32_t axisId); 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); }; diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 8404b3a..d77cb2f 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -592,7 +592,7 @@ private: } virtual status_t mapAxis(int32_t deviceId, int scancode, - int32_t* outAxis) const { + AxisInfo* outAxisInfo) const { return NAME_NOT_FOUND; } |