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