The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2006 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 android.text.method; |
| 18 | |
| 19 | import android.text.*; |
| 20 | import android.text.method.TextKeyListener.Capitalize; |
| 21 | import android.util.SparseArray; |
| 22 | import android.view.KeyCharacterMap; |
| 23 | import android.view.KeyEvent; |
| 24 | import android.view.View; |
| 25 | |
| 26 | /** |
| 27 | * This is the standard key listener for alphabetic input on qwerty |
| 28 | * keyboards. You should generally not need to instantiate this yourself; |
| 29 | * TextKeyListener will do it for you. |
Jean Chalard | 405bc51 | 2012-05-29 19:12:34 +0900 | [diff] [blame] | 30 | * <p></p> |
| 31 | * As for all implementations of {@link KeyListener}, this class is only concerned |
| 32 | * with hardware keyboards. Software input methods have no obligation to trigger |
| 33 | * the methods in this class. |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 34 | */ |
| 35 | public class QwertyKeyListener extends BaseKeyListener { |
| 36 | private static QwertyKeyListener[] sInstance = |
| 37 | new QwertyKeyListener[Capitalize.values().length * 2]; |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 38 | private static QwertyKeyListener sFullKeyboardInstance; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 39 | |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 40 | private Capitalize mAutoCap; |
| 41 | private boolean mAutoText; |
| 42 | private boolean mFullKeyboard; |
| 43 | |
| 44 | private QwertyKeyListener(Capitalize cap, boolean autoText, boolean fullKeyboard) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 45 | mAutoCap = cap; |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 46 | mAutoText = autoText; |
| 47 | mFullKeyboard = fullKeyboard; |
| 48 | } |
| 49 | |
| 50 | public QwertyKeyListener(Capitalize cap, boolean autoText) { |
| 51 | this(cap, autoText, false); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Returns a new or existing instance with the specified capitalization |
| 56 | * and correction properties. |
| 57 | */ |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 58 | public static QwertyKeyListener getInstance(boolean autoText, Capitalize cap) { |
| 59 | int off = cap.ordinal() * 2 + (autoText ? 1 : 0); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 60 | |
| 61 | if (sInstance[off] == null) { |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 62 | sInstance[off] = new QwertyKeyListener(cap, autoText); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | return sInstance[off]; |
| 66 | } |
| 67 | |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 68 | /** |
| 69 | * Gets an instance of the listener suitable for use with full keyboards. |
| 70 | * Disables auto-capitalization, auto-text and long-press initiated on-screen |
| 71 | * character pickers. |
| 72 | */ |
| 73 | public static QwertyKeyListener getInstanceForFullKeyboard() { |
| 74 | if (sFullKeyboardInstance == null) { |
| 75 | sFullKeyboardInstance = new QwertyKeyListener(Capitalize.NONE, false, true); |
| 76 | } |
| 77 | return sFullKeyboardInstance; |
| 78 | } |
| 79 | |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 80 | public int getInputType() { |
| 81 | return makeTextContentType(mAutoCap, mAutoText); |
| 82 | } |
| 83 | |
| 84 | public boolean onKeyDown(View view, Editable content, |
| 85 | int keyCode, KeyEvent event) { |
| 86 | int selStart, selEnd; |
| 87 | int pref = 0; |
| 88 | |
| 89 | if (view != null) { |
| 90 | pref = TextKeyListener.getInstance().getPrefs(view.getContext()); |
| 91 | } |
| 92 | |
| 93 | { |
| 94 | int a = Selection.getSelectionStart(content); |
| 95 | int b = Selection.getSelectionEnd(content); |
| 96 | |
| 97 | selStart = Math.min(a, b); |
| 98 | selEnd = Math.max(a, b); |
| 99 | |
| 100 | if (selStart < 0 || selEnd < 0) { |
| 101 | selStart = selEnd = 0; |
| 102 | Selection.setSelection(content, 0, 0); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | int activeStart = content.getSpanStart(TextKeyListener.ACTIVE); |
| 107 | int activeEnd = content.getSpanEnd(TextKeyListener.ACTIVE); |
| 108 | |
| 109 | // QWERTY keyboard normal case |
| 110 | |
Raph Levien | 14f10e5 | 2013-09-18 13:01:11 -0700 | [diff] [blame] | 111 | int i = event.getUnicodeChar(getMetaState(content, event)); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 112 | |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 113 | if (!mFullKeyboard) { |
| 114 | int count = event.getRepeatCount(); |
| 115 | if (count > 0 && selStart == selEnd && selStart > 0) { |
| 116 | char c = content.charAt(selStart - 1); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 117 | |
Dmitry Tsyganyuk | e004b86 | 2012-08-29 11:04:03 -0500 | [diff] [blame] | 118 | if ((c == i || c == Character.toUpperCase(i)) && view != null) { |
Jeff Brown | 47e6b1b | 2010-11-29 17:37:49 -0800 | [diff] [blame] | 119 | if (showCharacterPicker(view, content, c, false, count)) { |
| 120 | resetMetaState(content); |
| 121 | return true; |
| 122 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 123 | } |
| 124 | } |
| 125 | } |
| 126 | |
| 127 | if (i == KeyCharacterMap.PICKER_DIALOG_INPUT) { |
| 128 | if (view != null) { |
| 129 | showCharacterPicker(view, content, |
| 130 | KeyCharacterMap.PICKER_DIALOG_INPUT, true, 1); |
| 131 | } |
| 132 | resetMetaState(content); |
| 133 | return true; |
| 134 | } |
| 135 | |
| 136 | if (i == KeyCharacterMap.HEX_INPUT) { |
| 137 | int start; |
| 138 | |
| 139 | if (selStart == selEnd) { |
| 140 | start = selEnd; |
| 141 | |
| 142 | while (start > 0 && selEnd - start < 4 && |
| 143 | Character.digit(content.charAt(start - 1), 16) >= 0) { |
| 144 | start--; |
| 145 | } |
| 146 | } else { |
| 147 | start = selStart; |
| 148 | } |
| 149 | |
| 150 | int ch = -1; |
| 151 | try { |
| 152 | String hex = TextUtils.substring(content, start, selEnd); |
| 153 | ch = Integer.parseInt(hex, 16); |
| 154 | } catch (NumberFormatException nfe) { } |
| 155 | |
| 156 | if (ch >= 0) { |
| 157 | selStart = start; |
| 158 | Selection.setSelection(content, selStart, selEnd); |
| 159 | i = ch; |
| 160 | } else { |
| 161 | i = 0; |
| 162 | } |
| 163 | } |
| 164 | |
| 165 | if (i != 0) { |
| 166 | boolean dead = false; |
| 167 | |
| 168 | if ((i & KeyCharacterMap.COMBINING_ACCENT) != 0) { |
| 169 | dead = true; |
| 170 | i = i & KeyCharacterMap.COMBINING_ACCENT_MASK; |
| 171 | } |
| 172 | |
| 173 | if (activeStart == selStart && activeEnd == selEnd) { |
| 174 | boolean replace = false; |
| 175 | |
| 176 | if (selEnd - selStart - 1 == 0) { |
| 177 | char accent = content.charAt(selStart); |
| 178 | int composed = event.getDeadChar(accent, i); |
| 179 | |
| 180 | if (composed != 0) { |
| 181 | i = composed; |
| 182 | replace = true; |
Jean Chalard | 5486550 | 2013-02-25 19:56:32 -0800 | [diff] [blame] | 183 | dead = false; |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 184 | } |
| 185 | } |
| 186 | |
| 187 | if (!replace) { |
| 188 | Selection.setSelection(content, selEnd); |
| 189 | content.removeSpan(TextKeyListener.ACTIVE); |
| 190 | selStart = selEnd; |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | if ((pref & TextKeyListener.AUTO_CAP) != 0 && |
| 195 | Character.isLowerCase(i) && |
| 196 | TextKeyListener.shouldCap(mAutoCap, content, selStart)) { |
| 197 | int where = content.getSpanEnd(TextKeyListener.CAPPED); |
| 198 | int flags = content.getSpanFlags(TextKeyListener.CAPPED); |
| 199 | |
| 200 | if (where == selStart && (((flags >> 16) & 0xFFFF) == i)) { |
| 201 | content.removeSpan(TextKeyListener.CAPPED); |
| 202 | } else { |
| 203 | flags = i << 16; |
| 204 | i = Character.toUpperCase(i); |
| 205 | |
| 206 | if (selStart == 0) |
| 207 | content.setSpan(TextKeyListener.CAPPED, 0, 0, |
| 208 | Spannable.SPAN_MARK_MARK | flags); |
| 209 | else |
| 210 | content.setSpan(TextKeyListener.CAPPED, |
| 211 | selStart - 1, selStart, |
| 212 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | |
| 213 | flags); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | if (selStart != selEnd) { |
| 218 | Selection.setSelection(content, selEnd); |
| 219 | } |
| 220 | content.setSpan(OLD_SEL_START, selStart, selStart, |
| 221 | Spannable.SPAN_MARK_MARK); |
| 222 | |
| 223 | content.replace(selStart, selEnd, String.valueOf((char) i)); |
| 224 | |
| 225 | int oldStart = content.getSpanStart(OLD_SEL_START); |
| 226 | selEnd = Selection.getSelectionEnd(content); |
| 227 | |
| 228 | if (oldStart < selEnd) { |
| 229 | content.setSpan(TextKeyListener.LAST_TYPED, |
| 230 | oldStart, selEnd, |
| 231 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 232 | |
| 233 | if (dead) { |
| 234 | Selection.setSelection(content, oldStart, selEnd); |
| 235 | content.setSpan(TextKeyListener.ACTIVE, oldStart, selEnd, |
| 236 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 237 | } |
| 238 | } |
| 239 | |
| 240 | adjustMetaAfterKeypress(content); |
| 241 | |
| 242 | // potentially do autotext replacement if the character |
| 243 | // that was typed was an autotext terminator |
| 244 | |
| 245 | if ((pref & TextKeyListener.AUTO_TEXT) != 0 && mAutoText && |
| 246 | (i == ' ' || i == '\t' || i == '\n' || |
| 247 | i == ',' || i == '.' || i == '!' || i == '?' || |
| 248 | i == '"' || Character.getType(i) == Character.END_PUNCTUATION) && |
| 249 | content.getSpanEnd(TextKeyListener.INHIBIT_REPLACEMENT) |
| 250 | != oldStart) { |
| 251 | int x; |
| 252 | |
| 253 | for (x = oldStart; x > 0; x--) { |
| 254 | char c = content.charAt(x - 1); |
| 255 | if (c != '\'' && !Character.isLetter(c)) { |
| 256 | break; |
| 257 | } |
| 258 | } |
| 259 | |
| 260 | String rep = getReplacement(content, x, oldStart, view); |
| 261 | |
| 262 | if (rep != null) { |
| 263 | Replaced[] repl = content.getSpans(0, content.length(), |
| 264 | Replaced.class); |
| 265 | for (int a = 0; a < repl.length; a++) |
| 266 | content.removeSpan(repl[a]); |
| 267 | |
| 268 | char[] orig = new char[oldStart - x]; |
| 269 | TextUtils.getChars(content, x, oldStart, orig, 0); |
| 270 | |
| 271 | content.setSpan(new Replaced(orig), x, oldStart, |
| 272 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 273 | content.replace(x, oldStart, rep); |
| 274 | } |
| 275 | } |
| 276 | |
| 277 | // Replace two spaces by a period and a space. |
| 278 | |
| 279 | if ((pref & TextKeyListener.AUTO_PERIOD) != 0 && mAutoText) { |
| 280 | selEnd = Selection.getSelectionEnd(content); |
| 281 | if (selEnd - 3 >= 0) { |
| 282 | if (content.charAt(selEnd - 1) == ' ' && |
| 283 | content.charAt(selEnd - 2) == ' ') { |
| 284 | char c = content.charAt(selEnd - 3); |
| 285 | |
| 286 | for (int j = selEnd - 3; j > 0; j--) { |
| 287 | if (c == '"' || |
| 288 | Character.getType(c) == Character.END_PUNCTUATION) { |
| 289 | c = content.charAt(j - 1); |
| 290 | } else { |
| 291 | break; |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | if (Character.isLetter(c) || Character.isDigit(c)) { |
| 296 | content.replace(selEnd - 2, selEnd - 1, "."); |
| 297 | } |
| 298 | } |
| 299 | } |
| 300 | } |
| 301 | |
| 302 | return true; |
Jeff Brown | 14d0ca1 | 2010-12-21 16:06:44 -0800 | [diff] [blame] | 303 | } else if (keyCode == KeyEvent.KEYCODE_DEL |
| 304 | && (event.hasNoModifiers() || event.hasModifiers(KeyEvent.META_ALT_ON)) |
| 305 | && selStart == selEnd) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 306 | // special backspace case for undoing autotext |
| 307 | |
| 308 | int consider = 1; |
| 309 | |
| 310 | // if backspacing over the last typed character, |
| 311 | // it undoes the autotext prior to that character |
| 312 | // (unless the character typed was newline, in which |
| 313 | // case this behavior would be confusing) |
| 314 | |
| 315 | if (content.getSpanEnd(TextKeyListener.LAST_TYPED) == selStart) { |
| 316 | if (content.charAt(selStart - 1) != '\n') |
| 317 | consider = 2; |
| 318 | } |
| 319 | |
| 320 | Replaced[] repl = content.getSpans(selStart - consider, selStart, |
| 321 | Replaced.class); |
| 322 | |
| 323 | if (repl.length > 0) { |
| 324 | int st = content.getSpanStart(repl[0]); |
| 325 | int en = content.getSpanEnd(repl[0]); |
| 326 | String old = new String(repl[0].mText); |
| 327 | |
| 328 | content.removeSpan(repl[0]); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 329 | |
The Android Open Source Project | 4df2423 | 2009-03-05 14:34:35 -0800 | [diff] [blame] | 330 | // only cancel the autocomplete if the cursor is at the end of |
The Android Open Source Project | c39a6e0 | 2009-03-11 12:11:56 -0700 | [diff] [blame] | 331 | // the replaced span (or after it, because the user is |
| 332 | // backspacing over the space after the word, not the word |
| 333 | // itself). |
| 334 | if (selStart >= en) { |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 335 | content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, |
The Android Open Source Project | 4df2423 | 2009-03-05 14:34:35 -0800 | [diff] [blame] | 336 | en, en, Spannable.SPAN_POINT_POINT); |
| 337 | content.replace(st, en, old); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 338 | |
The Android Open Source Project | 4df2423 | 2009-03-05 14:34:35 -0800 | [diff] [blame] | 339 | en = content.getSpanStart(TextKeyListener.INHIBIT_REPLACEMENT); |
| 340 | if (en - 1 >= 0) { |
| 341 | content.setSpan(TextKeyListener.INHIBIT_REPLACEMENT, |
| 342 | en - 1, en, |
| 343 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 344 | } else { |
| 345 | content.removeSpan(TextKeyListener.INHIBIT_REPLACEMENT); |
| 346 | } |
| 347 | adjustMetaAfterKeypress(content); |
| 348 | } else { |
| 349 | adjustMetaAfterKeypress(content); |
| 350 | return super.onKeyDown(view, content, keyCode, event); |
| 351 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 352 | |
| 353 | return true; |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | return super.onKeyDown(view, content, keyCode, event); |
| 358 | } |
| 359 | |
| 360 | private String getReplacement(CharSequence src, int start, int end, |
| 361 | View view) { |
| 362 | int len = end - start; |
| 363 | boolean changecase = false; |
| 364 | |
| 365 | String replacement = AutoText.get(src, start, end, view); |
| 366 | |
| 367 | if (replacement == null) { |
| 368 | String key = TextUtils.substring(src, start, end).toLowerCase(); |
| 369 | replacement = AutoText.get(key, 0, end - start, view); |
| 370 | changecase = true; |
| 371 | |
| 372 | if (replacement == null) |
| 373 | return null; |
| 374 | } |
| 375 | |
| 376 | int caps = 0; |
| 377 | |
| 378 | if (changecase) { |
| 379 | for (int j = start; j < end; j++) { |
| 380 | if (Character.isUpperCase(src.charAt(j))) |
| 381 | caps++; |
| 382 | } |
| 383 | } |
| 384 | |
| 385 | String out; |
| 386 | |
| 387 | if (caps == 0) |
| 388 | out = replacement; |
| 389 | else if (caps == 1) |
| 390 | out = toTitleCase(replacement); |
| 391 | else if (caps == len) |
| 392 | out = replacement.toUpperCase(); |
| 393 | else |
| 394 | out = toTitleCase(replacement); |
| 395 | |
| 396 | if (out.length() == len && |
| 397 | TextUtils.regionMatches(src, start, out, 0, len)) |
| 398 | return null; |
| 399 | |
| 400 | return out; |
| 401 | } |
| 402 | |
| 403 | /** |
| 404 | * Marks the specified region of <code>content</code> as having |
| 405 | * contained <code>original</code> prior to AutoText replacement. |
| 406 | * Call this method when you have done or are about to do an |
| 407 | * AutoText-style replacement on a region of text and want to let |
| 408 | * the same mechanism (the user pressing DEL immediately after the |
| 409 | * change) undo the replacement. |
| 410 | * |
| 411 | * @param content the Editable text where the replacement was made |
| 412 | * @param start the start of the replaced region |
| 413 | * @param end the end of the replaced region; the location of the cursor |
| 414 | * @param original the text to be restored if the user presses DEL |
| 415 | */ |
| 416 | public static void markAsReplaced(Spannable content, int start, int end, |
| 417 | String original) { |
| 418 | Replaced[] repl = content.getSpans(0, content.length(), Replaced.class); |
| 419 | for (int a = 0; a < repl.length; a++) { |
| 420 | content.removeSpan(repl[a]); |
| 421 | } |
| 422 | |
| 423 | int len = original.length(); |
| 424 | char[] orig = new char[len]; |
| 425 | original.getChars(0, len, orig, 0); |
| 426 | |
| 427 | content.setSpan(new Replaced(orig), start, end, |
| 428 | Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
| 429 | } |
| 430 | |
| 431 | private static SparseArray<String> PICKER_SETS = |
| 432 | new SparseArray<String>(); |
| 433 | static { |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 434 | PICKER_SETS.put('A', "\u00C0\u00C1\u00C2\u00C4\u00C6\u00C3\u00C5\u0104\u0100"); |
| 435 | PICKER_SETS.put('C', "\u00C7\u0106\u010C"); |
| 436 | PICKER_SETS.put('D', "\u010E"); |
| 437 | PICKER_SETS.put('E', "\u00C8\u00C9\u00CA\u00CB\u0118\u011A\u0112"); |
Eric Fischer | ec1f8a2 | 2009-09-30 18:03:47 -0700 | [diff] [blame] | 438 | PICKER_SETS.put('G', "\u011E"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 439 | PICKER_SETS.put('L', "\u0141"); |
Eric Fischer | 4ef2995 | 2009-09-15 16:02:47 -0700 | [diff] [blame] | 440 | PICKER_SETS.put('I', "\u00CC\u00CD\u00CE\u00CF\u012A\u0130"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 441 | PICKER_SETS.put('N', "\u00D1\u0143\u0147"); |
| 442 | PICKER_SETS.put('O', "\u00D8\u0152\u00D5\u00D2\u00D3\u00D4\u00D6\u014C"); |
| 443 | PICKER_SETS.put('R', "\u0158"); |
Eric Fischer | ec1f8a2 | 2009-09-30 18:03:47 -0700 | [diff] [blame] | 444 | PICKER_SETS.put('S', "\u015A\u0160\u015E"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 445 | PICKER_SETS.put('T', "\u0164"); |
| 446 | PICKER_SETS.put('U', "\u00D9\u00DA\u00DB\u00DC\u016E\u016A"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 447 | PICKER_SETS.put('Y', "\u00DD\u0178"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 448 | PICKER_SETS.put('Z', "\u0179\u017B\u017D"); |
| 449 | PICKER_SETS.put('a', "\u00E0\u00E1\u00E2\u00E4\u00E6\u00E3\u00E5\u0105\u0101"); |
| 450 | PICKER_SETS.put('c', "\u00E7\u0107\u010D"); |
| 451 | PICKER_SETS.put('d', "\u010F"); |
| 452 | PICKER_SETS.put('e', "\u00E8\u00E9\u00EA\u00EB\u0119\u011B\u0113"); |
Eric Fischer | ec1f8a2 | 2009-09-30 18:03:47 -0700 | [diff] [blame] | 453 | PICKER_SETS.put('g', "\u011F"); |
Eric Fischer | 4ef2995 | 2009-09-15 16:02:47 -0700 | [diff] [blame] | 454 | PICKER_SETS.put('i', "\u00EC\u00ED\u00EE\u00EF\u012B\u0131"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 455 | PICKER_SETS.put('l', "\u0142"); |
| 456 | PICKER_SETS.put('n', "\u00F1\u0144\u0148"); |
| 457 | PICKER_SETS.put('o', "\u00F8\u0153\u00F5\u00F2\u00F3\u00F4\u00F6\u014D"); |
| 458 | PICKER_SETS.put('r', "\u0159"); |
Eric Fischer | ec1f8a2 | 2009-09-30 18:03:47 -0700 | [diff] [blame] | 459 | PICKER_SETS.put('s', "\u00A7\u00DF\u015B\u0161\u015F"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 460 | PICKER_SETS.put('t', "\u0165"); |
| 461 | PICKER_SETS.put('u', "\u00F9\u00FA\u00FB\u00FC\u016F\u016B"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 462 | PICKER_SETS.put('y', "\u00FD\u00FF"); |
Eric Fischer | a3ea3ae | 2009-03-31 14:17:10 -0700 | [diff] [blame] | 463 | PICKER_SETS.put('z', "\u017A\u017C\u017E"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 464 | PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT, |
Eric Fischer | d7c432b | 2009-11-17 16:28:30 -0800 | [diff] [blame] | 465 | "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\|"); |
Eric Fischer | cebe347 | 2009-09-16 16:26:48 -0700 | [diff] [blame] | 466 | PICKER_SETS.put('/', "\\"); |
Eric Fischer | 4ef2995 | 2009-09-15 16:02:47 -0700 | [diff] [blame] | 467 | |
| 468 | // From packages/inputmethods/LatinIME/res/xml/kbd_symbols.xml |
| 469 | |
| 470 | PICKER_SETS.put('1', "\u00b9\u00bd\u2153\u00bc\u215b"); |
| 471 | PICKER_SETS.put('2', "\u00b2\u2154"); |
| 472 | PICKER_SETS.put('3', "\u00b3\u00be\u215c"); |
| 473 | PICKER_SETS.put('4', "\u2074"); |
| 474 | PICKER_SETS.put('5', "\u215d"); |
| 475 | PICKER_SETS.put('7', "\u215e"); |
| 476 | PICKER_SETS.put('0', "\u207f\u2205"); |
| 477 | PICKER_SETS.put('$', "\u00a2\u00a3\u20ac\u00a5\u20a3\u20a4\u20b1"); |
| 478 | PICKER_SETS.put('%', "\u2030"); |
| 479 | PICKER_SETS.put('*', "\u2020\u2021"); |
| 480 | PICKER_SETS.put('-', "\u2013\u2014"); |
| 481 | PICKER_SETS.put('+', "\u00b1"); |
| 482 | PICKER_SETS.put('(', "[{<"); |
| 483 | PICKER_SETS.put(')', "]}>"); |
| 484 | PICKER_SETS.put('!', "\u00a1"); |
| 485 | PICKER_SETS.put('"', "\u201c\u201d\u00ab\u00bb\u02dd"); |
| 486 | PICKER_SETS.put('?', "\u00bf"); |
| 487 | PICKER_SETS.put(',', "\u201a\u201e"); |
| 488 | |
| 489 | // From packages/inputmethods/LatinIME/res/xml/kbd_symbols_shift.xml |
| 490 | |
| 491 | PICKER_SETS.put('=', "\u2260\u2248\u221e"); |
| 492 | PICKER_SETS.put('<', "\u2264\u00ab\u2039"); |
| 493 | PICKER_SETS.put('>', "\u2265\u00bb\u203a"); |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 494 | }; |
| 495 | |
| 496 | private boolean showCharacterPicker(View view, Editable content, char c, |
| 497 | boolean insert, int count) { |
| 498 | String set = PICKER_SETS.get(c); |
| 499 | if (set == null) { |
| 500 | return false; |
| 501 | } |
| 502 | |
| 503 | if (count == 1) { |
| 504 | new CharacterPickerDialog(view.getContext(), |
| 505 | view, content, set, insert).show(); |
| 506 | } |
| 507 | |
| 508 | return true; |
| 509 | } |
| 510 | |
| 511 | private static String toTitleCase(String src) { |
| 512 | return Character.toUpperCase(src.charAt(0)) + src.substring(1); |
| 513 | } |
| 514 | |
| 515 | /* package */ static class Replaced implements NoCopySpan |
| 516 | { |
| 517 | public Replaced(char[] text) { |
| 518 | mText = text; |
| 519 | } |
| 520 | |
| 521 | private char[] mText; |
| 522 | } |
The Android Open Source Project | 9066cfe | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 523 | } |
| 524 | |