blob: 0b5c7ff7855ca46844a124409c6ec9eeb755290a [file] [log] [blame]
Jeff Brown5912f952013-07-01 19:10:31 -07001/*
2 * Copyright (C) 2010 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#define LOG_TAG "Keyboard"
18
Harry Cuttsf13161a2023-03-08 14:15:49 +000019#include <limits.h>
Jeff Brown5912f952013-07-01 19:10:31 -070020#include <stdlib.h>
21#include <unistd.h>
Harry Cuttsf13161a2023-03-08 14:15:49 +000022#include <optional>
Jeff Brown5912f952013-07-01 19:10:31 -070023
Jeff Brown5912f952013-07-01 19:10:31 -070024#include <input/InputDevice.h>
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -070025#include <input/InputEventLabels.h>
26#include <input/KeyCharacterMap.h>
27#include <input/KeyLayoutMap.h>
28#include <input/Keyboard.h>
29#include <log/log.h>
Jeff Brown5912f952013-07-01 19:10:31 -070030#include <utils/Errors.h>
Jeff Brown5912f952013-07-01 19:10:31 -070031
32namespace android {
33
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -070034static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
35 InputDeviceConfigurationFileType type) {
36 return name.empty()
37 ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
38 : getInputDeviceConfigurationFilePathByName(name, type);
39}
40
Jeff Brown5912f952013-07-01 19:10:31 -070041// --- KeyMap ---
42
43KeyMap::KeyMap() {
44}
45
46KeyMap::~KeyMap() {
47}
48
Yuichiro Hanadaf92661b2019-06-06 18:50:18 +090049status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
Jeff Brown5912f952013-07-01 19:10:31 -070050 const PropertyMap* deviceConfiguration) {
51 // Use the configured key layout if available.
52 if (deviceConfiguration) {
Harry Cuttsf13161a2023-03-08 14:15:49 +000053 std::optional<std::string> keyLayoutName =
54 deviceConfiguration->getString("keyboard.layout");
55 if (keyLayoutName.has_value()) {
56 status_t status = loadKeyLayout(deviceIdentifier, *keyLayoutName);
Jeff Brown5912f952013-07-01 19:10:31 -070057 if (status == NAME_NOT_FOUND) {
58 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -070059 "it was not found.",
Harry Cuttsf13161a2023-03-08 14:15:49 +000060 deviceIdentifier.name.c_str(), keyLayoutName->c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070061 }
62 }
63
Harry Cuttsf13161a2023-03-08 14:15:49 +000064 std::optional<std::string> keyCharacterMapName =
65 deviceConfiguration->getString("keyboard.characterMap");
66 if (keyCharacterMapName.has_value()) {
67 status_t status = loadKeyCharacterMap(deviceIdentifier, *keyCharacterMapName);
Jeff Brown5912f952013-07-01 19:10:31 -070068 if (status == NAME_NOT_FOUND) {
69 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
Siarhei Vishniakou4f94c1a2022-07-13 07:29:51 -070070 "map '%s' but it was not found.",
Harry Cuttsf13161a2023-03-08 14:15:49 +000071 deviceIdentifier.name.c_str(), keyCharacterMapName->c_str());
Jeff Brown5912f952013-07-01 19:10:31 -070072 }
73 }
74
75 if (isComplete()) {
76 return OK;
77 }
78 }
79
80 // Try searching by device identifier.
Yuichiro Hanadaf92661b2019-06-06 18:50:18 +090081 if (probeKeyMap(deviceIdentifier, "")) {
Jeff Brown5912f952013-07-01 19:10:31 -070082 return OK;
83 }
84
85 // Fall back on the Generic key map.
86 // TODO Apply some additional heuristics here to figure out what kind of
87 // generic key map to use (US English, etc.) for typical external keyboards.
Yuichiro Hanadaf92661b2019-06-06 18:50:18 +090088 if (probeKeyMap(deviceIdentifier, "Generic")) {
Jeff Brown5912f952013-07-01 19:10:31 -070089 return OK;
90 }
91
92 // Try the Virtual key map as a last resort.
Yuichiro Hanadaf92661b2019-06-06 18:50:18 +090093 if (probeKeyMap(deviceIdentifier, "Virtual")) {
Jeff Brown5912f952013-07-01 19:10:31 -070094 return OK;
95 }
96
97 // Give up!
98 ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
Yuichiro Hanadaf92661b2019-06-06 18:50:18 +090099 deviceIdentifier.name.c_str());
Jeff Brown5912f952013-07-01 19:10:31 -0700100 return NAME_NOT_FOUND;
101}
102
103bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100104 const std::string& keyMapName) {
Jeff Brown5912f952013-07-01 19:10:31 -0700105 if (!haveKeyLayout()) {
106 loadKeyLayout(deviceIdentifier, keyMapName);
107 }
108 if (!haveKeyCharacterMap()) {
109 loadKeyCharacterMap(deviceIdentifier, keyMapName);
110 }
111 return isComplete();
112}
113
114status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100115 const std::string& name) {
Chris Ye1d927aa2020-07-04 18:22:41 -0700116 std::string path(getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_LAYOUT));
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100117 if (path.empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700118 return NAME_NOT_FOUND;
119 }
120
Chris Ye1abffbd2020-08-18 12:50:12 -0700121 base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700122 if (ret.ok()) {
123 keyLayoutMap = *ret;
124 keyLayoutFile = path;
125 return OK;
126 }
127
128 // Try to load fallback layout if the regular layout could not be loaded due to missing
129 // kernel modules
130 std::string fallbackPath(
131 getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
132 InputDeviceConfigurationFileType::
133 KEY_LAYOUT,
134 "_fallback"));
135 ret = KeyLayoutMap::load(fallbackPath);
Bernie Innocenti55396a82020-12-19 18:47:35 +0900136 if (!ret.ok()) {
Chris Ye1abffbd2020-08-18 12:50:12 -0700137 return ret.error().code();
Jeff Brown5912f952013-07-01 19:10:31 -0700138 }
Chris Ye1abffbd2020-08-18 12:50:12 -0700139 keyLayoutMap = *ret;
Siarhei Vishniakoua9fd82c2022-05-18 09:42:52 -0700140 keyLayoutFile = fallbackPath;
Jeff Brown5912f952013-07-01 19:10:31 -0700141 return OK;
142}
143
144status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100145 const std::string& name) {
Chris Ye1d927aa2020-07-04 18:22:41 -0700146 std::string path =
147 getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_CHARACTER_MAP);
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100148 if (path.empty()) {
Jeff Brown5912f952013-07-01 19:10:31 -0700149 return NAME_NOT_FOUND;
150 }
151
Chris Ye3a1e4462020-08-12 10:13:15 -0700152 base::Result<std::shared_ptr<KeyCharacterMap>> ret =
Michael Wright102936e2020-11-04 03:44:27 +0000153 KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
Bernie Innocenti55396a82020-12-19 18:47:35 +0900154 if (!ret.ok()) {
Chris Ye3a1e4462020-08-12 10:13:15 -0700155 return ret.error().code();
Jeff Brown5912f952013-07-01 19:10:31 -0700156 }
Chris Ye3a1e4462020-08-12 10:13:15 -0700157 keyCharacterMap = *ret;
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100158 keyCharacterMapFile = path;
Jeff Brown5912f952013-07-01 19:10:31 -0700159 return OK;
160}
161
Jeff Brown5912f952013-07-01 19:10:31 -0700162// --- Global functions ---
163
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600164bool isKeyboardSpecialFunction(const PropertyMap* config) {
165 if (config == nullptr) {
166 return false;
167 }
Harry Cuttsf13161a2023-03-08 14:15:49 +0000168 return config->getBool("keyboard.specialFunction").value_or(false);
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600169}
170
Jeff Brown5912f952013-07-01 19:10:31 -0700171bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
172 const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
Siarhei Vishniakou61da25a2018-02-15 21:04:49 -0600173 // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q
Michael Wright102936e2020-11-04 03:44:27 +0000174 if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration) ||
175 keyMap->keyCharacterMap->getKeyboardType() ==
176 KeyCharacterMap::KeyboardType::SPECIAL_FUNCTION) {
Jeff Brown5912f952013-07-01 19:10:31 -0700177 return false;
178 }
179
180 if (deviceConfiguration) {
Harry Cuttsf13161a2023-03-08 14:15:49 +0000181 if (deviceConfiguration->getBool("keyboard.builtIn").value_or(false)) {
Jeff Brown5912f952013-07-01 19:10:31 -0700182 return true;
183 }
184 }
185
Siarhei Vishniakouec8f7252018-07-06 11:19:32 +0100186 return strstr(deviceIdentifier.name.c_str(), "-keypad");
Jeff Brown5912f952013-07-01 19:10:31 -0700187}
188
Jeff Brown5912f952013-07-01 19:10:31 -0700189static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
190 int32_t newMetaState;
191 if (down) {
192 newMetaState = oldMetaState | mask;
193 } else {
194 newMetaState = oldMetaState &
195 ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
196 }
197
Dmitry Torokhov115f93e2015-09-17 18:04:50 -0700198 return normalizeMetaState(newMetaState);
199}
200
201int32_t normalizeMetaState(int32_t oldMetaState) {
202 int32_t newMetaState = oldMetaState;
Jeff Brown5912f952013-07-01 19:10:31 -0700203 if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
204 newMetaState |= AMETA_ALT_ON;
205 }
206
207 if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
208 newMetaState |= AMETA_SHIFT_ON;
209 }
210
211 if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
212 newMetaState |= AMETA_CTRL_ON;
213 }
214
215 if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
216 newMetaState |= AMETA_META_ON;
217 }
218 return newMetaState;
219}
220
221static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
222 if (down) {
223 return oldMetaState;
224 } else {
225 return oldMetaState ^ mask;
226 }
227}
228
229int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
Jeff Brown5912f952013-07-01 19:10:31 -0700230 switch (keyCode) {
231 case AKEYCODE_ALT_LEFT:
232 return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
233 case AKEYCODE_ALT_RIGHT:
234 return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
235 case AKEYCODE_SHIFT_LEFT:
236 return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
237 case AKEYCODE_SHIFT_RIGHT:
238 return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
239 case AKEYCODE_SYM:
240 return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
241 case AKEYCODE_FUNCTION:
242 return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
243 case AKEYCODE_CTRL_LEFT:
244 return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
245 case AKEYCODE_CTRL_RIGHT:
246 return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
247 case AKEYCODE_META_LEFT:
248 return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
249 case AKEYCODE_META_RIGHT:
250 return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
251 case AKEYCODE_CAPS_LOCK:
252 return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
253 case AKEYCODE_NUM_LOCK:
254 return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
255 case AKEYCODE_SCROLL_LOCK:
256 return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
257 default:
258 return oldMetaState;
259 }
260}
261
262bool isMetaKey(int32_t keyCode) {
263 switch (keyCode) {
264 case AKEYCODE_ALT_LEFT:
265 case AKEYCODE_ALT_RIGHT:
266 case AKEYCODE_SHIFT_LEFT:
267 case AKEYCODE_SHIFT_RIGHT:
268 case AKEYCODE_SYM:
269 case AKEYCODE_FUNCTION:
270 case AKEYCODE_CTRL_LEFT:
271 case AKEYCODE_CTRL_RIGHT:
272 case AKEYCODE_META_LEFT:
273 case AKEYCODE_META_RIGHT:
274 case AKEYCODE_CAPS_LOCK:
275 case AKEYCODE_NUM_LOCK:
276 case AKEYCODE_SCROLL_LOCK:
277 return true;
278 default:
279 return false;
280 }
281}
282
283
284} // namespace android