blob: 1c08ab1ed2644347b592411f7a2b8dd93afbde72 [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001/*
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
17#include "Macros.h"
18
19#include "InputDevice.h"
20
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -080021#include "CursorInputMapper.h"
22#include "ExternalStylusInputMapper.h"
23#include "InputReaderContext.h"
24#include "JoystickInputMapper.h"
25#include "KeyboardInputMapper.h"
26#include "MultiTouchInputMapper.h"
27#include "RotaryEncoderInputMapper.h"
28#include "SingleTouchInputMapper.h"
29#include "SwitchInputMapper.h"
30#include "VibratorInputMapper.h"
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070031
32namespace android {
33
34InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation,
35 int32_t controllerNumber, const InputDeviceIdentifier& identifier,
36 uint32_t classes)
37 : mContext(context),
38 mId(id),
39 mGeneration(generation),
40 mControllerNumber(controllerNumber),
41 mIdentifier(identifier),
42 mClasses(classes),
43 mSources(0),
44 mIsExternal(false),
45 mHasMic(false),
46 mDropUntilNextSync(false) {}
47
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -080048InputDevice::~InputDevice() {}
Prabir Pradhanbaa5c822019-08-30 15:27:05 -070049
50bool InputDevice::isEnabled() {
51 return getEventHub()->isDeviceEnabled(mId);
52}
53
54void InputDevice::setEnabled(bool enabled, nsecs_t when) {
55 if (enabled && mAssociatedDisplayPort && !mAssociatedViewport) {
56 ALOGW("Cannot enable input device %s because it is associated with port %" PRIu8 ", "
57 "but the corresponding viewport is not found",
58 getName().c_str(), *mAssociatedDisplayPort);
59 enabled = false;
60 }
61
62 if (isEnabled() == enabled) {
63 return;
64 }
65
66 if (enabled) {
67 getEventHub()->enableDevice(mId);
68 reset(when);
69 } else {
70 reset(when);
71 getEventHub()->disableDevice(mId);
72 }
73 // Must change generation to flag this device as changed
74 bumpGeneration();
75}
76
77void InputDevice::dump(std::string& dump) {
78 InputDeviceInfo deviceInfo;
79 getDeviceInfo(&deviceInfo);
80
81 dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
82 deviceInfo.getDisplayName().c_str());
83 dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
84 dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
85 dump += StringPrintf(INDENT2 "AssociatedDisplayPort: ");
86 if (mAssociatedDisplayPort) {
87 dump += StringPrintf("%" PRIu8 "\n", *mAssociatedDisplayPort);
88 } else {
89 dump += "<none>\n";
90 }
91 dump += StringPrintf(INDENT2 "HasMic: %s\n", toString(mHasMic));
92 dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
93 dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
94
95 const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
96 if (!ranges.empty()) {
97 dump += INDENT2 "Motion Ranges:\n";
98 for (size_t i = 0; i < ranges.size(); i++) {
99 const InputDeviceInfo::MotionRange& range = ranges[i];
100 const char* label = getAxisLabel(range.axis);
101 char name[32];
102 if (label) {
103 strncpy(name, label, sizeof(name));
104 name[sizeof(name) - 1] = '\0';
105 } else {
106 snprintf(name, sizeof(name), "%d", range.axis);
107 }
108 dump += StringPrintf(INDENT3
109 "%s: source=0x%08x, "
110 "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
111 name, range.source, range.min, range.max, range.flat, range.fuzz,
112 range.resolution);
113 }
114 }
115
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800116 for_each_mapper([&dump](InputMapper& mapper) { mapper.dump(dump); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700117}
118
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800119void InputDevice::populateMappers() {
120 uint32_t classes = mClasses;
121 std::vector<std::unique_ptr<InputMapper>>& mappers = mMappers;
122
123 // External devices.
124 if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
125 setExternal(true);
126 }
127
128 // Devices with mics.
129 if (classes & INPUT_DEVICE_CLASS_MIC) {
130 setMic(true);
131 }
132
133 // Switch-like devices.
134 if (classes & INPUT_DEVICE_CLASS_SWITCH) {
135 mappers.push_back(std::make_unique<SwitchInputMapper>(this));
136 }
137
138 // Scroll wheel-like devices.
139 if (classes & INPUT_DEVICE_CLASS_ROTARY_ENCODER) {
140 mappers.push_back(std::make_unique<RotaryEncoderInputMapper>(this));
141 }
142
143 // Vibrator-like devices.
144 if (classes & INPUT_DEVICE_CLASS_VIBRATOR) {
145 mappers.push_back(std::make_unique<VibratorInputMapper>(this));
146 }
147
148 // Keyboard-like devices.
149 uint32_t keyboardSource = 0;
150 int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC;
151 if (classes & INPUT_DEVICE_CLASS_KEYBOARD) {
152 keyboardSource |= AINPUT_SOURCE_KEYBOARD;
153 }
154 if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
155 keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
156 }
157 if (classes & INPUT_DEVICE_CLASS_DPAD) {
158 keyboardSource |= AINPUT_SOURCE_DPAD;
159 }
160 if (classes & INPUT_DEVICE_CLASS_GAMEPAD) {
161 keyboardSource |= AINPUT_SOURCE_GAMEPAD;
162 }
163
164 if (keyboardSource != 0) {
165 mappers.push_back(
166 std::make_unique<KeyboardInputMapper>(this, keyboardSource, keyboardType));
167 }
168
169 // Cursor-like devices.
170 if (classes & INPUT_DEVICE_CLASS_CURSOR) {
171 mappers.push_back(std::make_unique<CursorInputMapper>(this));
172 }
173
174 // Touchscreens and touchpad devices.
175 if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
176 mappers.push_back(std::make_unique<MultiTouchInputMapper>(this));
177 } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
178 mappers.push_back(std::make_unique<SingleTouchInputMapper>(this));
179 }
180
181 // Joystick-like devices.
182 if (classes & INPUT_DEVICE_CLASS_JOYSTICK) {
183 mappers.push_back(std::make_unique<JoystickInputMapper>(this));
184 }
185
186 // External stylus-like devices.
187 if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
188 mappers.push_back(std::make_unique<ExternalStylusInputMapper>(this));
189 }
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700190}
191
192void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config,
193 uint32_t changes) {
194 mSources = 0;
195
196 if (!isIgnored()) {
197 if (!changes) { // first time only
198 mContext->getEventHub()->getConfiguration(mId, &mConfiguration);
199 }
200
201 if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
202 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
203 sp<KeyCharacterMap> keyboardLayout =
204 mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
205 if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) {
206 bumpGeneration();
207 }
208 }
209 }
210
211 if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
212 if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) {
213 std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
214 if (mAlias != alias) {
215 mAlias = alias;
216 bumpGeneration();
217 }
218 }
219 }
220
221 if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
222 auto it = config->disabledDevices.find(mId);
223 bool enabled = it == config->disabledDevices.end();
224 setEnabled(enabled, when);
225 }
226
227 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
228 // In most situations, no port will be specified.
229 mAssociatedDisplayPort = std::nullopt;
230 mAssociatedViewport = std::nullopt;
231 // Find the display port that corresponds to the current input port.
232 const std::string& inputPort = mIdentifier.location;
233 if (!inputPort.empty()) {
234 const std::unordered_map<std::string, uint8_t>& ports = config->portAssociations;
235 const auto& displayPort = ports.find(inputPort);
236 if (displayPort != ports.end()) {
237 mAssociatedDisplayPort = std::make_optional(displayPort->second);
238 }
239 }
240
241 // If the device was explicitly disabled by the user, it would be present in the
242 // "disabledDevices" list. If it is associated with a specific display, and it was not
243 // explicitly disabled, then enable/disable the device based on whether we can find the
244 // corresponding viewport.
245 bool enabled = (config->disabledDevices.find(mId) == config->disabledDevices.end());
246 if (mAssociatedDisplayPort) {
247 mAssociatedViewport = config->getDisplayViewportByPort(*mAssociatedDisplayPort);
248 if (!mAssociatedViewport) {
249 ALOGW("Input device %s should be associated with display on port %" PRIu8 ", "
250 "but the corresponding viewport is not found.",
251 getName().c_str(), *mAssociatedDisplayPort);
252 enabled = false;
253 }
254 }
255
256 if (changes) {
257 // For first-time configuration, only allow device to be disabled after mappers have
258 // finished configuring. This is because we need to read some of the properties from
259 // the device's open fd.
260 setEnabled(enabled, when);
261 }
262 }
263
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800264 for_each_mapper([this, when, config, changes](InputMapper& mapper) {
265 mapper.configure(when, config, changes);
266 mSources |= mapper.getSources();
267 });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700268
269 // If a device is just plugged but it might be disabled, we need to update some info like
270 // axis range of touch from each InputMapper first, then disable it.
271 if (!changes) {
272 setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(), when);
273 }
274 }
275}
276
277void InputDevice::reset(nsecs_t when) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800278 for_each_mapper([when](InputMapper& mapper) { mapper.reset(when); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700279
280 mContext->updateGlobalMetaState();
281
282 notifyReset(when);
283}
284
285void InputDevice::process(const RawEvent* rawEvents, size_t count) {
286 // Process all of the events in order for each mapper.
287 // We cannot simply ask each mapper to process them in bulk because mappers may
288 // have side-effects that must be interleaved. For example, joystick movement events and
289 // gamepad button presses are handled by different mappers but they should be dispatched
290 // in the order received.
291 for (const RawEvent* rawEvent = rawEvents; count != 0; rawEvent++) {
292#if DEBUG_RAW_EVENTS
293 ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%" PRId64,
294 rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, rawEvent->when);
295#endif
296
297 if (mDropUntilNextSync) {
298 if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
299 mDropUntilNextSync = false;
300#if DEBUG_RAW_EVENTS
301 ALOGD("Recovered from input event buffer overrun.");
302#endif
303 } else {
304#if DEBUG_RAW_EVENTS
305 ALOGD("Dropped input event while waiting for next input sync.");
306#endif
307 }
308 } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) {
309 ALOGI("Detected input event buffer overrun for device %s.", getName().c_str());
310 mDropUntilNextSync = true;
311 reset(rawEvent->when);
312 } else {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800313 for_each_mapper([rawEvent](InputMapper& mapper) { mapper.process(rawEvent); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700314 }
315 --count;
316 }
317}
318
319void InputDevice::timeoutExpired(nsecs_t when) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800320 for_each_mapper([when](InputMapper& mapper) { mapper.timeoutExpired(when); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700321}
322
323void InputDevice::updateExternalStylusState(const StylusState& state) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800324 for_each_mapper([state](InputMapper& mapper) { mapper.updateExternalStylusState(state); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700325}
326
327void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) {
328 outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, mIsExternal,
329 mHasMic);
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800330 for_each_mapper(
331 [outDeviceInfo](InputMapper& mapper) { mapper.populateDeviceInfo(outDeviceInfo); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700332}
333
334int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
335 return getState(sourceMask, keyCode, &InputMapper::getKeyCodeState);
336}
337
338int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
339 return getState(sourceMask, scanCode, &InputMapper::getScanCodeState);
340}
341
342int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) {
343 return getState(sourceMask, switchCode, &InputMapper::getSwitchState);
344}
345
346int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) {
347 int32_t result = AKEY_STATE_UNKNOWN;
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800348 for (auto& mapperPtr : mMappers) {
349 InputMapper& mapper = *mapperPtr;
350 if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700351 // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that
352 // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it.
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800353 int32_t currentResult = (mapper.*getStateFunc)(sourceMask, code);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700354 if (currentResult >= AKEY_STATE_DOWN) {
355 return currentResult;
356 } else if (currentResult == AKEY_STATE_UP) {
357 result = currentResult;
358 }
359 }
360 }
361 return result;
362}
363
364bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
365 const int32_t* keyCodes, uint8_t* outFlags) {
366 bool result = false;
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800367 for_each_mapper([&result, sourceMask, numCodes, keyCodes, outFlags](InputMapper& mapper) {
368 if (sourcesMatchMask(mapper.getSources(), sourceMask)) {
369 result |= mapper.markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700370 }
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800371 });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700372 return result;
373}
374
375void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
376 int32_t token) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800377 for_each_mapper([pattern, patternSize, repeat, token](InputMapper& mapper) {
378 mapper.vibrate(pattern, patternSize, repeat, token);
379 });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700380}
381
382void InputDevice::cancelVibrate(int32_t token) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800383 for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700384}
385
386void InputDevice::cancelTouch(nsecs_t when) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800387 for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700388}
389
390int32_t InputDevice::getMetaState() {
391 int32_t result = 0;
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800392 for_each_mapper([&result](InputMapper& mapper) { result |= mapper.getMetaState(); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700393 return result;
394}
395
396void InputDevice::updateMetaState(int32_t keyCode) {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800397 for_each_mapper([keyCode](InputMapper& mapper) { mapper.updateMetaState(keyCode); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700398}
399
400void InputDevice::fadePointer() {
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800401 for_each_mapper([](InputMapper& mapper) { mapper.fadePointer(); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700402}
403
404void InputDevice::bumpGeneration() {
405 mGeneration = mContext->bumpGeneration();
406}
407
408void InputDevice::notifyReset(nsecs_t when) {
409 NotifyDeviceResetArgs args(mContext->getNextSequenceNum(), when, mId);
410 mContext->getListener()->notifyDeviceReset(&args);
411}
412
413std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
414 // Check if we had associated to the specific display.
415 if (mAssociatedViewport) {
416 return mAssociatedViewport->displayId;
417 }
418
419 // No associated display port, check if some InputMapper is associated.
Nathaniel R. Lewisf4916ef2020-01-14 11:57:18 -0800420 return first_in_mappers<int32_t>(
421 [](InputMapper& mapper) { return mapper.getAssociatedDisplayId(); });
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700422}
423
424} // namespace android