• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014, 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 package com.android.inputmethod.latin;
18 
19 import android.content.res.Resources;
20 import android.util.Log;
21 import android.view.KeyEvent;
22 
23 import com.android.inputmethod.keyboard.KeyboardSwitcher;
24 import com.android.inputmethod.latin.settings.Settings;
25 
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Map;
29 import java.util.Set;
30 
31 import javax.annotation.Nonnull;
32 
33 /**
34  * A class for detecting Emoji-Alt physical key.
35  */
36 final class EmojiAltPhysicalKeyDetector {
37     private static final String TAG = "EmojiAltPhysicalKeyDetector";
38 
39     private final Map<Integer, Integer> mEmojiSwitcherMap;
40     private final Map<Integer, Integer> mSymbolsShiftedSwitcherMap;
41     private final Map<Integer, Integer> mCombinedSwitcherMap;
42 
43     // Set of keys codes that have been used as modifiers.
44     private Set<Integer> mActiveModifiers;
45 
EmojiAltPhysicalKeyDetector(@onnull final Resources resources)46     public EmojiAltPhysicalKeyDetector(@Nonnull final Resources resources) {
47         mEmojiSwitcherMap = parseSwitchDefinition(resources, R.array.keyboard_switcher_emoji);
48         mSymbolsShiftedSwitcherMap = parseSwitchDefinition(
49                 resources, R.array.keyboard_switcher_symbols_shifted);
50         mCombinedSwitcherMap = new HashMap<>();
51         mCombinedSwitcherMap.putAll(mEmojiSwitcherMap);
52         mCombinedSwitcherMap.putAll(mSymbolsShiftedSwitcherMap);
53         mActiveModifiers = new HashSet<>();
54     }
55 
parseSwitchDefinition( @onnull final Resources resources, final int resourceId)56     private static Map<Integer, Integer> parseSwitchDefinition(
57             @Nonnull final Resources resources,
58             final int resourceId) {
59         final Map<Integer, Integer> definition = new HashMap<>();
60         final String name = resources.getResourceEntryName(resourceId);
61         final String[] values = resources.getStringArray(resourceId);
62         for (int i = 0; values != null && i < values.length; i++) {
63             String[] valuePair = values[i].split(",");
64             if (valuePair.length != 2) {
65                 Log.w(TAG, "Expected 2 integers in " + name + "[" + i + "] : " + values[i]);
66             }
67             try {
68                 definition.put(Integer.parseInt(valuePair[0]), Integer.parseInt(valuePair[1]));
69             } catch (NumberFormatException e) {
70                 Log.w(TAG, "Failed to parse " + name + "[" + i + "] : " + values[i], e);
71             }
72         }
73         return definition;
74     }
75 
76     /**
77      * Determine whether an up key event came from a mapped modifier key.
78      *
79      * @param keyEvent an up key event.
80      */
onKeyUp(@onnull final KeyEvent keyEvent)81     public void onKeyUp(@Nonnull final KeyEvent keyEvent) {
82         Log.d(TAG, "onKeyUp() : " + keyEvent);
83         if (!Settings.getInstance().getCurrent().mEnableEmojiAltPhysicalKey) {
84             // The feature is disabled.
85             Log.d(TAG, "onKeyUp() : Disabled");
86             return;
87         }
88         if (keyEvent.isCanceled()) {
89             // This key up event was a part of key combinations and should be ignored.
90             Log.d(TAG, "onKeyUp() : Canceled");
91             return;
92         }
93         final Integer mappedModifier = getMappedModifier(keyEvent);
94         if (mappedModifier != null) {
95             // If the key was modified by a mapped key, then ignore the next time
96             // the same modifier key comes up.
97             Log.d(TAG, "onKeyUp() : Using Modifier: " + mappedModifier);
98             mActiveModifiers.add(mappedModifier);
99             return;
100         }
101         final int keyCode = keyEvent.getKeyCode();
102         if (mActiveModifiers.contains(keyCode)) {
103             // Used as a modifier, not a standalone key press.
104             Log.d(TAG, "onKeyUp() : Used as Modifier: " + keyCode);
105             mActiveModifiers.remove(keyCode);
106             return;
107         }
108         if (!isMappedKeyCode(keyEvent)) {
109             // Nothing special about this key.
110             Log.d(TAG, "onKeyUp() : Not Mapped: " + keyCode);
111             return;
112         }
113         final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
114         if (mEmojiSwitcherMap.keySet().contains(keyCode)) {
115             switcher.onToggleKeyboard(KeyboardSwitcher.KeyboardSwitchState.EMOJI);
116         } else if (mSymbolsShiftedSwitcherMap.keySet().contains(keyCode)) {
117             switcher.onToggleKeyboard(KeyboardSwitcher.KeyboardSwitchState.SYMBOLS_SHIFTED);
118         } else {
119             Log.w(TAG, "Cannot toggle on keyCode: " + keyCode);
120         }
121     }
122 
123     /**
124      * @param keyEvent pressed key event
125      * @return true iff the user pressed a mapped modifier key.
126      */
isMappedKeyCode(@onnull final KeyEvent keyEvent)127     private boolean isMappedKeyCode(@Nonnull final KeyEvent keyEvent) {
128         return mCombinedSwitcherMap.get(keyEvent.getKeyCode()) != null;
129     }
130 
131     /**
132      * @param keyEvent pressed key event
133      * @return the mapped modifier used with this key opress, if any.
134      */
getMappedModifier(@onnull final KeyEvent keyEvent)135     private Integer getMappedModifier(@Nonnull final KeyEvent keyEvent) {
136         final int keyCode = keyEvent.getKeyCode();
137         final int metaState = keyEvent.getMetaState();
138         for (int mappedKeyCode : mCombinedSwitcherMap.keySet()) {
139             if (keyCode == mappedKeyCode) {
140                 Log.d(TAG, "getMappedModifier() : KeyCode = MappedKeyCode = " + mappedKeyCode);
141                 continue;
142             }
143             final Integer mappedMeta = mCombinedSwitcherMap.get(mappedKeyCode);
144             if (mappedMeta == null || mappedMeta.intValue() == -1) {
145                 continue;
146             }
147             if ((metaState & mappedMeta) != 0) {
148                 Log.d(TAG, "getMappedModifier() : MetaState(" + metaState
149                         + ") contains MappedMeta(" + mappedMeta + ")");
150                 return mappedKeyCode;
151             }
152         }
153         return null;
154     }
155 }
156