| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 1 | /* | 
 | 2 |  * Copyright (C) 2019 The Android Open Source Project | 
 | 3 |  * | 
 | 4 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
 | 5 |  * you may not use this file except in compliance with the License. | 
 | 6 |  * You may obtain a copy of the License at | 
 | 7 |  * | 
 | 8 |  *      http://www.apache.org/licenses/LICENSE-2.0 | 
 | 9 |  * | 
 | 10 |  * Unless required by applicable law or agreed to in writing, software | 
 | 11 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
 | 12 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | 13 |  * See the License for the specific language governing permissions and | 
 | 14 |  * limitations under the License. | 
 | 15 |  */ | 
 | 16 |  | 
| Prabir Pradhan | 9244aea | 2020-02-05 20:31:40 -0800 | [diff] [blame] | 17 | #include "../Macros.h" | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 18 |  | 
 | 19 | #include "JoystickInputMapper.h" | 
 | 20 |  | 
 | 21 | namespace android { | 
 | 22 |  | 
| Nathaniel R. Lewis | 26ec222 | 2020-01-10 16:30:54 -0800 | [diff] [blame] | 23 | JoystickInputMapper::JoystickInputMapper(InputDeviceContext& deviceContext) | 
 | 24 |       : InputMapper(deviceContext) {} | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 25 |  | 
 | 26 | JoystickInputMapper::~JoystickInputMapper() {} | 
 | 27 |  | 
 | 28 | uint32_t JoystickInputMapper::getSources() { | 
 | 29 |     return AINPUT_SOURCE_JOYSTICK; | 
 | 30 | } | 
 | 31 |  | 
 | 32 | void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { | 
 | 33 |     InputMapper::populateDeviceInfo(info); | 
 | 34 |  | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 35 |     for (std::pair<const int32_t, Axis>& pair : mAxes) { | 
 | 36 |         const Axis& axis = pair.second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 37 |         addMotionRange(axis.axisInfo.axis, axis, info); | 
 | 38 |  | 
 | 39 |         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { | 
 | 40 |             addMotionRange(axis.axisInfo.highAxis, axis, info); | 
 | 41 |         } | 
 | 42 |     } | 
 | 43 | } | 
 | 44 |  | 
 | 45 | void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info) { | 
 | 46 |     info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, axis.fuzz, | 
 | 47 |                          axis.resolution); | 
 | 48 |     /* In order to ease the transition for developers from using the old axes | 
 | 49 |      * to the newer, more semantically correct axes, we'll continue to register | 
 | 50 |      * the old axes as duplicates of their corresponding new ones.  */ | 
 | 51 |     int32_t compatAxis = getCompatAxis(axisId); | 
 | 52 |     if (compatAxis >= 0) { | 
 | 53 |         info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, axis.min, axis.max, axis.flat, | 
 | 54 |                              axis.fuzz, axis.resolution); | 
 | 55 |     } | 
 | 56 | } | 
 | 57 |  | 
 | 58 | /* A mapping from axes the joystick actually has to the axes that should be | 
 | 59 |  * artificially created for compatibility purposes. | 
 | 60 |  * Returns -1 if no compatibility axis is needed. */ | 
 | 61 | int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { | 
 | 62 |     switch (axis) { | 
 | 63 |         case AMOTION_EVENT_AXIS_LTRIGGER: | 
 | 64 |             return AMOTION_EVENT_AXIS_BRAKE; | 
 | 65 |         case AMOTION_EVENT_AXIS_RTRIGGER: | 
 | 66 |             return AMOTION_EVENT_AXIS_GAS; | 
 | 67 |     } | 
 | 68 |     return -1; | 
 | 69 | } | 
 | 70 |  | 
 | 71 | void JoystickInputMapper::dump(std::string& dump) { | 
 | 72 |     dump += INDENT2 "Joystick Input Mapper:\n"; | 
 | 73 |  | 
 | 74 |     dump += INDENT3 "Axes:\n"; | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 75 |     for (const auto& [rawAxis, axis] : mAxes) { | 
| Chris Ye | 4958d06 | 2020-08-20 13:21:10 -0700 | [diff] [blame] | 76 |         const char* label = InputEventLookup::getAxisLabel(axis.axisInfo.axis); | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 77 |         if (label) { | 
 | 78 |             dump += StringPrintf(INDENT4 "%s", label); | 
 | 79 |         } else { | 
 | 80 |             dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis); | 
 | 81 |         } | 
 | 82 |         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { | 
| Chris Ye | 4958d06 | 2020-08-20 13:21:10 -0700 | [diff] [blame] | 83 |             label = InputEventLookup::getAxisLabel(axis.axisInfo.highAxis); | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 84 |             if (label) { | 
 | 85 |                 dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue); | 
 | 86 |             } else { | 
 | 87 |                 dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis, | 
 | 88 |                                      axis.axisInfo.splitValue); | 
 | 89 |             } | 
 | 90 |         } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { | 
 | 91 |             dump += " (invert)"; | 
 | 92 |         } | 
 | 93 |  | 
 | 94 |         dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", | 
 | 95 |                              axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); | 
 | 96 |         dump += StringPrintf(INDENT4 "  scale=%0.5f, offset=%0.5f, " | 
 | 97 |                                      "highScale=%0.5f, highOffset=%0.5f\n", | 
 | 98 |                              axis.scale, axis.offset, axis.highScale, axis.highOffset); | 
 | 99 |         dump += StringPrintf(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, " | 
 | 100 |                                      "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 101 |                              rawAxis, axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 102 |                              axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, | 
 | 103 |                              axis.rawAxisInfo.resolution); | 
 | 104 |     } | 
 | 105 | } | 
 | 106 |  | 
 | 107 | void JoystickInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config, | 
 | 108 |                                     uint32_t changes) { | 
 | 109 |     InputMapper::configure(when, config, changes); | 
 | 110 |  | 
 | 111 |     if (!changes) { // first time only | 
 | 112 |         // Collect all axes. | 
 | 113 |         for (int32_t abs = 0; abs <= ABS_MAX; abs++) { | 
| Chris Ye | 1b0c734 | 2020-07-28 21:57:03 -0700 | [diff] [blame] | 114 |             if (!(getAbsAxisUsage(abs, getDeviceContext().getDeviceClasses()) | 
 | 115 |                           .test(InputDeviceClass::JOYSTICK))) { | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 116 |                 continue; // axis must be claimed by a different device | 
 | 117 |             } | 
 | 118 |  | 
 | 119 |             RawAbsoluteAxisInfo rawAxisInfo; | 
 | 120 |             getAbsoluteAxisInfo(abs, &rawAxisInfo); | 
 | 121 |             if (rawAxisInfo.valid) { | 
 | 122 |                 // Map axis. | 
 | 123 |                 AxisInfo axisInfo; | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 124 |                 const bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo); | 
 | 125 |  | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 126 |                 if (!explicitlyMapped) { | 
 | 127 |                     // Axis is not explicitly mapped, will choose a generic axis later. | 
 | 128 |                     axisInfo.mode = AxisInfo::MODE_NORMAL; | 
 | 129 |                     axisInfo.axis = -1; | 
 | 130 |                 } | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 131 |                 mAxes.insert({abs, createAxis(axisInfo, rawAxisInfo, explicitlyMapped)}); | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 132 |             } | 
 | 133 |         } | 
 | 134 |  | 
 | 135 |         // If there are too many axes, start dropping them. | 
 | 136 |         // Prefer to keep explicitly mapped axes. | 
 | 137 |         if (mAxes.size() > PointerCoords::MAX_AXES) { | 
 | 138 |             ALOGI("Joystick '%s' has %zu axes but the framework only supports a maximum of %d.", | 
 | 139 |                   getDeviceName().c_str(), mAxes.size(), PointerCoords::MAX_AXES); | 
 | 140 |             pruneAxes(true); | 
 | 141 |             pruneAxes(false); | 
 | 142 |         } | 
 | 143 |  | 
 | 144 |         // Assign generic axis ids to remaining axes. | 
 | 145 |         int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 146 |         for (auto it = mAxes.begin(); it != mAxes.end(); /*increment it inside loop*/) { | 
 | 147 |             Axis& axis = it->second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 148 |             if (axis.axisInfo.axis < 0) { | 
 | 149 |                 while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 && | 
 | 150 |                        haveAxis(nextGenericAxisId)) { | 
 | 151 |                     nextGenericAxisId += 1; | 
 | 152 |                 } | 
 | 153 |  | 
 | 154 |                 if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { | 
 | 155 |                     axis.axisInfo.axis = nextGenericAxisId; | 
 | 156 |                     nextGenericAxisId += 1; | 
 | 157 |                 } else { | 
 | 158 |                     ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " | 
 | 159 |                           "have already been assigned to other axes.", | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 160 |                           getDeviceName().c_str(), it->first); | 
 | 161 |                     it = mAxes.erase(it); | 
 | 162 |                     continue; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 163 |                 } | 
 | 164 |             } | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 165 |             it++; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 166 |         } | 
 | 167 |     } | 
 | 168 | } | 
 | 169 |  | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 170 | JoystickInputMapper::Axis JoystickInputMapper::createAxis(const AxisInfo& axisInfo, | 
 | 171 |                                                           const RawAbsoluteAxisInfo& rawAxisInfo, | 
 | 172 |                                                           bool explicitlyMapped) { | 
 | 173 |     // Apply flat override. | 
 | 174 |     int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride; | 
 | 175 |  | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 176 |     float scale = std::numeric_limits<float>::signaling_NaN(); | 
 | 177 |     float highScale = std::numeric_limits<float>::signaling_NaN(); | 
 | 178 |     float highOffset = 0; | 
 | 179 |     float offset = 0; | 
 | 180 |     float min = 0; | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 181 |     // Calculate scaling factors and limits. | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 182 |     if (axisInfo.mode == AxisInfo::MODE_SPLIT) { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 183 |         scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); | 
 | 184 |         highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 185 |     } else if (isCenteredAxis(axisInfo.axis)) { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 186 |         scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); | 
 | 187 |         offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; | 
 | 188 |         highOffset = offset; | 
 | 189 |         highScale = scale; | 
 | 190 |         min = -1.0f; | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 191 |     } else { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 192 |         scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); | 
 | 193 |         highScale = scale; | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 194 |     } | 
 | 195 |  | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 196 |     constexpr float max = 1.0; | 
 | 197 |     const float flat = rawFlat * scale; | 
 | 198 |     const float fuzz = rawAxisInfo.fuzz * scale; | 
 | 199 |     const float resolution = rawAxisInfo.resolution * scale; | 
 | 200 |  | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 201 |     // To eliminate noise while the joystick is at rest, filter out small variations | 
 | 202 |     // in axis values up front. | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 203 |     const float filter = fuzz ? fuzz : flat * 0.25f; | 
 | 204 |     return Axis(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, highScale, highOffset, min, | 
 | 205 |                 max, flat, fuzz, resolution, filter); | 
| Siarhei Vishniakou | 690f8be | 2020-06-30 04:31:25 -0500 | [diff] [blame] | 206 | } | 
 | 207 |  | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 208 | bool JoystickInputMapper::haveAxis(int32_t axisId) { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 209 |     for (const std::pair<int32_t, Axis>& pair : mAxes) { | 
 | 210 |         const Axis& axis = pair.second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 211 |         if (axis.axisInfo.axis == axisId || | 
 | 212 |             (axis.axisInfo.mode == AxisInfo::MODE_SPLIT && axis.axisInfo.highAxis == axisId)) { | 
 | 213 |             return true; | 
 | 214 |         } | 
 | 215 |     } | 
 | 216 |     return false; | 
 | 217 | } | 
 | 218 |  | 
 | 219 | void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 220 |     while (mAxes.size() > PointerCoords::MAX_AXES) { | 
 | 221 |         auto it = mAxes.begin(); | 
 | 222 |         if (ignoreExplicitlyMappedAxes && it->second.explicitlyMapped) { | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 223 |             continue; | 
 | 224 |         } | 
 | 225 |         ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 226 |               getDeviceName().c_str(), it->first); | 
 | 227 |         mAxes.erase(it); | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 228 |     } | 
 | 229 | } | 
 | 230 |  | 
 | 231 | bool JoystickInputMapper::isCenteredAxis(int32_t axis) { | 
 | 232 |     switch (axis) { | 
 | 233 |         case AMOTION_EVENT_AXIS_X: | 
 | 234 |         case AMOTION_EVENT_AXIS_Y: | 
 | 235 |         case AMOTION_EVENT_AXIS_Z: | 
 | 236 |         case AMOTION_EVENT_AXIS_RX: | 
 | 237 |         case AMOTION_EVENT_AXIS_RY: | 
 | 238 |         case AMOTION_EVENT_AXIS_RZ: | 
 | 239 |         case AMOTION_EVENT_AXIS_HAT_X: | 
 | 240 |         case AMOTION_EVENT_AXIS_HAT_Y: | 
 | 241 |         case AMOTION_EVENT_AXIS_ORIENTATION: | 
 | 242 |         case AMOTION_EVENT_AXIS_RUDDER: | 
 | 243 |         case AMOTION_EVENT_AXIS_WHEEL: | 
 | 244 |             return true; | 
 | 245 |         default: | 
 | 246 |             return false; | 
 | 247 |     } | 
 | 248 | } | 
 | 249 |  | 
 | 250 | void JoystickInputMapper::reset(nsecs_t when) { | 
 | 251 |     // Recenter all axes. | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 252 |     for (std::pair<const int32_t, Axis>& pair : mAxes) { | 
 | 253 |         Axis& axis = pair.second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 254 |         axis.resetValue(); | 
 | 255 |     } | 
 | 256 |  | 
 | 257 |     InputMapper::reset(when); | 
 | 258 | } | 
 | 259 |  | 
 | 260 | void JoystickInputMapper::process(const RawEvent* rawEvent) { | 
 | 261 |     switch (rawEvent->type) { | 
 | 262 |         case EV_ABS: { | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 263 |             auto it = mAxes.find(rawEvent->code); | 
 | 264 |             if (it != mAxes.end()) { | 
 | 265 |                 Axis& axis = it->second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 266 |                 float newValue, highNewValue; | 
 | 267 |                 switch (axis.axisInfo.mode) { | 
 | 268 |                     case AxisInfo::MODE_INVERT: | 
 | 269 |                         newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) * axis.scale + | 
 | 270 |                                 axis.offset; | 
 | 271 |                         highNewValue = 0.0f; | 
 | 272 |                         break; | 
 | 273 |                     case AxisInfo::MODE_SPLIT: | 
 | 274 |                         if (rawEvent->value < axis.axisInfo.splitValue) { | 
 | 275 |                             newValue = (axis.axisInfo.splitValue - rawEvent->value) * axis.scale + | 
 | 276 |                                     axis.offset; | 
 | 277 |                             highNewValue = 0.0f; | 
 | 278 |                         } else if (rawEvent->value > axis.axisInfo.splitValue) { | 
 | 279 |                             newValue = 0.0f; | 
 | 280 |                             highNewValue = | 
 | 281 |                                     (rawEvent->value - axis.axisInfo.splitValue) * axis.highScale + | 
 | 282 |                                     axis.highOffset; | 
 | 283 |                         } else { | 
 | 284 |                             newValue = 0.0f; | 
 | 285 |                             highNewValue = 0.0f; | 
 | 286 |                         } | 
 | 287 |                         break; | 
 | 288 |                     default: | 
 | 289 |                         newValue = rawEvent->value * axis.scale + axis.offset; | 
 | 290 |                         highNewValue = 0.0f; | 
 | 291 |                         break; | 
 | 292 |                 } | 
 | 293 |                 axis.newValue = newValue; | 
 | 294 |                 axis.highNewValue = highNewValue; | 
 | 295 |             } | 
 | 296 |             break; | 
 | 297 |         } | 
 | 298 |  | 
 | 299 |         case EV_SYN: | 
 | 300 |             switch (rawEvent->code) { | 
 | 301 |                 case SYN_REPORT: | 
 | 302 |                     sync(rawEvent->when, false /*force*/); | 
 | 303 |                     break; | 
 | 304 |             } | 
 | 305 |             break; | 
 | 306 |     } | 
 | 307 | } | 
 | 308 |  | 
 | 309 | void JoystickInputMapper::sync(nsecs_t when, bool force) { | 
 | 310 |     if (!filterAxes(force)) { | 
 | 311 |         return; | 
 | 312 |     } | 
 | 313 |  | 
| Nathaniel R. Lewis | 26ec222 | 2020-01-10 16:30:54 -0800 | [diff] [blame] | 314 |     int32_t metaState = getContext()->getGlobalMetaState(); | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 315 |     int32_t buttonState = 0; | 
 | 316 |  | 
 | 317 |     PointerProperties pointerProperties; | 
 | 318 |     pointerProperties.clear(); | 
 | 319 |     pointerProperties.id = 0; | 
 | 320 |     pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; | 
 | 321 |  | 
 | 322 |     PointerCoords pointerCoords; | 
 | 323 |     pointerCoords.clear(); | 
 | 324 |  | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 325 |     for (std::pair<const int32_t, Axis>& pair : mAxes) { | 
 | 326 |         const Axis& axis = pair.second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 327 |         setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); | 
 | 328 |         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { | 
 | 329 |             setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, | 
 | 330 |                                       axis.highCurrentValue); | 
 | 331 |         } | 
 | 332 |     } | 
 | 333 |  | 
 | 334 |     // Moving a joystick axis should not wake the device because joysticks can | 
 | 335 |     // be fairly noisy even when not in use.  On the other hand, pushing a gamepad | 
 | 336 |     // button will likely wake the device. | 
 | 337 |     // TODO: Use the input device configuration to control this behavior more finely. | 
 | 338 |     uint32_t policyFlags = 0; | 
 | 339 |  | 
| Garfield Tan | 6a5a14e | 2020-01-28 13:24:04 -0800 | [diff] [blame] | 340 |     NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, | 
 | 341 |                           ADISPLAY_ID_NONE, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, | 
 | 342 |                           buttonState, MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1, | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 343 |                           &pointerProperties, &pointerCoords, 0, 0, | 
 | 344 |                           AMOTION_EVENT_INVALID_CURSOR_POSITION, | 
 | 345 |                           AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {}); | 
 | 346 |     getListener()->notifyMotion(&args); | 
 | 347 | } | 
 | 348 |  | 
 | 349 | void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, | 
 | 350 |                                                     float value) { | 
 | 351 |     pointerCoords->setAxisValue(axis, value); | 
 | 352 |     /* In order to ease the transition for developers from using the old axes | 
 | 353 |      * to the newer, more semantically correct axes, we'll continue to produce | 
 | 354 |      * values for the old axes as mirrors of the value of their corresponding | 
 | 355 |      * new axes. */ | 
 | 356 |     int32_t compatAxis = getCompatAxis(axis); | 
 | 357 |     if (compatAxis >= 0) { | 
 | 358 |         pointerCoords->setAxisValue(compatAxis, value); | 
 | 359 |     } | 
 | 360 | } | 
 | 361 |  | 
 | 362 | bool JoystickInputMapper::filterAxes(bool force) { | 
 | 363 |     bool atLeastOneSignificantChange = force; | 
| Siarhei Vishniakou | b4d960d | 2019-10-03 15:38:44 -0500 | [diff] [blame] | 364 |     for (std::pair<const int32_t, Axis>& pair : mAxes) { | 
 | 365 |         Axis& axis = pair.second; | 
| Prabir Pradhan | baa5c82 | 2019-08-30 15:27:05 -0700 | [diff] [blame] | 366 |         if (force || | 
 | 367 |             hasValueChangedSignificantly(axis.filter, axis.newValue, axis.currentValue, axis.min, | 
 | 368 |                                          axis.max)) { | 
 | 369 |             axis.currentValue = axis.newValue; | 
 | 370 |             atLeastOneSignificantChange = true; | 
 | 371 |         } | 
 | 372 |         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { | 
 | 373 |             if (force || | 
 | 374 |                 hasValueChangedSignificantly(axis.filter, axis.highNewValue, axis.highCurrentValue, | 
 | 375 |                                              axis.min, axis.max)) { | 
 | 376 |                 axis.highCurrentValue = axis.highNewValue; | 
 | 377 |                 atLeastOneSignificantChange = true; | 
 | 378 |             } | 
 | 379 |         } | 
 | 380 |     } | 
 | 381 |     return atLeastOneSignificantChange; | 
 | 382 | } | 
 | 383 |  | 
 | 384 | bool JoystickInputMapper::hasValueChangedSignificantly(float filter, float newValue, | 
 | 385 |                                                        float currentValue, float min, float max) { | 
 | 386 |     if (newValue != currentValue) { | 
 | 387 |         // Filter out small changes in value unless the value is converging on the axis | 
 | 388 |         // bounds or center point.  This is intended to reduce the amount of information | 
 | 389 |         // sent to applications by particularly noisy joysticks (such as PS3). | 
 | 390 |         if (fabs(newValue - currentValue) > filter || | 
 | 391 |             hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) || | 
 | 392 |             hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) || | 
 | 393 |             hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { | 
 | 394 |             return true; | 
 | 395 |         } | 
 | 396 |     } | 
 | 397 |     return false; | 
 | 398 | } | 
 | 399 |  | 
 | 400 | bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange(float filter, float newValue, | 
 | 401 |                                                                    float currentValue, | 
 | 402 |                                                                    float thresholdValue) { | 
 | 403 |     float newDistance = fabs(newValue - thresholdValue); | 
 | 404 |     if (newDistance < filter) { | 
 | 405 |         float oldDistance = fabs(currentValue - thresholdValue); | 
 | 406 |         if (newDistance < oldDistance) { | 
 | 407 |             return true; | 
 | 408 |         } | 
 | 409 |     } | 
 | 410 |     return false; | 
 | 411 | } | 
 | 412 |  | 
 | 413 | } // namespace android |