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