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(InputDeviceContext & deviceContext,uint32_t source,int32_t keyboardType)90 KeyboardInputMapper::KeyboardInputMapper(InputDeviceContext& deviceContext, uint32_t source,
91 int32_t keyboardType)
92 : InputMapper(deviceContext), mSource(source), mKeyboardType(keyboardType) {}
93
~KeyboardInputMapper()94 KeyboardInputMapper::~KeyboardInputMapper() {}
95
getSources()96 uint32_t KeyboardInputMapper::getSources() {
97 return mSource;
98 }
99
getOrientation()100 int32_t KeyboardInputMapper::getOrientation() {
101 if (mViewport) {
102 return mViewport->orientation;
103 }
104 return DISPLAY_ORIENTATION_0;
105 }
106
getDisplayId()107 int32_t KeyboardInputMapper::getDisplayId() {
108 if (mViewport) {
109 return mViewport->displayId;
110 }
111 return ADISPLAY_ID_NONE;
112 }
113
populateDeviceInfo(InputDeviceInfo * info)114 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
115 InputMapper::populateDeviceInfo(info);
116
117 info->setKeyboardType(mKeyboardType);
118 info->setKeyCharacterMap(getDeviceContext().getKeyCharacterMap());
119 }
120
dump(std::string & dump)121 void KeyboardInputMapper::dump(std::string& dump) {
122 dump += INDENT2 "Keyboard Input Mapper:\n";
123 dumpParameters(dump);
124 dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
125 dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
126 dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
127 dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
128 dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
129 }
130
findViewport(nsecs_t when,const InputReaderConfiguration * config)131 std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
132 nsecs_t when, const InputReaderConfiguration* config) {
133 const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
134 if (displayPort) {
135 // Find the viewport that contains the same port
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::VIEWPORT_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->value != 0, scanCode, usageCode);
218 }
219 break;
220 }
221 case EV_MSC: {
222 if (rawEvent->code == MSC_SCAN) {
223 mCurrentHidUsage = rawEvent->value;
224 }
225 break;
226 }
227 case EV_SYN: {
228 if (rawEvent->code == SYN_REPORT) {
229 mCurrentHidUsage = 0;
230 }
231 }
232 }
233 }
234
isKeyboardOrGamepadKey(int32_t scanCode)235 bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
236 return scanCode < BTN_MOUSE || scanCode >= BTN_WHEEL ||
237 (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) ||
238 (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
239 }
240
isMediaKey(int32_t keyCode)241 bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
242 switch (keyCode) {
243 case AKEYCODE_MEDIA_PLAY:
244 case AKEYCODE_MEDIA_PAUSE:
245 case AKEYCODE_MEDIA_PLAY_PAUSE:
246 case AKEYCODE_MUTE:
247 case AKEYCODE_HEADSETHOOK:
248 case AKEYCODE_MEDIA_STOP:
249 case AKEYCODE_MEDIA_NEXT:
250 case AKEYCODE_MEDIA_PREVIOUS:
251 case AKEYCODE_MEDIA_REWIND:
252 case AKEYCODE_MEDIA_RECORD:
253 case AKEYCODE_MEDIA_FAST_FORWARD:
254 case AKEYCODE_MEDIA_SKIP_FORWARD:
255 case AKEYCODE_MEDIA_SKIP_BACKWARD:
256 case AKEYCODE_MEDIA_STEP_FORWARD:
257 case AKEYCODE_MEDIA_STEP_BACKWARD:
258 case AKEYCODE_MEDIA_AUDIO_TRACK:
259 case AKEYCODE_VOLUME_UP:
260 case AKEYCODE_VOLUME_DOWN:
261 case AKEYCODE_VOLUME_MUTE:
262 case AKEYCODE_TV_AUDIO_DESCRIPTION:
263 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
264 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
265 return true;
266 }
267 return false;
268 }
269
processKey(nsecs_t when,bool down,int32_t scanCode,int32_t usageCode)270 void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
271 int32_t keyCode;
272 int32_t keyMetaState;
273 uint32_t policyFlags;
274
275 if (getDeviceContext().mapKey(scanCode, usageCode, mMetaState, &keyCode, &keyMetaState,
276 &policyFlags)) {
277 keyCode = AKEYCODE_UNKNOWN;
278 keyMetaState = mMetaState;
279 policyFlags = 0;
280 }
281
282 if (down) {
283 // Rotate key codes according to orientation if needed.
284 if (mParameters.orientationAware) {
285 keyCode = rotateKeyCode(keyCode, getOrientation());
286 }
287
288 // Add key down.
289 ssize_t keyDownIndex = findKeyDown(scanCode);
290 if (keyDownIndex >= 0) {
291 // key repeat, be sure to use same keycode as before in case of rotation
292 keyCode = mKeyDowns[keyDownIndex].keyCode;
293 } else {
294 // key down
295 if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
296 getContext()->shouldDropVirtualKey(when, keyCode, scanCode)) {
297 return;
298 }
299 if (policyFlags & POLICY_FLAG_GESTURE) {
300 getDeviceContext().cancelTouch(when);
301 }
302
303 KeyDown keyDown;
304 keyDown.keyCode = keyCode;
305 keyDown.scanCode = scanCode;
306 mKeyDowns.push_back(keyDown);
307 }
308
309 mDownTime = when;
310 } else {
311 // Remove key down.
312 ssize_t keyDownIndex = findKeyDown(scanCode);
313 if (keyDownIndex >= 0) {
314 // key up, be sure to use same keycode as before in case of rotation
315 keyCode = mKeyDowns[keyDownIndex].keyCode;
316 mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
317 } else {
318 // key was not actually down
319 ALOGI("Dropping key up from device %s because the key was not down. "
320 "keyCode=%d, scanCode=%d",
321 getDeviceName().c_str(), keyCode, scanCode);
322 return;
323 }
324 }
325
326 if (updateMetaStateIfNeeded(keyCode, down)) {
327 // If global meta state changed send it along with the key.
328 // If it has not changed then we'll use what keymap gave us,
329 // since key replacement logic might temporarily reset a few
330 // meta bits for given key.
331 keyMetaState = mMetaState;
332 }
333
334 nsecs_t downTime = mDownTime;
335
336 // Key down on external an keyboard should wake the device.
337 // We don't do this for internal keyboards to prevent them from waking up in your pocket.
338 // For internal keyboards and devices for which the default wake behavior is explicitly
339 // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
340 // wake key individually.
341 // TODO: Use the input device configuration to control this behavior more finely.
342 if (down && getDeviceContext().isExternal() && !mParameters.doNotWakeByDefault &&
343 !isMediaKey(keyCode)) {
344 policyFlags |= POLICY_FLAG_WAKE;
345 }
346
347 if (mParameters.handlesKeyRepeat) {
348 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
349 }
350
351 NotifyKeyArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, getDisplayId(),
352 policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
353 AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
354 getListener()->notifyKey(&args);
355 }
356
findKeyDown(int32_t scanCode)357 ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
358 size_t n = mKeyDowns.size();
359 for (size_t i = 0; i < n; i++) {
360 if (mKeyDowns[i].scanCode == scanCode) {
361 return i;
362 }
363 }
364 return -1;
365 }
366
getKeyCodeState(uint32_t sourceMask,int32_t keyCode)367 int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
368 return getDeviceContext().getKeyCodeState(keyCode);
369 }
370
getScanCodeState(uint32_t sourceMask,int32_t scanCode)371 int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
372 return getDeviceContext().getScanCodeState(scanCode);
373 }
374
markSupportedKeyCodes(uint32_t sourceMask,size_t numCodes,const int32_t * keyCodes,uint8_t * outFlags)375 bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
376 const int32_t* keyCodes, uint8_t* outFlags) {
377 return getDeviceContext().markSupportedKeyCodes(numCodes, keyCodes, outFlags);
378 }
379
getMetaState()380 int32_t KeyboardInputMapper::getMetaState() {
381 return mMetaState;
382 }
383
updateMetaState(int32_t keyCode)384 void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
385 updateMetaStateIfNeeded(keyCode, false);
386 }
387
updateMetaStateIfNeeded(int32_t keyCode,bool down)388 bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
389 int32_t oldMetaState = mMetaState;
390 int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
391 bool metaStateChanged = oldMetaState != newMetaState;
392 if (metaStateChanged) {
393 mMetaState = newMetaState;
394 updateLedState(false);
395
396 getContext()->updateGlobalMetaState();
397 }
398
399 return metaStateChanged;
400 }
401
resetLedState()402 void KeyboardInputMapper::resetLedState() {
403 initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
404 initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
405 initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
406
407 updateLedState(true);
408 }
409
initializeLedState(LedState & ledState,int32_t led)410 void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
411 ledState.avail = getDeviceContext().hasLed(led);
412 ledState.on = false;
413 }
414
updateLedState(bool reset)415 void KeyboardInputMapper::updateLedState(bool reset) {
416 updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset);
417 updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset);
418 updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset);
419 }
420
updateLedStateForModifier(LedState & ledState,int32_t led,int32_t modifier,bool reset)421 void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led,
422 int32_t modifier, bool reset) {
423 if (ledState.avail) {
424 bool desiredState = (mMetaState & modifier) != 0;
425 if (reset || ledState.on != desiredState) {
426 getDeviceContext().setLedState(led, desiredState);
427 ledState.on = desiredState;
428 }
429 }
430 }
431
getAssociatedDisplayId()432 std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() {
433 if (mViewport) {
434 return std::make_optional(mViewport->displayId);
435 }
436 return std::nullopt;
437 }
438
439 } // namespace android
440