• 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 namespace android {
24 
25 // --- Static Definitions ---
26 
rotateValueUsingRotationMap(int32_t value,int32_t orientation,const int32_t map[][4],size_t mapSize)27 static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation,
28                                            const int32_t map[][4], size_t mapSize) {
29     if (orientation != DISPLAY_ORIENTATION_0) {
30         for (size_t i = 0; i < mapSize; i++) {
31             if (value == map[i][0]) {
32                 return map[i][orientation];
33             }
34         }
35     }
36     return value;
37 }
38 
39 static const int32_t keyCodeRotationMap[][4] = {
40         // key codes enumerated counter-clockwise with the original (unrotated) key first
41         // no rotation,        90 degree rotation,  180 degree rotation, 270 degree rotation
42         {AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT},
43         {AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN},
44         {AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT},
45         {AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP},
46         {AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT,
47          AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT},
48         {AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP,
49          AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN},
50         {AKEYCODE_SYSTEM_NAVIGATION_UP, AKEYCODE_SYSTEM_NAVIGATION_LEFT,
51          AKEYCODE_SYSTEM_NAVIGATION_DOWN, AKEYCODE_SYSTEM_NAVIGATION_RIGHT},
52         {AKEYCODE_SYSTEM_NAVIGATION_LEFT, AKEYCODE_SYSTEM_NAVIGATION_DOWN,
53          AKEYCODE_SYSTEM_NAVIGATION_RIGHT, AKEYCODE_SYSTEM_NAVIGATION_UP},
54 };
55 
56 static const size_t keyCodeRotationMapSize =
57         sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
58 
rotateStemKey(int32_t value,int32_t orientation,const int32_t map[][2],size_t mapSize)59 static int32_t rotateStemKey(int32_t value, int32_t orientation, const int32_t map[][2],
60                              size_t mapSize) {
61     if (orientation == DISPLAY_ORIENTATION_180) {
62         for (size_t i = 0; i < mapSize; i++) {
63             if (value == map[i][0]) {
64                 return map[i][1];
65             }
66         }
67     }
68     return value;
69 }
70 
71 // The mapping can be defined using input device configuration properties keyboard.rotated.stem_X
72 static int32_t stemKeyRotationMap[][2] = {
73         // key codes enumerated with the original (unrotated) key first
74         // no rotation,           180 degree rotation
75         {AKEYCODE_STEM_PRIMARY, AKEYCODE_STEM_PRIMARY},
76         {AKEYCODE_STEM_1, AKEYCODE_STEM_1},
77         {AKEYCODE_STEM_2, AKEYCODE_STEM_2},
78         {AKEYCODE_STEM_3, AKEYCODE_STEM_3},
79 };
80 
81 static const size_t stemKeyRotationMapSize =
82         sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]);
83 
rotateKeyCode(int32_t keyCode,int32_t orientation)84 static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) {
85     keyCode = rotateStemKey(keyCode, orientation, stemKeyRotationMap, stemKeyRotationMapSize);
86     return rotateValueUsingRotationMap(keyCode, orientation, keyCodeRotationMap,
87                                        keyCodeRotationMapSize);
88 }
89 
90 // --- KeyboardInputMapper ---
91 
KeyboardInputMapper(InputDeviceContext & deviceContext,uint32_t source,int32_t keyboardType)92 KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source,
93                                          int32_t keyboardType)
94       : InputMapper(deviceContext), mSource(source), mKeyboardType(keyboardType) {}
95 
~KeyboardInputMapper()96 KeyboardInputMapper::~KeyboardInputMapper() {}
97 
getSources()98 uint32_t KeyboardInputMapper::getSources() {
99     return mSource;
100 }
101 
getOrientation()102 int32_t KeyboardInputMapper::getOrientation() {
103     if (mViewport) {
104         return mViewport->orientation;
105     }
106     return DISPLAY_ORIENTATION_0;
107 }
108 
getDisplayId()109 int32_t KeyboardInputMapper::getDisplayId() {
110     if (mViewport) {
111         return mViewport->displayId;
112     }
113     return ADISPLAY_ID_NONE;
114 }
115 
populateDeviceInfo(InputDeviceInfo * info)116 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
117     InputMapper::populateDeviceInfo(info);
118 
119     info->setKeyboardType(mKeyboardType);
120     info->setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
121 }
122 
dump(std::string & dump)123 void KeyboardInputMapper::dump(std::string& dump) {
124     dump += INDENT2 "Keyboard Input Mapper:\n";
125     dumpParameters(dump);
126     dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
127     dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
128     dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
129     dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
130     dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
131 }
132 
findViewport(nsecs_t when,const InputReaderConfiguration * config)133 std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
134         nsecs_t when, const InputReaderConfiguration* config) {
135     if (getDeviceContext().getAssociatedViewport()) {
136         return getDeviceContext().getAssociatedViewport();
137     }
138 
139     // No associated display defined, try to find default display if orientationAware.
140     if (mParameters.orientationAware) {
141         return config->getDisplayViewportByType(ViewportType::INTERNAL);
142     }
143 
144     return std::nullopt;
145 }
146 
configure(nsecs_t when,const InputReaderConfiguration * config,uint32_t changes)147 void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
148                                     uint32_t changes) {
149     InputMapper::configure(when, config, changes);
150 
151     if (!changes) { // first time only
152         // Configure basic parameters.
153         configureParameters();
154     }
155 
156     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
157         mViewport = findViewport(when, config);
158     }
159 }
160 
mapStemKey(int32_t keyCode,const PropertyMap & config,char const * property)161 static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) {
162     int32_t mapped = 0;
163     if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
164         for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
165             if (stemKeyRotationMap[i][0] == keyCode) {
166                 stemKeyRotationMap[i][1] = mapped;
167                 return;
168             }
169         }
170     }
171 }
172 
configureParameters()173 void KeyboardInputMapper::configureParameters() {
174     mParameters.orientationAware = false;
175     const PropertyMap& config = getDeviceContext().getConfiguration();
176     config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware);
177 
178     if (mParameters.orientationAware) {
179         mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
180         mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
181         mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
182         mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3");
183     }
184 
185     mParameters.handlesKeyRepeat = false;
186     config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat);
187 
188     mParameters.doNotWakeByDefault = false;
189     config.tryGetProperty(String8("keyboard.doNotWakeByDefault"), mParameters.doNotWakeByDefault);
190 }
191 
dumpParameters(std::string & dump)192 void KeyboardInputMapper::dumpParameters(std::string& dump) {
193     dump += INDENT3 "Parameters:\n";
194     dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
195     dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat));
196 }
197 
reset(nsecs_t when)198 void KeyboardInputMapper::reset(nsecs_t when) {
199     mMetaState = AMETA_NONE;
200     mDownTime = 0;
201     mKeyDowns.clear();
202     mCurrentHidUsage = 0;
203 
204     resetLedState();
205 
206     InputMapper::reset(when);
207 }
208 
process(const RawEvent * rawEvent)209 void KeyboardInputMapper::process(const RawEvent* rawEvent) {
210     switch (rawEvent->type) {
211         case EV_KEY: {
212             int32_t scanCode = rawEvent->code;
213             int32_t usageCode = mCurrentHidUsage;
214             mCurrentHidUsage = 0;
215 
216             if (isKeyboardOrGamepadKey(scanCode)) {
217                 processKey(rawEvent->when, rawEvent->readTime, rawEvent->value != 0, scanCode,
218                            usageCode);
219             }
220             break;
221         }
222         case EV_MSC: {
223             if (rawEvent->code == MSC_SCAN) {
224                 mCurrentHidUsage = rawEvent->value;
225             }
226             break;
227         }
228         case EV_SYN: {
229             if (rawEvent->code == SYN_REPORT) {
230                 mCurrentHidUsage = 0;
231             }
232         }
233     }
234 }
235 
isKeyboardOrGamepadKey(int32_t scanCode)236 bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
237     return scanCode < BTN_MOUSE || scanCode >= BTN_WHEEL ||
238             (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) ||
239             (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
240 }
241 
isMediaKey(int32_t keyCode)242 bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
243     switch (keyCode) {
244         case AKEYCODE_MEDIA_PLAY:
245         case AKEYCODE_MEDIA_PAUSE:
246         case AKEYCODE_MEDIA_PLAY_PAUSE:
247         case AKEYCODE_MUTE:
248         case AKEYCODE_HEADSETHOOK:
249         case AKEYCODE_MEDIA_STOP:
250         case AKEYCODE_MEDIA_NEXT:
251         case AKEYCODE_MEDIA_PREVIOUS:
252         case AKEYCODE_MEDIA_REWIND:
253         case AKEYCODE_MEDIA_RECORD:
254         case AKEYCODE_MEDIA_FAST_FORWARD:
255         case AKEYCODE_MEDIA_SKIP_FORWARD:
256         case AKEYCODE_MEDIA_SKIP_BACKWARD:
257         case AKEYCODE_MEDIA_STEP_FORWARD:
258         case AKEYCODE_MEDIA_STEP_BACKWARD:
259         case AKEYCODE_MEDIA_AUDIO_TRACK:
260         case AKEYCODE_VOLUME_UP:
261         case AKEYCODE_VOLUME_DOWN:
262         case AKEYCODE_VOLUME_MUTE:
263         case AKEYCODE_TV_AUDIO_DESCRIPTION:
264         case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
265         case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
266             return true;
267     }
268     return false;
269 }
270 
processKey(nsecs_t when,nsecs_t readTime,bool down,int32_t scanCode,int32_t usageCode)271 void KeyboardInputMapper::processKey(nsecs_t when, nsecs_t readTime, bool down, int32_t scanCode,
272                                      int32_t usageCode) {
273     int32_t keyCode;
274     int32_t keyMetaState;
275     uint32_t policyFlags;
276 
277     if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
278                                   &policyFlags)) {
279         keyCode = AKEYCODE_UNKNOWN;
280         keyMetaState = mMetaState;
281         policyFlags = 0;
282     }
283 
284     if (down) {
285         // Rotate key codes according to orientation if needed.
286         if (mParameters.orientationAware) {
287             keyCode = rotateKeyCode(keyCode, getOrientation());
288         }
289 
290         // Add key down.
291         ssize_t keyDownIndex = findKeyDown(scanCode);
292         if (keyDownIndex >= 0) {
293             // key repeat, be sure to use same keycode as before in case of rotation
294             keyCode = mKeyDowns[keyDownIndex].keyCode;
295         } else {
296             // key down
297             if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
298                 getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
299                 return;
300             }
301             if (policyFlags & POLICY_FLAG_GESTURE) {
302                 getDeviceContext().cancelTouch(when, readTime);
303             }
304 
305             KeyDown keyDown;
306             keyDown.keyCode = keyCode;
307             keyDown.scanCode = scanCode;
308             mKeyDowns.push_back(keyDown);
309         }
310 
311         mDownTime = when;
312     } else {
313         // Remove key down.
314         ssize_t keyDownIndex = findKeyDown(scanCode);
315         if (keyDownIndex >= 0) {
316             // key up, be sure to use same keycode as before in case of rotation
317             keyCode = mKeyDowns[keyDownIndex].keyCode;
318             mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
319         } else {
320             // key was not actually down
321             ALOGI("Dropping key up from device %s because the key was not down.  "
322                   "keyCode=%d, scanCode=%d",
323                   getDeviceName().c_str(), keyCode, scanCode);
324             return;
325         }
326     }
327 
328     if (updateMetaStateIfNeeded(keyCode, down)) {
329         // If global meta state changed send it along with the key.
330         // If it has not changed then we'll use what keymap gave us,
331         // since key replacement logic might temporarily reset a few
332         // meta bits for given key.
333         keyMetaState = mMetaState;
334     }
335 
336     nsecs_t downTime = mDownTime;
337 
338     // Key down on external an keyboard should wake the device.
339     // We don't do this for internal keyboards to prevent them from waking up in your pocket.
340     // For internal keyboards and devices for which the default wake behavior is explicitly
341     // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
342     // wake key individually.
343     // TODO: Use the input device configuration to control this behavior more finely.
344     if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
345         !isMediaKey(keyCode)) {
346         policyFlags |= POLICY_FLAG_WAKE;
347     }
348 
349     if (mParameters.handlesKeyRepeat) {
350         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
351     }
352 
353     NotifyKeyArgs args(getContext()->getNextId(), when, readTime, getDeviceId(), mSource,
354                        getDisplayId(), policyFlags,
355                        down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
356                        AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
357     getListener()->notifyKey(&args);
358 }
359 
findKeyDown(int32_t scanCode)360 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
361     size_t n = mKeyDowns.size();
362     for (size_t i = 0; i < n; i++) {
363         if (mKeyDowns[i].scanCode == scanCode) {
364             return i;
365         }
366     }
367     return -1;
368 }
369 
getKeyCodeState(uint32_t sourceMask,int32_t keyCode)370 int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
371     return getDeviceContext().getKeyCodeState(keyCode);
372 }
373 
getScanCodeState(uint32_t sourceMask,int32_t scanCode)374 int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
375     return getDeviceContext().getScanCodeState(scanCode);
376 }
377 
markSupportedKeyCodes(uint32_t sourceMask,size_t numCodes,const int32_t * keyCodes,uint8_t * outFlags)378 bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
379                                                 const int32_t* keyCodes, uint8_t* outFlags) {
380     return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags);
381 }
382 
getMetaState()383 int32_t KeyboardInputMapper::getMetaState() {
384     return mMetaState;
385 }
386 
updateMetaState(int32_t keyCode)387 void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
388     updateMetaStateIfNeeded(keyCode, false);
389 }
390 
updateMetaStateIfNeeded(int32_t keyCode,bool down)391 bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
392     int32_t oldMetaState = mMetaState;
393     int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
394     int32_t metaStateChanged = oldMetaState ^ newMetaState;
395     if (metaStateChanged) {
396         mMetaState = newMetaState;
397         constexpr int32_t allLedMetaState =
398                 AMETA_CAPS_LOCK_ON | AMETA_NUM_LOCK_ON | AMETA_SCROLL_LOCK_ON;
399         if ((metaStateChanged & allLedMetaState) != 0) {
400             getContext()->updateLedMetaState(newMetaState & allLedMetaState);
401         }
402         getContext()->updateGlobalMetaState();
403     }
404 
405     return metaStateChanged;
406 }
407 
resetLedState()408 void KeyboardInputMapper::resetLedState() {
409     initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
410     initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
411     initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
412 
413     updateLedState(true);
414 }
415 
initializeLedState(LedState & ledState,int32_t led)416 void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
417     ledState.avail = getDeviceContext().hasLed(led);
418     ledState.on = false;
419 }
420 
updateLedState(bool reset)421 void KeyboardInputMapper::updateLedState(bool reset) {
422     mMetaState |= getContext()->getLedMetaState();
423 
424     constexpr int32_t META_NUM = 3;
425     const std::array<int32_t, META_NUM> keyCodes = {AKEYCODE_CAPS_LOCK, AKEYCODE_NUM_LOCK,
426                                                     AKEYCODE_SCROLL_LOCK};
427     const std::array<int32_t, META_NUM> metaCodes = {AMETA_CAPS_LOCK_ON, AMETA_NUM_LOCK_ON,
428                                                      AMETA_SCROLL_LOCK_ON};
429     std::array<uint8_t, META_NUM> flags = {0, 0, 0};
430     bool hasKeyLayout =
431             getDeviceContext().markSupportedKeyCodes(META_NUM, keyCodes.data(), flags.data());
432     // If the device doesn't have the physical meta key it shouldn't generate the corresponding
433     // meta state.
434     if (hasKeyLayout) {
435         for (int i = 0; i < META_NUM; i++) {
436             if (!flags[i]) {
437                 mMetaState &= ~metaCodes[i];
438             }
439         }
440     }
441 
442     updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset);
443     updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset);
444     updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset);
445 }
446 
updateLedStateForModifier(LedState & ledState,int32_t led,int32_t modifier,bool reset)447 void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led,
448                                                     int32_t modifier, bool reset) {
449     if (ledState.avail) {
450         bool desiredState = (mMetaState & modifier) != 0;
451         if (reset || ledState.on != desiredState) {
452             getDeviceContext().setLedState(led, desiredState);
453             ledState.on = desiredState;
454         }
455     }
456 }
457 
getAssociatedDisplayId()458 std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() {
459     if (mViewport) {
460         return std::make_optional(mViewport->displayId);
461     }
462     return std::nullopt;
463 }
464 
465 } // namespace android
466