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