From e89d1041ddc81a85c73f00f94a978e32597afa68 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Fri, 4 Mar 2011 13:07:49 -0800 Subject: [PATCH] Joystick tweaks. (DO NOT MERGE) Ensure that the joystick can always reach -1.0, 0.0 and 1.0 positions even when noise filtering is applied. (Bug: 3514510) Add support for a few more standard axes. Add additional mapping modes for axes. Some axes are inverted from standard interpretation or are actually intended to be split into two distict axes such as left/right trigger controls or accelerator/brake. Add key layout file for a G25 racing wheel and XBox 360 controller to tweak behavior. They work fine without them but the axis mappings are not ideal. Change-Id: I0fddd90309af4dc14d35f34fe99ed6e521c0b7c7 --- include/ui/KeyLayoutMap.h | 34 ++++++++++++- include/ui/KeycodeLabels.h | 5 ++ libs/ui/KeyLayoutMap.cpp | 97 +++++++++++++++++++++++++++++++++----- 3 files changed, 122 insertions(+), 14 deletions(-) diff --git a/include/ui/KeyLayoutMap.h b/include/ui/KeyLayoutMap.h index 904c8f305..d82d0c8e0 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* 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 mKeys; - KeyedVector mAxes; + KeyedVector mAxes; KeyLayoutMap(); diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h index bdfbf7cac..b912e9be6 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 2ed0e66e1..8626a03bf 100644 --- a/libs/ui/KeyLayoutMap.cpp +++ b/libs/ui/KeyLayoutMap.cpp @@ -113,20 +113,23 @@ status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector* 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; }