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
17 // clang-format off
18 #include "../Macros.h"
19 // clang-format on
20
21 #include "KeyboardInputMapper.h"
22
23 #include <ftl/enum.h>
24 #include <input/KeyboardClassifier.h>
25 #include <ui/Rotation.h>
26
27 namespace android {
28
29 // --- Static Definitions ---
30
rotateKeyCode(int32_t keyCode,ui::Rotation orientation)31 static int32_t rotateKeyCode(int32_t keyCode, ui::Rotation orientation) {
32 static constexpr int32_t KEYCODE_ROTATION_MAP[][4] = {
33 // key codes enumerated counter-clockwise with the original (unrotated) key first
34 // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation
35 {AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT},
36 {AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN},
37 {AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT},
38 {AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP},
39 {AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT,
40 AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT},
41 {AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP,
42 AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN},
43 {AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT,
44 AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT},
45 {AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN,
46 AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP},
47 };
48
49 if (orientation != ui::ROTATION_0) {
50 for (const auto& rotation : KEYCODE_ROTATION_MAP) {
51 if (rotation[static_cast<size_t>(ui::ROTATION_0)] == keyCode) {
52 return rotation[static_cast<size_t>(orientation)];
53 }
54 }
55 }
56 return keyCode;
57 }
58
isSupportedScanCode(int32_t scanCode)59 static bool isSupportedScanCode(int32_t scanCode) {
60 // KeyboardInputMapper handles keys from keyboards, gamepads, and styluses.
61 return scanCode < BTN_MOUSE || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI) ||
62 scanCode == BTN_STYLUS || scanCode == BTN_STYLUS2 || scanCode == BTN_STYLUS3 ||
63 scanCode >= BTN_WHEEL;
64 }
65
isMediaKey(int32_t keyCode)66 static bool isMediaKey(int32_t keyCode) {
67 switch (keyCode) {
68 case AKEYCODE_MEDIA_PLAY:
69 case AKEYCODE_MEDIA_PAUSE:
70 case AKEYCODE_MEDIA_PLAY_PAUSE:
71 case AKEYCODE_MUTE:
72 case AKEYCODE_HEADSETHOOK:
73 case AKEYCODE_MEDIA_STOP:
74 case AKEYCODE_MEDIA_NEXT:
75 case AKEYCODE_MEDIA_PREVIOUS:
76 case AKEYCODE_MEDIA_REWIND:
77 case AKEYCODE_MEDIA_RECORD:
78 case AKEYCODE_MEDIA_FAST_FORWARD:
79 case AKEYCODE_MEDIA_SKIP_FORWARD:
80 case AKEYCODE_MEDIA_SKIP_BACKWARD:
81 case AKEYCODE_MEDIA_STEP_FORWARD:
82 case AKEYCODE_MEDIA_STEP_BACKWARD:
83 case AKEYCODE_MEDIA_AUDIO_TRACK:
84 case AKEYCODE_VOLUME_UP:
85 case AKEYCODE_VOLUME_DOWN:
86 case AKEYCODE_VOLUME_MUTE:
87 case AKEYCODE_TV_AUDIO_DESCRIPTION:
88 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
89 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
90 return true;
91 default:
92 return false;
93 }
94 }
95
96 // --- KeyboardInputMapper ---
97
KeyboardInputMapper(InputDeviceContext & deviceContext,const InputReaderConfiguration & readerConfig,uint32_t source)98 KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext,
99 const InputReaderConfiguration& readerConfig,
100 uint32_t source)
101 : InputMapper(deviceContext, readerConfig), mSource(source) {}
102
getSources() const103 uint32_t KeyboardInputMapper::getSources() const {
104 return mSource;
105 }
106
getOrientation()107 ui::Rotation KeyboardInputMapper::getOrientation() {
108 if (mViewport) {
109 return mViewport->orientation;
110 }
111 return ui::ROTATION_0;
112 }
113
getDisplayId()114 ui::LogicalDisplayId KeyboardInputMapper::getDisplayId() {
115 if (mViewport) {
116 return mViewport->displayId;
117 }
118 return ui::LogicalDisplayId::INVALID;
119 }
120
getKeyboardLayoutInfo() const121 std::optional<KeyboardLayoutInfo> KeyboardInputMapper::getKeyboardLayoutInfo() const {
122 if (mKeyboardLayoutInfo) {
123 return mKeyboardLayoutInfo;
124 }
125 std::optional<RawLayoutInfo> layoutInfo = getDeviceContext().getRawLayoutInfo();
126 if (!layoutInfo) {
127 return std::nullopt;
128 }
129 return KeyboardLayoutInfo(layoutInfo->languageTag, layoutInfo->layoutType);
130 }
131
populateDeviceInfo(InputDeviceInfo & info)132 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo& info) {
133 InputMapper::populateDeviceInfo(info);
134
135 info.setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
136
137 std::optional keyboardLayoutInfo = getKeyboardLayoutInfo();
138 if (keyboardLayoutInfo) {
139 info.setKeyboardLayoutInfo(*keyboardLayoutInfo);
140 }
141 }
142
dump(std::string & dump)143 void KeyboardInputMapper::dump(std::string& dump) {
144 dump += INDENT2 "Keyboard Input Mapper:\n";
145 dumpParameters(dump);
146 dump += StringPrintf(INDENT3 "Orientation: %s\n", ftl::enum_string(getOrientation()).c_str());
147 dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
148 dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
149 dump += INDENT3 "KeyboardLayoutInfo: ";
150 if (mKeyboardLayoutInfo) {
151 dump += mKeyboardLayoutInfo->languageTag + ", " + mKeyboardLayoutInfo->layoutType + "\n";
152 } else {
153 dump += "<not set>\n";
154 }
155 }
156
findViewport(const InputReaderConfiguration & readerConfig)157 std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
158 const InputReaderConfiguration& readerConfig) {
159 if (getDeviceContext().getAssociatedViewport()) {
160 return getDeviceContext().getAssociatedViewport();
161 }
162
163 // No associated display defined, try to find default display if orientationAware.
164 if (mParameters.orientationAware) {
165 return readerConfig.getDisplayViewportByType(ViewportType::INTERNAL);
166 }
167
168 return std::nullopt;
169 }
170
reconfigure(nsecs_t when,const InputReaderConfiguration & config,ConfigurationChanges changes)171 std::list<NotifyArgs> KeyboardInputMapper::reconfigure(nsecs_t when,
172 const InputReaderConfiguration& config,
173 ConfigurationChanges changes) {
174 std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
175
176 if (!changes.any()) { // first time only
177 // Configure basic parameters.
178 configureParameters();
179 }
180
181 if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
182 mViewport = findViewport(config);
183 }
184
185 if (!changes.any() ||
186 changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION)) {
187 std::optional<KeyboardLayoutInfo> newKeyboardLayoutInfo =
188 getValueByKey(config.keyboardLayoutAssociations, getDeviceContext().getLocation());
189 if (mKeyboardLayoutInfo != newKeyboardLayoutInfo) {
190 mKeyboardLayoutInfo = newKeyboardLayoutInfo;
191 // Also update keyboard layout overlay as soon as we find the new layout info
192 updateKeyboardLayoutOverlay();
193 bumpGeneration();
194 }
195 }
196
197 if (!changes.any() || changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUTS)) {
198 if (!getDeviceContext().getDeviceClasses().test(InputDeviceClass::VIRTUAL) &&
199 updateKeyboardLayoutOverlay()) {
200 bumpGeneration();
201 }
202 }
203 return out;
204 }
205
updateKeyboardLayoutOverlay()206 bool KeyboardInputMapper::updateKeyboardLayoutOverlay() {
207 std::shared_ptr<KeyCharacterMap> keyboardLayout =
208 getDeviceContext()
209 .getContext()
210 ->getPolicy()
211 ->getKeyboardLayoutOverlay(getDeviceContext().getDeviceIdentifier(),
212 getKeyboardLayoutInfo());
213 return getDeviceContext().setKeyboardLayoutOverlay(keyboardLayout);
214 }
215
configureParameters()216 void KeyboardInputMapper::configureParameters() {
217 const PropertyMap& config = getDeviceContext().getConfiguration();
218 mParameters.orientationAware = config.getBool("keyboard.orientationAware").value_or(false);
219 mParameters.handlesKeyRepeat = config.getBool("keyboard.handlesKeyRepeat").value_or(false);
220 mParameters.doNotWakeByDefault = config.getBool("keyboard.doNotWakeByDefault").value_or(false);
221 }
222
dumpParameters(std::string & dump) const223 void KeyboardInputMapper::dumpParameters(std::string& dump) const {
224 dump += INDENT3 "Parameters:\n";
225 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
226 dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat));
227 }
228
reset(nsecs_t when)229 std::list<NotifyArgs> KeyboardInputMapper::reset(nsecs_t when) {
230 std::list<NotifyArgs> out = cancelAllDownKeys(when);
231 mHidUsageAccumulator.reset();
232
233 resetLedState();
234
235 out += InputMapper::reset(when);
236 return out;
237 }
238
process(const RawEvent & rawEvent)239 std::list<NotifyArgs> KeyboardInputMapper::process(const RawEvent& rawEvent) {
240 std::list<NotifyArgs> out;
241 mHidUsageAccumulator.process(rawEvent);
242 switch (rawEvent.type) {
243 case EV_KEY: {
244 int32_t scanCode = rawEvent.code;
245
246 if (isSupportedScanCode(scanCode)) {
247 out += processKey(rawEvent.when, rawEvent.readTime, rawEvent.value != 0,
248 scanCode, mHidUsageAccumulator.consumeCurrentHidUsage());
249 }
250 break;
251 }
252 }
253 return out;
254 }
255
processKey(nsecs_t when,nsecs_t readTime,bool down,int32_t scanCode,int32_t usageCode)256 std::list<NotifyArgs> KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down,
257 int32_t scanCode, int32_t usageCode) {
258 std::list<NotifyArgs> out;
259 int32_t keyCode;
260 int32_t keyMetaState;
261 uint32_t policyFlags;
262 int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
263
264 if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
265 &policyFlags)) {
266 keyCode = AKEYCODE_UNKNOWN;
267 keyMetaState = mMetaState;
268 policyFlags = 0;
269 }
270
271 nsecs_t downTime = when;
272 std::optional<size_t> keyDownIndex = findKeyDownIndex(scanCode);
273 if (down) {
274 // Rotate key codes according to orientation if needed.
275 if (mParameters.orientationAware) {
276 keyCode = rotateKeyCode(keyCode, getOrientation());
277 }
278
279 // Add key down.
280 if (keyDownIndex) {
281 // key repeat, be sure to use same keycode as before in case of rotation
282 keyCode = mKeyDowns[*keyDownIndex].keyCode;
283 downTime = mKeyDowns[*keyDownIndex].downTime;
284 flags = mKeyDowns[*keyDownIndex].flags;
285 } else {
286 // key down
287 if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
288 getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
289 return out;
290 }
291 if (policyFlags & POLICY_FLAG_GESTURE) {
292 out += getDeviceContext().cancelTouch(when, readTime);
293 flags |= AKEY_EVENT_FLAG_KEEP_TOUCH_MODE;
294 }
295
296 KeyDown keyDown;
297 keyDown.keyCode = keyCode;
298 keyDown.scanCode = scanCode;
299 keyDown.downTime = when;
300 keyDown.flags = flags;
301 mKeyDowns.push_back(keyDown);
302 }
303 onKeyDownProcessed(downTime);
304 } else {
305 // Remove key down.
306 if (keyDownIndex) {
307 // key up, be sure to use same keycode as before in case of rotation
308 keyCode = mKeyDowns[*keyDownIndex].keyCode;
309 downTime = mKeyDowns[*keyDownIndex].downTime;
310 flags = mKeyDowns[*keyDownIndex].flags;
311 mKeyDowns.erase(mKeyDowns.begin() + *keyDownIndex);
312 } else {
313 // key was not actually down
314 ALOGI("Dropping key up from device %s because the key was not down. "
315 "keyCode=%d, scanCode=%d",
316 getDeviceName().c_str(), keyCode, scanCode);
317 return out;
318 }
319 }
320
321 if (updateMetaStateIfNeeded(keyCode, down)) {
322 // If global meta state changed send it along with the key.
323 // If it has not changed then we'll use what keymap gave us,
324 // since key replacement logic might temporarily reset a few
325 // meta bits for given key.
326 keyMetaState = mMetaState;
327 }
328
329 DeviceId deviceId = getDeviceId();
330
331 // On first down: Process key for keyboard classification (will send reconfiguration if the
332 // keyboard type change)
333 if (down && !keyDownIndex) {
334 KeyboardClassifier& classifier = getDeviceContext().getContext()->getKeyboardClassifier();
335 classifier.processKey(deviceId, scanCode, keyMetaState);
336 getDeviceContext().setKeyboardType(classifier.getKeyboardType(deviceId));
337 }
338
339 KeyboardType keyboardType = getDeviceContext().getKeyboardType();
340 // Any key down on an external keyboard should wake the device.
341 // We don't do this for internal keyboards to prevent them from waking up in your pocket.
342 // For internal keyboards and devices for which the default wake behavior is explicitly
343 // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
344 // wake key individually.
345 if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
346 !(keyboardType != KeyboardType::ALPHABETIC && isMediaKey(keyCode))) {
347 policyFlags |= POLICY_FLAG_WAKE;
348 }
349
350 if (mParameters.handlesKeyRepeat) {
351 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
352 }
353
354 out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when, readTime, deviceId, mSource,
355 getDisplayId(), policyFlags,
356 down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, flags,
357 keyCode, scanCode, keyMetaState, downTime));
358 return out;
359 }
360
findKeyDownIndex(int32_t scanCode)361 std::optional<size_t> KeyboardInputMapper::findKeyDownIndex(int32_t scanCode) {
362 size_t n = mKeyDowns.size();
363 for (size_t i = 0; i < n; i++) {
364 if (mKeyDowns[i].scanCode == scanCode) {
365 return i;
366 }
367 }
368 return {};
369 }
370
getKeyCodeState(uint32_t sourceMask,int32_t keyCode)371 int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
372 return getDeviceContext().getKeyCodeState(keyCode);
373 }
374
getScanCodeState(uint32_t sourceMask,int32_t scanCode)375 int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
376 return getDeviceContext().getScanCodeState(scanCode);
377 }
378
getKeyCodeForKeyLocation(int32_t locationKeyCode) const379 int32_t KeyboardInputMapper::getKeyCodeForKeyLocation(int32_t locationKeyCode) const {
380 return getDeviceContext().getKeyCodeForKeyLocation(locationKeyCode);
381 }
382
markSupportedKeyCodes(uint32_t sourceMask,const std::vector<int32_t> & keyCodes,uint8_t * outFlags)383 bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask,
384 const std::vector<int32_t>& keyCodes,
385 uint8_t* outFlags) {
386 return getDeviceContext().markSupportedKeyCodes(keyCodes, outFlags);
387 }
388
getMetaState()389 int32_t KeyboardInputMapper::getMetaState() {
390 return mMetaState;
391 }
392
updateMetaState(int32_t keyCode)393 bool KeyboardInputMapper::updateMetaState(int32_t keyCode) {
394 if (!android::isMetaKey(keyCode) || !getDeviceContext().hasKeyCode(keyCode)) {
395 return false;
396 }
397
398 updateMetaStateIfNeeded(keyCode, false);
399 return true;
400 }
401
updateMetaStateIfNeeded(int32_t keyCode,bool down)402 bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
403 int32_t oldMetaState = mMetaState;
404 int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
405 int32_t metaStateChanged = oldMetaState ^ newMetaState;
406 if (metaStateChanged) {
407 mMetaState = newMetaState;
408 constexpr int32_t allLedMetaState =
409 AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON;
410 if ((metaStateChanged & allLedMetaState) != 0) {
411 getContext()->updateLedMetaState(newMetaState & allLedMetaState);
412 }
413 getContext()->updateGlobalMetaState();
414 }
415
416 return metaStateChanged;
417 }
418
resetLedState()419 void KeyboardInputMapper::resetLedState() {
420 initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
421 initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
422 initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
423
424 updateLedState(true);
425 }
426
initializeLedState(LedState & ledState,int32_t led)427 void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
428 ledState.avail = getDeviceContext().hasLed(led);
429 ledState.on = false;
430 }
431
updateLedState(bool reset)432 void KeyboardInputMapper::updateLedState(bool reset) {
433 // Clear the local led state then union the global led state.
434 mMetaState &= ~(AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON);
435 mMetaState |= getContext()->getLedMetaState();
436
437 constexpr int32_t META_NUM = 3;
438 const std::vector<int32_t> keyCodes{AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK,
439 AKEYCODE_SCROLL_LOCK};
440 const std::array<int32_t, META_NUM> metaCodes = {AMETA_CAPS_LOCK_ON, AMETA_NUM_LOCK_ON,
441 AMETA_SCROLL_LOCK_ON};
442 std::array<uint8_t, META_NUM> flags = {0, 0, 0};
443 bool hasKeyLayout = getDeviceContext().markSupportedKeyCodes(keyCodes, flags.data());
444 // If the device doesn't have the physical meta key it shouldn't generate the corresponding
445 // meta state.
446 if (hasKeyLayout) {
447 for (int i = 0; i < META_NUM; i++) {
448 if (!flags[i]) {
449 mMetaState &= ~metaCodes[i];
450 }
451 }
452 }
453
454 updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset);
455 updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset);
456 updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset);
457 }
458
updateLedStateForModifier(LedState & ledState,int32_t led,int32_t modifier,bool reset)459 void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led,
460 int32_t modifier, bool reset) {
461 if (ledState.avail) {
462 bool desiredState = (mMetaState & modifier) != 0;
463 if (reset || ledState.on != desiredState) {
464 getDeviceContext().setLedState(led, desiredState);
465 ledState.on = desiredState;
466 }
467 }
468 }
469
getAssociatedDisplayId()470 std::optional<ui::LogicalDisplayId> KeyboardInputMapper::getAssociatedDisplayId() {
471 if (mViewport) {
472 return std::make_optional(mViewport->displayId);
473 }
474 return std::nullopt;
475 }
476
cancelAllDownKeys(nsecs_t when)477 std::list<NotifyArgs> KeyboardInputMapper::cancelAllDownKeys(nsecs_t when) {
478 std::list<NotifyArgs> out;
479 size_t n = mKeyDowns.size();
480 for (size_t i = 0; i < n; i++) {
481 out.emplace_back(NotifyKeyArgs(getContext()->getNextId(), when,
482 systemTime(SYSTEM_TIME_MONOTONIC), getDeviceId(), mSource,
483 getDisplayId(), /*policyFlags=*/0, AKEY_EVENT_ACTION_UP,
484 mKeyDowns[i].flags | AKEY_EVENT_FLAG_CANCELED,
485 mKeyDowns[i].keyCode, mKeyDowns[i].scanCode, AMETA_NONE,
486 mKeyDowns[i].downTime));
487 }
488 mKeyDowns.clear();
489 mMetaState = AMETA_NONE;
490 return out;
491 }
492
onKeyDownProcessed(nsecs_t downTime)493 void KeyboardInputMapper::onKeyDownProcessed(nsecs_t downTime) {
494 InputReaderContext& context = *getContext();
495 context.setLastKeyDownTimestamp(downTime);
496 // Ignore meta keys or multiple simultaneous down keys as they are likely to be keyboard
497 // shortcuts
498 bool shouldHideCursor = mKeyDowns.size() == 1 && !isMetaKey(mKeyDowns[0].keyCode);
499 if (shouldHideCursor && context.getPolicy()->isInputMethodConnectionActive()) {
500 context.setPreventingTouchpadTaps(true);
501 }
502 }
503
504 } // namespace android
505