blob: 348a7ada0e37ff4d15991b8054794324d5d3e63c [file] [log] [blame]
Prabir Pradhanbaa5c822019-08-30 15:27:05 -07001/*
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
21namespace android {
22
23// --- Static Definitions ---
24
25static 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
37static 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
54static const size_t keyCodeRotationMapSize =
55 sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]);
56
57static 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
70static 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
79static const size_t stemKeyRotationMapSize =
80 sizeof(stemKeyRotationMap) / sizeof(stemKeyRotationMap[0]);
81
82static 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
90KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType)
91 : InputMapper(device), mSource(source), mKeyboardType(keyboardType) {}
92
93KeyboardInputMapper::~KeyboardInputMapper() {}
94
95uint32_t KeyboardInputMapper::getSources() {
96 return mSource;
97}
98
99int32_t KeyboardInputMapper::getOrientation() {
100 if (mViewport) {
101 return mViewport->orientation;
102 }
103 return DISPLAY_ORIENTATION_0;
104}
105
106int32_t KeyboardInputMapper::getDisplayId() {
107 if (mViewport) {
108 return mViewport->displayId;
109 }
110 return ADISPLAY_ID_NONE;
111}
112
113void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
114 InputMapper::populateDeviceInfo(info);
115
116 info->setKeyboardType(mKeyboardType);
117 info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
118}
119
120void 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
130std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
131 nsecs_t when, const InputReaderConfiguration* config) {
132 const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
133 if (displayPort) {
134 // Find the viewport that contains the same port
135 return mDevice->getAssociatedViewport();
136 }
137
138 // No associated display defined, try to find default display if orientationAware.
139 if (mParameters.orientationAware) {
140 return config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
141 }
142
143 return std::nullopt;
144}
145
146void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
147 uint32_t changes) {
148 InputMapper::configure(when, config, changes);
149
150 if (!changes) { // first time only
151 // Configure basic parameters.
152 configureParameters();
153 }
154
155 if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
156 mViewport = findViewport(when, config);
157 }
158}
159
160static void mapStemKey(int32_t keyCode, const PropertyMap& config, char const* property) {
161 int32_t mapped = 0;
162 if (config.tryGetProperty(String8(property), mapped) && mapped > 0) {
163 for (size_t i = 0; i < stemKeyRotationMapSize; i++) {
164 if (stemKeyRotationMap[i][0] == keyCode) {
165 stemKeyRotationMap[i][1] = mapped;
166 return;
167 }
168 }
169 }
170}
171
172void KeyboardInputMapper::configureParameters() {
173 mParameters.orientationAware = false;
174 const PropertyMap& config = getDevice()->getConfiguration();
175 config.tryGetProperty(String8("keyboard.orientationAware"), mParameters.orientationAware);
176
177 if (mParameters.orientationAware) {
178 mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
179 mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
180 mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
181 mapStemKey(AKEYCODE_STEM_3, config, "keyboard.rotated.stem_3");
182 }
183
184 mParameters.handlesKeyRepeat = false;
185 config.tryGetProperty(String8("keyboard.handlesKeyRepeat"), mParameters.handlesKeyRepeat);
Powei Fengd041c5d2019-05-03 17:11:33 -0700186
187 mParameters.doNotWakeByDefault = false;
188 config.tryGetProperty(String8("keyboard.doNotWakeByDefault"), mParameters.doNotWakeByDefault);
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700189}
190
191void KeyboardInputMapper::dumpParameters(std::string& dump) {
192 dump += INDENT3 "Parameters:\n";
193 dump += StringPrintf(INDENT4 "OrientationAware: %s\n", toString(mParameters.orientationAware));
194 dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n", toString(mParameters.handlesKeyRepeat));
195}
196
197void KeyboardInputMapper::reset(nsecs_t when) {
198 mMetaState = AMETA_NONE;
199 mDownTime = 0;
200 mKeyDowns.clear();
201 mCurrentHidUsage = 0;
202
203 resetLedState();
204
205 InputMapper::reset(when);
206}
207
208void KeyboardInputMapper::process(const RawEvent* rawEvent) {
209 switch (rawEvent->type) {
210 case EV_KEY: {
211 int32_t scanCode = rawEvent->code;
212 int32_t usageCode = mCurrentHidUsage;
213 mCurrentHidUsage = 0;
214
215 if (isKeyboardOrGamepadKey(scanCode)) {
216 processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
217 }
218 break;
219 }
220 case EV_MSC: {
221 if (rawEvent->code == MSC_SCAN) {
222 mCurrentHidUsage = rawEvent->value;
223 }
224 break;
225 }
226 case EV_SYN: {
227 if (rawEvent->code == SYN_REPORT) {
228 mCurrentHidUsage = 0;
229 }
230 }
231 }
232}
233
234bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) {
235 return scanCode < BTN_MOUSE || scanCode >= KEY_OK ||
236 (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) ||
237 (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
238}
239
240bool KeyboardInputMapper::isMediaKey(int32_t keyCode) {
241 switch (keyCode) {
242 case AKEYCODE_MEDIA_PLAY:
243 case AKEYCODE_MEDIA_PAUSE:
244 case AKEYCODE_MEDIA_PLAY_PAUSE:
245 case AKEYCODE_MUTE:
246 case AKEYCODE_HEADSETHOOK:
247 case AKEYCODE_MEDIA_STOP:
248 case AKEYCODE_MEDIA_NEXT:
249 case AKEYCODE_MEDIA_PREVIOUS:
250 case AKEYCODE_MEDIA_REWIND:
251 case AKEYCODE_MEDIA_RECORD:
252 case AKEYCODE_MEDIA_FAST_FORWARD:
253 case AKEYCODE_MEDIA_SKIP_FORWARD:
254 case AKEYCODE_MEDIA_SKIP_BACKWARD:
255 case AKEYCODE_MEDIA_STEP_FORWARD:
256 case AKEYCODE_MEDIA_STEP_BACKWARD:
257 case AKEYCODE_MEDIA_AUDIO_TRACK:
258 case AKEYCODE_VOLUME_UP:
259 case AKEYCODE_VOLUME_DOWN:
260 case AKEYCODE_VOLUME_MUTE:
261 case AKEYCODE_TV_AUDIO_DESCRIPTION:
262 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP:
263 case AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN:
264 return true;
265 }
266 return false;
267}
268
269void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode) {
270 int32_t keyCode;
271 int32_t keyMetaState;
272 uint32_t policyFlags;
273
274 if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState, &keyCode,
275 &keyMetaState, &policyFlags)) {
276 keyCode = AKEYCODE_UNKNOWN;
277 keyMetaState = mMetaState;
278 policyFlags = 0;
279 }
280
281 if (down) {
282 // Rotate key codes according to orientation if needed.
283 if (mParameters.orientationAware) {
284 keyCode = rotateKeyCode(keyCode, getOrientation());
285 }
286
287 // Add key down.
288 ssize_t keyDownIndex = findKeyDown(scanCode);
289 if (keyDownIndex >= 0) {
290 // key repeat, be sure to use same keycode as before in case of rotation
291 keyCode = mKeyDowns[keyDownIndex].keyCode;
292 } else {
293 // key down
294 if ((policyFlags & POLICY_FLAG_VIRTUAL) &&
295 mContext->shouldDropVirtualKey(when, getDevice(), keyCode, scanCode)) {
296 return;
297 }
298 if (policyFlags & POLICY_FLAG_GESTURE) {
299 mDevice->cancelTouch(when);
300 }
301
302 KeyDown keyDown;
303 keyDown.keyCode = keyCode;
304 keyDown.scanCode = scanCode;
305 mKeyDowns.push_back(keyDown);
306 }
307
308 mDownTime = when;
309 } else {
310 // Remove key down.
311 ssize_t keyDownIndex = findKeyDown(scanCode);
312 if (keyDownIndex >= 0) {
313 // key up, be sure to use same keycode as before in case of rotation
314 keyCode = mKeyDowns[keyDownIndex].keyCode;
315 mKeyDowns.erase(mKeyDowns.begin() + (size_t)keyDownIndex);
316 } else {
317 // key was not actually down
318 ALOGI("Dropping key up from device %s because the key was not down. "
319 "keyCode=%d, scanCode=%d",
320 getDeviceName().c_str(), keyCode, scanCode);
321 return;
322 }
323 }
324
325 if (updateMetaStateIfNeeded(keyCode, down)) {
326 // If global meta state changed send it along with the key.
327 // If it has not changed then we'll use what keymap gave us,
328 // since key replacement logic might temporarily reset a few
329 // meta bits for given key.
330 keyMetaState = mMetaState;
331 }
332
333 nsecs_t downTime = mDownTime;
334
335 // Key down on external an keyboard should wake the device.
336 // We don't do this for internal keyboards to prevent them from waking up in your pocket.
Powei Fengd041c5d2019-05-03 17:11:33 -0700337 // For internal keyboards and devices for which the default wake behavior is explicitly
338 // prevented (e.g. TV remotes), the key layout file should specify the policy flags for each
339 // wake key individually.
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700340 // TODO: Use the input device configuration to control this behavior more finely.
Powei Fengd041c5d2019-05-03 17:11:33 -0700341 if (down && getDevice()->isExternal() && !mParameters.doNotWakeByDefault &&
342 !isMediaKey(keyCode)) {
Prabir Pradhanbaa5c822019-08-30 15:27:05 -0700343 policyFlags |= POLICY_FLAG_WAKE;
344 }
345
346 if (mParameters.handlesKeyRepeat) {
347 policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
348 }
349
350 NotifyKeyArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource, getDisplayId(),
351 policyFlags, down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
352 AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
353 getListener()->notifyKey(&args);
354}
355
356ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
357 size_t n = mKeyDowns.size();
358 for (size_t i = 0; i < n; i++) {
359 if (mKeyDowns[i].scanCode == scanCode) {
360 return i;
361 }
362 }
363 return -1;
364}
365
366int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
367 return getEventHub()->getKeyCodeState(getDeviceId(), keyCode);
368}
369
370int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
371 return getEventHub()->getScanCodeState(getDeviceId(), scanCode);
372}
373
374bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
375 const int32_t* keyCodes, uint8_t* outFlags) {
376 return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags);
377}
378
379int32_t KeyboardInputMapper::getMetaState() {
380 return mMetaState;
381}
382
383void KeyboardInputMapper::updateMetaState(int32_t keyCode) {
384 updateMetaStateIfNeeded(keyCode, false);
385}
386
387bool KeyboardInputMapper::updateMetaStateIfNeeded(int32_t keyCode, bool down) {
388 int32_t oldMetaState = mMetaState;
389 int32_t newMetaState = android::updateMetaState(keyCode, down, oldMetaState);
390 bool metaStateChanged = oldMetaState != newMetaState;
391 if (metaStateChanged) {
392 mMetaState = newMetaState;
393 updateLedState(false);
394
395 getContext()->updateGlobalMetaState();
396 }
397
398 return metaStateChanged;
399}
400
401void KeyboardInputMapper::resetLedState() {
402 initializeLedState(mCapsLockLedState, ALED_CAPS_LOCK);
403 initializeLedState(mNumLockLedState, ALED_NUM_LOCK);
404 initializeLedState(mScrollLockLedState, ALED_SCROLL_LOCK);
405
406 updateLedState(true);
407}
408
409void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) {
410 ledState.avail = getEventHub()->hasLed(getDeviceId(), led);
411 ledState.on = false;
412}
413
414void KeyboardInputMapper::updateLedState(bool reset) {
415 updateLedStateForModifier(mCapsLockLedState, ALED_CAPS_LOCK, AMETA_CAPS_LOCK_ON, reset);
416 updateLedStateForModifier(mNumLockLedState, ALED_NUM_LOCK, AMETA_NUM_LOCK_ON, reset);
417 updateLedStateForModifier(mScrollLockLedState, ALED_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, reset);
418}
419
420void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, int32_t led,
421 int32_t modifier, bool reset) {
422 if (ledState.avail) {
423 bool desiredState = (mMetaState & modifier) != 0;
424 if (reset || ledState.on != desiredState) {
425 getEventHub()->setLedState(getDeviceId(), led, desiredState);
426 ledState.on = desiredState;
427 }
428 }
429}
430
431std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() {
432 if (mViewport) {
433 return std::make_optional(mViewport->displayId);
434 }
435 return std::nullopt;
436}
437
438} // namespace android