• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <limits.h>
22 
23 #include <input/InputDevice.h>
24 #include <input/InputEventLabels.h>
25 #include <input/KeyCharacterMap.h>
26 #include <input/KeyLayoutMap.h>
27 #include <input/Keyboard.h>
28 #include <log/log.h>
29 #include <utils/Errors.h>
30 
31 namespace android {
32 
getPath(const InputDeviceIdentifier & deviceIdentifier,const std::string & name,InputDeviceConfigurationFileType type)33 static std::string getPath(const InputDeviceIdentifier& deviceIdentifier, const std::string& name,
34                            InputDeviceConfigurationFileType type) {
35     return name.empty()
36             ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
37             : getInputDeviceConfigurationFilePathByName(name, type);
38 }
39 
40 // --- KeyMap ---
41 
KeyMap()42 KeyMap::KeyMap() {
43 }
44 
~KeyMap()45 KeyMap::~KeyMap() {
46 }
47 
load(const InputDeviceIdentifier & deviceIdentifier,const PropertyMap * deviceConfiguration)48 status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
49         const PropertyMap* deviceConfiguration) {
50     // Use the configured key layout if available.
51     if (deviceConfiguration) {
52         String8 keyLayoutName;
53         if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
54                 keyLayoutName)) {
55             status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
56             if (status == NAME_NOT_FOUND) {
57                 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
58                         "it was not found.",
59                         deviceIdentifier.name.c_str(), keyLayoutName.string());
60             }
61         }
62 
63         String8 keyCharacterMapName;
64         if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
65                 keyCharacterMapName)) {
66             status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
67             if (status == NAME_NOT_FOUND) {
68                 ALOGE("Configuration for keyboard device '%s' requested keyboard character "
69                         "map '%s' but it was not found.",
70                         deviceIdentifier.name.c_str(), keyCharacterMapName.string());
71             }
72         }
73 
74         if (isComplete()) {
75             return OK;
76         }
77     }
78 
79     // Try searching by device identifier.
80     if (probeKeyMap(deviceIdentifier, "")) {
81         return OK;
82     }
83 
84     // Fall back on the Generic key map.
85     // TODO Apply some additional heuristics here to figure out what kind of
86     //      generic key map to use (US English, etc.) for typical external keyboards.
87     if (probeKeyMap(deviceIdentifier, "Generic")) {
88         return OK;
89     }
90 
91     // Try the Virtual key map as a last resort.
92     if (probeKeyMap(deviceIdentifier, "Virtual")) {
93         return OK;
94     }
95 
96     // Give up!
97     ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
98             deviceIdentifier.name.c_str());
99     return NAME_NOT_FOUND;
100 }
101 
probeKeyMap(const InputDeviceIdentifier & deviceIdentifier,const std::string & keyMapName)102 bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier,
103         const std::string& keyMapName) {
104     if (!haveKeyLayout()) {
105         loadKeyLayout(deviceIdentifier, keyMapName);
106     }
107     if (!haveKeyCharacterMap()) {
108         loadKeyCharacterMap(deviceIdentifier, keyMapName);
109     }
110     return isComplete();
111 }
112 
loadKeyLayout(const InputDeviceIdentifier & deviceIdentifier,const std::string & name)113 status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
114         const std::string& name) {
115     std::string path(getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_LAYOUT));
116     if (path.empty()) {
117         return NAME_NOT_FOUND;
118     }
119 
120     base::Result<std::shared_ptr<KeyLayoutMap>> ret = KeyLayoutMap::load(path);
121     if (ret.ok()) {
122         keyLayoutMap = *ret;
123         keyLayoutFile = path;
124         return OK;
125     }
126 
127     // Try to load fallback layout if the regular layout could not be loaded due to missing
128     // kernel modules
129     std::string fallbackPath(
130             getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier,
131                                                                   InputDeviceConfigurationFileType::
132                                                                           KEY_LAYOUT,
133                                                                   "_fallback"));
134     ret = KeyLayoutMap::load(fallbackPath);
135     if (!ret.ok()) {
136         return ret.error().code();
137     }
138     keyLayoutMap = *ret;
139     keyLayoutFile = fallbackPath;
140     return OK;
141 }
142 
loadKeyCharacterMap(const InputDeviceIdentifier & deviceIdentifier,const std::string & name)143 status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier,
144         const std::string& name) {
145     std::string path =
146             getPath(deviceIdentifier, name, InputDeviceConfigurationFileType::KEY_CHARACTER_MAP);
147     if (path.empty()) {
148         return NAME_NOT_FOUND;
149     }
150 
151     base::Result<std::shared_ptr<KeyCharacterMap>> ret =
152             KeyCharacterMap::load(path, KeyCharacterMap::Format::BASE);
153     if (!ret.ok()) {
154         return ret.error().code();
155     }
156     keyCharacterMap = *ret;
157     keyCharacterMapFile = path;
158     return OK;
159 }
160 
161 // --- Global functions ---
162 
isKeyboardSpecialFunction(const PropertyMap * config)163 bool isKeyboardSpecialFunction(const PropertyMap* config) {
164     if (config == nullptr) {
165         return false;
166     }
167     bool isSpecialFunction = false;
168     config->tryGetProperty(String8("keyboard.specialFunction"), isSpecialFunction);
169     return isSpecialFunction;
170 }
171 
isEligibleBuiltInKeyboard(const InputDeviceIdentifier & deviceIdentifier,const PropertyMap * deviceConfiguration,const KeyMap * keyMap)172 bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier,
173         const PropertyMap* deviceConfiguration, const KeyMap* keyMap) {
174     // TODO: remove the third OR statement (SPECIAL_FUNCTION) in Q
175     if (!keyMap->haveKeyCharacterMap() || isKeyboardSpecialFunction(deviceConfiguration) ||
176         keyMap->keyCharacterMap->getKeyboardType() ==
177                 KeyCharacterMap::KeyboardType::SPECIAL_FUNCTION) {
178         return false;
179     }
180 
181     if (deviceConfiguration) {
182         bool builtIn = false;
183         if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn)
184                 && builtIn) {
185             return true;
186         }
187     }
188 
189     return strstr(deviceIdentifier.name.c_str(), "-keypad");
190 }
191 
setEphemeralMetaState(int32_t mask,bool down,int32_t oldMetaState)192 static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) {
193     int32_t newMetaState;
194     if (down) {
195         newMetaState = oldMetaState | mask;
196     } else {
197         newMetaState = oldMetaState &
198                 ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
199     }
200 
201     return normalizeMetaState(newMetaState);
202 }
203 
normalizeMetaState(int32_t oldMetaState)204 int32_t normalizeMetaState(int32_t oldMetaState) {
205     int32_t newMetaState = oldMetaState;
206     if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
207         newMetaState |= AMETA_ALT_ON;
208     }
209 
210     if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
211         newMetaState |= AMETA_SHIFT_ON;
212     }
213 
214     if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
215         newMetaState |= AMETA_CTRL_ON;
216     }
217 
218     if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) {
219         newMetaState |= AMETA_META_ON;
220     }
221     return newMetaState;
222 }
223 
toggleLockedMetaState(int32_t mask,bool down,int32_t oldMetaState)224 static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) {
225     if (down) {
226         return oldMetaState;
227     } else {
228         return oldMetaState ^ mask;
229     }
230 }
231 
updateMetaState(int32_t keyCode,bool down,int32_t oldMetaState)232 int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) {
233     switch (keyCode) {
234     case AKEYCODE_ALT_LEFT:
235         return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState);
236     case AKEYCODE_ALT_RIGHT:
237         return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState);
238     case AKEYCODE_SHIFT_LEFT:
239         return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState);
240     case AKEYCODE_SHIFT_RIGHT:
241         return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState);
242     case AKEYCODE_SYM:
243         return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState);
244     case AKEYCODE_FUNCTION:
245         return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState);
246     case AKEYCODE_CTRL_LEFT:
247         return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState);
248     case AKEYCODE_CTRL_RIGHT:
249         return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState);
250     case AKEYCODE_META_LEFT:
251         return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState);
252     case AKEYCODE_META_RIGHT:
253         return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState);
254     case AKEYCODE_CAPS_LOCK:
255         return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState);
256     case AKEYCODE_NUM_LOCK:
257         return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState);
258     case AKEYCODE_SCROLL_LOCK:
259         return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState);
260     default:
261         return oldMetaState;
262     }
263 }
264 
isMetaKey(int32_t keyCode)265 bool isMetaKey(int32_t keyCode) {
266     switch (keyCode) {
267     case AKEYCODE_ALT_LEFT:
268     case AKEYCODE_ALT_RIGHT:
269     case AKEYCODE_SHIFT_LEFT:
270     case AKEYCODE_SHIFT_RIGHT:
271     case AKEYCODE_SYM:
272     case AKEYCODE_FUNCTION:
273     case AKEYCODE_CTRL_LEFT:
274     case AKEYCODE_CTRL_RIGHT:
275     case AKEYCODE_META_LEFT:
276     case AKEYCODE_META_RIGHT:
277     case AKEYCODE_CAPS_LOCK:
278     case AKEYCODE_NUM_LOCK:
279     case AKEYCODE_SCROLL_LOCK:
280         return true;
281     default:
282         return false;
283     }
284 }
285 
286 
287 } // namespace android
288